Skip to content

Releases: smikhalevski/doubter

v5.1.0

25 Oct 14:14
Compare
Choose a tag to compare

Changelog: v5.0.0...v5.1.0

  • A prototype is preserved when an object is cloned:
class Foo {
  hello = 42
}

const input = new Foo();
const output = d.object({}).strip().parse(input);

input === output
// ⮕ false

output instanceof Foo
// ❌ Before ⮕ false
// ✅ After  ⮕ true
  • Simple plugin imports:
import * as d from 'doubter/core';
import 'doubter/plugin/array-essentials';

d.array().nonEmpty();
  • readonly() support for ArrayShape, ObjectShape, RecordShape, MapShape, and SetShape:
d.array(d.string()).readonly();
// ⮕ Shape<string[], readonly string[]>
  • Enhanced formatting of issue messages and validation error messages.

  • Multiple performance optimizations.

v5.0.0

10 Jun 18:04
Compare
Choose a tag to compare

Changelog: v4.0.3...v5.0.0

  • Migrated to ES6.

  • Added essentials plugin for RecordShape:

import * as d from 'doubter/core';
import enableRecordEssentials from 'doubter/plugin/record-essentials';

enableRecordEssentials(RecordShape);

d.record(d.number()).allKeys('foo', 'bar');
  • Issue messages can now be passed to parse methods of a shape:
d.string().parse(42, {
  message: { 'type.string': 'Yo, not a string!' }
});
  • Properties of options objects are now writable.

Breaking changes

  • The single issue code type was replaced with multiple codes: type.string, type.number, etc.

  • Shape.messages was removed.

  • %s placeholder isn't supported on messages anymore, use a MessageCallback instead.

  • Global error message formatter ValidationError.formatIssues and ParseOptions.errorMessage were removed.

  • ApplyOptions interface was merged into ParseOptions.

v4.0.3

06 Feb 10:27
Compare
Choose a tag to compare

Changelog: v4.0.2...v4.0.3

Simplified types of plugin callbacks to support older TypeScript compiler.

v4.0.2

14 Dec 20:31
Compare
Choose a tag to compare

Changelog: v4.0.1...v4.0.2

Source maps were disabled in the published package.

v4.0.1

04 Dec 18:43
Compare
Choose a tag to compare

Changelog: v4.0.0...v4.0.1

Types are exported using export type to enable isolatedModules support.

v4.0.0

26 Nov 11:26
Compare
Choose a tag to compare

Changelog: v3.0.3...v4.0.0

const shape1 = d.string().addOperation(value => {
  return { ok: true, value: value.trim() };
});
// ⮕ StringShape

shape1.parse('  Space  ');
// ⮕ 'Space'
const shape = d
  .string()
  .addAsyncOperation(async value => {
    if (await doAsyncCheck(value)) {
      return null;
    }
    return [{ code: 'kaputs' }];
  });

shape.isAsync;
// ⮕ true

shape.parseAsync('Hello');
  • ArrayShape.includes now support an async shape as an argument:
const shape1 = d.string().checkAsync(async () => );

const shape2 = d.array().includes(shape1);

shape2.isAsync;
// ⮕ true
  • Added Shape.checkAsync, Shape.refineAsync, and Shape.alterAsync;

  • Forced operations were replaced with the more flexible "tolerance for issues" concept. Tolerance setting changes the operation behavior depending on the validation issues are raised by the shape and preceding operations:

    • If skip then if preceding operations have raised issues, then this operation is skipped but consequent operations are still applied.
    • If abort then if preceding operations have raised issues, then this operation is skipped and consequent operations aren't applied. Also, if this operation itself raises issues then consequent operations aren't applied.
    • If auto then the operation is applied regardless of previously raised issues.
d.string().min(10).alter(
  value => value.substring(5),
  // 🟡 Skips alter operation if string length is insufficient
  { tolerance: 'skip' }
);
d.Shape.messages['type.string'] = 'Yo, not a string!';

d.string().parse(42);
// ❌ ValidationError: type at /: Yo, not a string!
const shape = d.const(42n).coerce();

shape.parse([new String('42')]);
// ⮕ 42n
  • Shape._getInputs() now returns a readonly array of types and literals, since these arrays are reused for most cases to avoid excessive allocations.

  • CoercibleShape.coerce() method doesn't accept a callback anymore. Use Shape.catch() or d.convert() to implement a custom coercion.

  • ApplyOptions.coerce flag was removed. Coercion can now be enabled on shape level only.

  • Doubter is now shipped with TypeScript sources, definitions, sourcemaps, ES6 modules, and plain-old JS. Bundling was removed to enhance tree-shaking.

Other changes

  • Shape.use was replaced with Shape.addOperation.

  • Fixed unexpected unwrapping of primitive wrappers in Array.coerce.

  • Removed async to sync auto downgrade optimization, so if parseAsync is called on a sync shape it would use the async path instead of wrapping a sync path in a promise.

  • _applyOperations now returns a promise if there are async operations.

    • If the shape overrides only _apply and doesn't override _applyAsync then it's only safe to call this method as the last statement in _apply. Otherwise, it may return an unexpected promise.

    • If the shape overrides both _apply and _applyAsync then this method would always synchronously return a Result inside _apply.

v3.0.3

19 Sep 19:48
Compare
Choose a tag to compare

Changelog: v3.0.2...v3.0.3

Paths of imported and exported modules now have an explicit extension specified.

v3.0.2

19 Sep 19:47
Compare
Choose a tag to compare

Changelog: v3.0.1...v3.0.2

Enabled side effects for index.js and index.mjs in package.json.

v3.0.1

17 Aug 11:24
Compare
Choose a tag to compare

Changelog: v3.0.0...v3.0.1

Fixed LazyShape.providedShape caching.

v3.0.0

31 Jul 22:49
Compare
Choose a tag to compare

Changelog: v2.1.0...v3.0.0

const shape = d.promise();

shape.coerce().parse('aaa');
// ⮕ Promise<'aaa'>

shape.isAsync;
// ⮕ false
type Foo {
  child?: Foo;
}

const parent: Foo = {};

// 👇 Cyclic objects are handled without stack overflow exceptions
parent.child = parent;

const lazyShape: d.Shape<Foo> = d.lazy(
  () => d.object({
    child: lazyShape
  })
);

lazyShape.parse(parent);
// ⮕ parent
  • Built-in type coercion can now be overridden with a custom callback. The callback passed to corce method is called only if the input value doesn't conform the requested type. If coercion isn't possible, d.NEVER must be returned.
const yesNoShape = d.boolean().coerce(value => {
  if (value === 'yes') {
    return true;
  }
  if (value === 'no') {
    return false;
  }
  // Coercion is not possible
  return d.NEVER;
});

d.array(yesNoShape).parse(['yes', 'no'])
// ⮕ [true, false]

yesNoShape.parse('true')
// ❌ ValidationError: type at /: Must be a boolean
  • Shape._clone was introduced to enable shape-specific cloning.

  • Shape.check signature was simplified to avoid the ambiguity between param and options arguments. Now param is the part of CheckOptions interface:

check<Param>(cb: CheckCallback<OutputValue, Param>, options: CheckOptions & { param: Param }): this;

check(cb: CheckCallback<OutputValue>, options?: CheckOptions): this;
  • Readonly arrays of keys are now supported as an argument for in pick, omit, partial, and required:
const keys = ['aaa'] as const;

d
  .object({
    aaa: d.string(),
    bbb: d.number()
  })
  //    👇 No typing errors here anymore
  .pick(keys)
// ⮕ Shape<{ aaa: string }>
  • FuntionShape.noWrap() was replaced with FuntionShape.strict(options). FuntionShape doesn't wrap input functions and strinct must be explicitly called to enable wrapping.

  • ApplyOptions.verbose was replaced with ApplyOptions.earlyReturn. Shapes now collect all issues by default, and earlyReturn: true should be used to exit after the first issue is encountered.

  • ObjectShape now has valueShapes property that holds an array of property shapes that is parallel to keys array.

  • ObjectShape.keyof() was replaced with ObjectShape.keysShape getter that returns the cached enum shape of known object keys.

Other changes

Removed members
Removed Replacement
d.finite() d.number().finite()
d.int() d.number().int()
d.integer() d.number().int()
BrandShape Shape<Branded<Value>>

getSheck, hasCheck, and deleteCheck were removed and don't have a replacement since checks were replaced with generic operations.

Renamed members
Old name New name
Shape.transform Shape.convert
Shape.transformAsync Shape.convertAsync
CoercibleShape.isCoerced CoercibleShape.isCoercing
ApplyOptions.coerced ApplyOptions.coerce
FunctionShape.isWrapperAsync FunctionShape.isAsyncFunction
FunctionShape.wrap FunctionShape.ensure
FunctionShape.wrapAsync FunctionShape.ensureAsync
ObjectShape.shapes ObjectShape.propShapes
ObjectShape.shapes ObjectShape.propShapes
ObjectShape.shapes ObjectShape.propShapes
ObjectShape.shapes ObjectShape.propShapes
KeysMode ObjectKeysMode
SetShape.shape SetShape.valueShape
NotShape.shape NotShape.baseShape
TransformShape.callback ConvertShape.converter
ReplaceShape.shape ReplaceShape.baseShape
DenyShape.shape DenyShape.baseShape
CatchShape.sahpe CatchShape.baseShape
ExcludeShape.shape ExcludeShape.baseShape
AllowLiteralShape AllowShape
DenyLiteralShape DenyShape
ReplaceLiteralShape ReplaceShape
Literal Any
ConstraintOptions IssueOptions