4a2040f92c
This PR adds a validation mode whereby previous known-to-be-valid values can be used to speed up the validation process itself. At the same time it enables us to do fine-grained equality checking on records much more quickly than by using something like lodash isEqual, and using that we can prevent triggering effects for record updates that don't actually alter any values in the store. Here's some preliminary perf testing of average time spent in `store.put()` during some common interactions | task | before (ms) | after (ms) | | ---- | ---- | ---- | | drawing lines | 0.0403 | 0.0214 | | drawing boxes | 0.0408 | 0.0348 | | translating lines | 0.0352 | 0.0042 | | translating boxes | 0.0051 | 0.0032 | | rotating lines | 0.0312 | 0.0065 | | rotating boxes | 0.0053 | 0.0035 | | brush selecting boxes | 0.0200 | 0.0232 | | traversal with shapes | 0.0130 | 0.0108 | | traversal without shapes | 0.0201 | 0.0173 | **traversal** means moving the camera and pointer around the canvas #### Discussion At the scale of hundredths of a millisecond these .put operations are so fast that even if they became literally instantaneous the change would not be human perceptible. That said, there is an overall marked improvement here. Especially for dealing with draw shapes. These figures are also mostly in line with expectations, aside from a couple of things: - I don't understand why the `brush selecting boxes` task got slower after the change. - I don't understand why the `traversal` tasks are slower than the `translating boxes` task, both before and after. I would expect that .putting shape records would be much slower than .putting pointer/camera records (since the latter have fewer and simpler properties) ### Change Type - [x] `patch` — Bug fix ### Test Plan 1. Add a step-by-step description of how to test your PR here. 2. - [ ] Unit Tests - [ ] End to end tests ### Release Notes - Add a brief release note for your PR here.
236 lines
6.6 KiB
Markdown
236 lines
6.6 KiB
Markdown
## API Report File for "@tldraw/validate"
|
|
|
|
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
|
|
|
```ts
|
|
|
|
import { IndexKey } from '@tldraw/utils';
|
|
import { JsonValue } from '@tldraw/utils';
|
|
|
|
// @public
|
|
const any: Validator<any>;
|
|
|
|
// @public
|
|
const array: Validator<unknown[]>;
|
|
|
|
// @public
|
|
function arrayOf<T>(itemValidator: Validatable<T>): ArrayOfValidator<T>;
|
|
|
|
// @public (undocumented)
|
|
export class ArrayOfValidator<T> extends Validator<T[]> {
|
|
constructor(itemValidator: Validatable<T>);
|
|
// (undocumented)
|
|
readonly itemValidator: Validatable<T>;
|
|
// (undocumented)
|
|
lengthGreaterThan1(): Validator<T[]>;
|
|
// (undocumented)
|
|
nonEmpty(): Validator<T[]>;
|
|
}
|
|
|
|
// @public
|
|
const bigint: Validator<bigint>;
|
|
|
|
// @public
|
|
const boolean: Validator<boolean>;
|
|
|
|
// @public
|
|
function dict<Key extends string, Value>(keyValidator: Validatable<Key>, valueValidator: Validatable<Value>): DictValidator<Key, Value>;
|
|
|
|
// @public (undocumented)
|
|
export class DictValidator<Key extends string, Value> extends Validator<Record<Key, Value>> {
|
|
constructor(keyValidator: Validatable<Key>, valueValidator: Validatable<Value>);
|
|
// (undocumented)
|
|
readonly keyValidator: Validatable<Key>;
|
|
// (undocumented)
|
|
readonly valueValidator: Validatable<Value>;
|
|
}
|
|
|
|
// @public
|
|
const indexKey: Validator<IndexKey>;
|
|
|
|
// @public
|
|
const integer: Validator<number>;
|
|
|
|
// @public
|
|
function jsonDict(): DictValidator<string, JsonValue>;
|
|
|
|
// @public
|
|
const jsonValue: Validator<JsonValue>;
|
|
|
|
// @public
|
|
const linkUrl: Validator<string>;
|
|
|
|
// @public
|
|
function literal<T extends boolean | number | string>(expectedValue: T): Validator<T>;
|
|
|
|
// @public (undocumented)
|
|
function literalEnum<const Values extends readonly unknown[]>(...values: Values): Validator<Values[number]>;
|
|
|
|
// @public
|
|
function model<T extends {
|
|
readonly id: string;
|
|
}>(name: string, validator: Validatable<T>): Validator<T>;
|
|
|
|
// @public
|
|
const nonZeroInteger: Validator<number>;
|
|
|
|
// @public
|
|
const nonZeroNumber: Validator<number>;
|
|
|
|
// @public (undocumented)
|
|
function nullable<T>(validator: Validatable<T>): Validator<null | T>;
|
|
|
|
// @public
|
|
const number: Validator<number>;
|
|
|
|
// @public
|
|
function object<Shape extends object>(config: {
|
|
readonly [K in keyof Shape]: Validatable<Shape[K]>;
|
|
}): ObjectValidator<{
|
|
[P in ExtractRequiredKeys<Shape>]: Shape[P];
|
|
} & {
|
|
[P in ExtractOptionalKeys<Shape>]?: Shape[P];
|
|
}>;
|
|
|
|
// @public (undocumented)
|
|
export class ObjectValidator<Shape extends object> extends Validator<Shape> {
|
|
constructor(config: {
|
|
readonly [K in keyof Shape]: Validatable<Shape[K]>;
|
|
}, shouldAllowUnknownProperties?: boolean);
|
|
// (undocumented)
|
|
allowUnknownProperties(): ObjectValidator<Shape>;
|
|
// (undocumented)
|
|
readonly config: {
|
|
readonly [K in keyof Shape]: Validatable<Shape[K]>;
|
|
};
|
|
extend<Extension extends Record<string, unknown>>(extension: {
|
|
readonly [K in keyof Extension]: Validatable<Extension[K]>;
|
|
}): ObjectValidator<Shape & Extension>;
|
|
}
|
|
|
|
// @public (undocumented)
|
|
function optional<T>(validator: Validatable<T>): Validator<T | undefined>;
|
|
|
|
// @public
|
|
const positiveInteger: Validator<number>;
|
|
|
|
// @public
|
|
const positiveNumber: Validator<number>;
|
|
|
|
// @public (undocumented)
|
|
function setEnum<T>(values: ReadonlySet<T>): Validator<T>;
|
|
|
|
// @public
|
|
const srcUrl: Validator<string>;
|
|
|
|
// @public
|
|
const string: Validator<string>;
|
|
|
|
declare namespace T {
|
|
export {
|
|
literal,
|
|
arrayOf,
|
|
object,
|
|
jsonDict,
|
|
dict,
|
|
union,
|
|
model,
|
|
setEnum,
|
|
optional,
|
|
nullable,
|
|
literalEnum,
|
|
ValidatorFn,
|
|
ValidatorUsingKnownGoodVersionFn,
|
|
Validatable,
|
|
ValidationError,
|
|
TypeOf,
|
|
Validator,
|
|
ArrayOfValidator,
|
|
ObjectValidator,
|
|
UnionValidator,
|
|
DictValidator,
|
|
unknown,
|
|
any,
|
|
string,
|
|
number,
|
|
positiveNumber,
|
|
nonZeroNumber,
|
|
integer,
|
|
positiveInteger,
|
|
nonZeroInteger,
|
|
boolean,
|
|
bigint,
|
|
array,
|
|
unknownObject,
|
|
jsonValue,
|
|
linkUrl,
|
|
srcUrl,
|
|
indexKey
|
|
}
|
|
}
|
|
export { T }
|
|
|
|
// @public (undocumented)
|
|
type TypeOf<V extends Validatable<any>> = V extends Validatable<infer T> ? T : never;
|
|
|
|
// @public
|
|
function union<Key extends string, Config extends UnionValidatorConfig<Key, Config>>(key: Key, config: Config): UnionValidator<Key, Config>;
|
|
|
|
// @public (undocumented)
|
|
export class UnionValidator<Key extends string, Config extends UnionValidatorConfig<Key, Config>, UnknownValue = never> extends Validator<TypeOf<Config[keyof Config]> | UnknownValue> {
|
|
constructor(key: Key, config: Config, unknownValueValidation: (value: object, variant: string) => UnknownValue);
|
|
// (undocumented)
|
|
validateUnknownVariants<Unknown>(unknownValueValidation: (value: object, variant: string) => Unknown): UnionValidator<Key, Config, Unknown>;
|
|
}
|
|
|
|
// @public
|
|
const unknown: Validator<unknown>;
|
|
|
|
// @public (undocumented)
|
|
const unknownObject: Validator<Record<string, unknown>>;
|
|
|
|
// @public (undocumented)
|
|
type Validatable<T> = {
|
|
validate: (value: unknown) => T;
|
|
validateUsingKnownGoodVersion?: (knownGoodValue: T, newValue: unknown) => T;
|
|
};
|
|
|
|
// @public (undocumented)
|
|
class ValidationError extends Error {
|
|
constructor(rawMessage: string, path?: ReadonlyArray<number | string>);
|
|
// (undocumented)
|
|
name: string;
|
|
// (undocumented)
|
|
readonly path: ReadonlyArray<number | string>;
|
|
// (undocumented)
|
|
readonly rawMessage: string;
|
|
}
|
|
|
|
// @public (undocumented)
|
|
export class Validator<T> implements Validatable<T> {
|
|
constructor(validationFn: ValidatorFn<T>, validateUsingKnownGoodVersionFn?: undefined | ValidatorUsingKnownGoodVersionFn<T, T>);
|
|
check(name: string, checkFn: (value: T) => void): Validator<T>;
|
|
// (undocumented)
|
|
check(checkFn: (value: T) => void): Validator<T>;
|
|
isValid(value: unknown): value is T;
|
|
nullable(): Validator<null | T>;
|
|
optional(): Validator<T | undefined>;
|
|
refine<U>(otherValidationFn: (value: T) => U): Validator<U>;
|
|
validate(value: unknown): T;
|
|
// (undocumented)
|
|
validateUsingKnownGoodVersion(knownGoodValue: T, newValue: unknown): T;
|
|
// (undocumented)
|
|
readonly validateUsingKnownGoodVersionFn?: undefined | ValidatorUsingKnownGoodVersionFn<T, T>;
|
|
// (undocumented)
|
|
readonly validationFn: ValidatorFn<T>;
|
|
}
|
|
|
|
// @public (undocumented)
|
|
type ValidatorFn<T> = (value: unknown) => T;
|
|
|
|
// @public (undocumented)
|
|
type ValidatorUsingKnownGoodVersionFn<In, Out = In> = (knownGoodValue: In, value: unknown) => Out;
|
|
|
|
// (No @packageDocumentation comment for this package)
|
|
|
|
```
|