[fix] allow loading files (#3517)
I messed up the schema validator for loading files. ### Change Type <!-- ❗ Please select a 'Scope' label ❗️ --> - [x] `sdk` — Changes the tldraw SDK - [ ] `dotcom` — Changes the tldraw.com web app - [ ] `docs` — Changes to the documentation, examples, or templates. - [ ] `vs code` — Changes to the vscode plugin - [ ] `internal` — Does not affect user-facing stuff <!-- ❗ Please select a 'Type' label ❗️ --> - [x] `bugfix` — Bug fix - [ ] `feature` — New feature - [ ] `improvement` — Improving existing features - [ ] `chore` — Updating dependencies, other boring stuff - [ ] `galaxy brain` — Architectural changes - [ ] `tests` — Changes to any test code - [ ] `tools` — Changes to infrastructure, CI, internal scripts, debugging tools, etc. - [ ] `dunno` — I don't know
This commit is contained in:
parent
f70fd2729d
commit
625f4abc3b
4 changed files with 80 additions and 14 deletions
|
@ -62,7 +62,7 @@ const schemaV2 = T.object<SerializedSchemaV2>({
|
||||||
|
|
||||||
const tldrawFileValidator: T.Validator<TldrawFile> = T.object({
|
const tldrawFileValidator: T.Validator<TldrawFile> = T.object({
|
||||||
tldrawFileFormatVersion: T.nonZeroInteger,
|
tldrawFileFormatVersion: T.nonZeroInteger,
|
||||||
schema: T.union('schemaVersion', {
|
schema: T.numberUnion('schemaVersion', {
|
||||||
1: schemaV1,
|
1: schemaV1,
|
||||||
2: schemaV2,
|
2: schemaV2,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -83,6 +83,9 @@ function nullable<T>(validator: Validatable<T>): Validator<null | T>;
|
||||||
// @public
|
// @public
|
||||||
const number: Validator<number>;
|
const number: Validator<number>;
|
||||||
|
|
||||||
|
// @internal (undocumented)
|
||||||
|
function numberUnion<Key extends string, Config extends UnionValidatorConfig<Key, Config>>(key: Key, config: Config): UnionValidator<Key, Config>;
|
||||||
|
|
||||||
// @public
|
// @public
|
||||||
function object<Shape extends object>(config: {
|
function object<Shape extends object>(config: {
|
||||||
readonly [K in keyof Shape]: Validatable<Shape[K]>;
|
readonly [K in keyof Shape]: Validatable<Shape[K]>;
|
||||||
|
@ -134,6 +137,7 @@ declare namespace T {
|
||||||
jsonDict,
|
jsonDict,
|
||||||
dict,
|
dict,
|
||||||
union,
|
union,
|
||||||
|
numberUnion,
|
||||||
model,
|
model,
|
||||||
setEnum,
|
setEnum,
|
||||||
optional,
|
optional,
|
||||||
|
@ -178,7 +182,7 @@ function union<Key extends string, Config extends UnionValidatorConfig<Key, Conf
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export class UnionValidator<Key extends string, Config extends UnionValidatorConfig<Key, Config>, UnknownValue = never> extends Validator<TypeOf<Config[keyof Config]> | UnknownValue> {
|
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);
|
constructor(key: Key, config: Config, unknownValueValidation: (value: object, variant: string) => UnknownValue, useNumberKeys: boolean);
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
validateUnknownVariants<Unknown>(unknownValueValidation: (value: object, variant: string) => Unknown): UnionValidator<Key, Config, Unknown>;
|
validateUnknownVariants<Unknown>(unknownValueValidation: (value: object, variant: string) => Unknown): UnionValidator<Key, Config, Unknown>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3027,6 +3027,14 @@
|
||||||
"kind": "Content",
|
"kind": "Content",
|
||||||
"text": "(value: object, variant: string) => UnknownValue"
|
"text": "(value: object, variant: string) => UnknownValue"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": ", useNumberKeys: "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": "boolean"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"kind": "Content",
|
"kind": "Content",
|
||||||
"text": ");"
|
"text": ");"
|
||||||
|
@ -3059,6 +3067,14 @@
|
||||||
"endIndex": 6
|
"endIndex": 6
|
||||||
},
|
},
|
||||||
"isOptional": false
|
"isOptional": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameterName": "useNumberKeys",
|
||||||
|
"parameterTypeTokenRange": {
|
||||||
|
"startIndex": 7,
|
||||||
|
"endIndex": 8
|
||||||
|
},
|
||||||
|
"isOptional": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -4260,6 +4276,14 @@
|
||||||
"kind": "Content",
|
"kind": "Content",
|
||||||
"text": "(value: object, variant: string) => UnknownValue"
|
"text": "(value: object, variant: string) => UnknownValue"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": ", useNumberKeys: "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": "boolean"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"kind": "Content",
|
"kind": "Content",
|
||||||
"text": ");"
|
"text": ");"
|
||||||
|
@ -4292,6 +4316,14 @@
|
||||||
"endIndex": 6
|
"endIndex": 6
|
||||||
},
|
},
|
||||||
"isOptional": false
|
"isOptional": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameterName": "useNumberKeys",
|
||||||
|
"parameterTypeTokenRange": {
|
||||||
|
"startIndex": 7,
|
||||||
|
"endIndex": 8
|
||||||
|
},
|
||||||
|
"isOptional": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -394,7 +394,8 @@ export class UnionValidator<
|
||||||
constructor(
|
constructor(
|
||||||
private readonly key: Key,
|
private readonly key: Key,
|
||||||
private readonly config: Config,
|
private readonly config: Config,
|
||||||
private readonly unknownValueValidation: (value: object, variant: string) => UnknownValue
|
private readonly unknownValueValidation: (value: object, variant: string) => UnknownValue,
|
||||||
|
private readonly useNumberKeys: boolean
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
(input) => {
|
(input) => {
|
||||||
|
@ -442,11 +443,13 @@ export class UnionValidator<
|
||||||
matchingSchema: Validatable<any> | undefined
|
matchingSchema: Validatable<any> | undefined
|
||||||
variant: string
|
variant: string
|
||||||
} {
|
} {
|
||||||
const variant = getOwnProperty(object, this.key) as keyof Config | undefined
|
const variant = getOwnProperty(object, this.key) as string & keyof Config
|
||||||
if (typeof variant !== 'string') {
|
if (!this.useNumberKeys && typeof variant !== 'string') {
|
||||||
throw new ValidationError(
|
throw new ValidationError(
|
||||||
`Expected a string for key "${this.key}", got ${typeToString(variant)}`
|
`Expected a string for key "${this.key}", got ${typeToString(variant)}`
|
||||||
)
|
)
|
||||||
|
} else if (this.useNumberKeys && !Number.isFinite(Number(variant))) {
|
||||||
|
throw new ValidationError(`Expected a number for key "${this.key}", got "${variant as any}"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const matchingSchema = hasOwnProperty(this.config, variant) ? this.config[variant] : undefined
|
const matchingSchema = hasOwnProperty(this.config, variant) ? this.config[variant] : undefined
|
||||||
|
@ -456,7 +459,7 @@ export class UnionValidator<
|
||||||
validateUnknownVariants<Unknown>(
|
validateUnknownVariants<Unknown>(
|
||||||
unknownValueValidation: (value: object, variant: string) => Unknown
|
unknownValueValidation: (value: object, variant: string) => Unknown
|
||||||
): UnionValidator<Key, Config, Unknown> {
|
): UnionValidator<Key, Config, Unknown> {
|
||||||
return new UnionValidator(this.key, this.config, unknownValueValidation)
|
return new UnionValidator(this.key, this.config, unknownValueValidation, this.useNumberKeys)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -829,14 +832,41 @@ export function union<Key extends string, Config extends UnionValidatorConfig<Ke
|
||||||
key: Key,
|
key: Key,
|
||||||
config: Config
|
config: Config
|
||||||
): UnionValidator<Key, Config> {
|
): UnionValidator<Key, Config> {
|
||||||
return new UnionValidator(key, config, (unknownValue, unknownVariant) => {
|
return new UnionValidator(
|
||||||
throw new ValidationError(
|
key,
|
||||||
`Expected one of ${Object.keys(config)
|
config,
|
||||||
.map((key) => JSON.stringify(key))
|
(unknownValue, unknownVariant) => {
|
||||||
.join(' or ')}, got ${JSON.stringify(unknownVariant)}`,
|
throw new ValidationError(
|
||||||
[key]
|
`Expected one of ${Object.keys(config)
|
||||||
)
|
.map((key) => JSON.stringify(key))
|
||||||
})
|
.join(' or ')}, got ${JSON.stringify(unknownVariant)}`,
|
||||||
|
[key]
|
||||||
|
)
|
||||||
|
},
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function numberUnion<Key extends string, Config extends UnionValidatorConfig<Key, Config>>(
|
||||||
|
key: Key,
|
||||||
|
config: Config
|
||||||
|
): UnionValidator<Key, Config> {
|
||||||
|
return new UnionValidator(
|
||||||
|
key,
|
||||||
|
config,
|
||||||
|
(unknownValue, unknownVariant) => {
|
||||||
|
throw new ValidationError(
|
||||||
|
`Expected one of ${Object.keys(config)
|
||||||
|
.map((key) => JSON.stringify(key))
|
||||||
|
.join(' or ')}, got ${JSON.stringify(unknownVariant)}`,
|
||||||
|
[key]
|
||||||
|
)
|
||||||
|
},
|
||||||
|
true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue