[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:
David Sheldrick 2024-04-17 20:38:31 +01:00 committed by GitHub
parent f70fd2729d
commit 625f4abc3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 80 additions and 14 deletions

View file

@ -62,7 +62,7 @@ const schemaV2 = T.object<SerializedSchemaV2>({
const tldrawFileValidator: T.Validator<TldrawFile> = T.object({
tldrawFileFormatVersion: T.nonZeroInteger,
schema: T.union('schemaVersion', {
schema: T.numberUnion('schemaVersion', {
1: schemaV1,
2: schemaV2,
}),

View file

@ -83,6 +83,9 @@ function nullable<T>(validator: Validatable<T>): Validator<null | T>;
// @public
const number: Validator<number>;
// @internal (undocumented)
function numberUnion<Key extends string, Config extends UnionValidatorConfig<Key, Config>>(key: Key, config: Config): UnionValidator<Key, Config>;
// @public
function object<Shape extends object>(config: {
readonly [K in keyof Shape]: Validatable<Shape[K]>;
@ -134,6 +137,7 @@ declare namespace T {
jsonDict,
dict,
union,
numberUnion,
model,
setEnum,
optional,
@ -178,7 +182,7 @@ function union<Key extends string, Config extends UnionValidatorConfig<Key, Conf
// @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);
constructor(key: Key, config: Config, unknownValueValidation: (value: object, variant: string) => UnknownValue, useNumberKeys: boolean);
// (undocumented)
validateUnknownVariants<Unknown>(unknownValueValidation: (value: object, variant: string) => Unknown): UnionValidator<Key, Config, Unknown>;
}

View file

@ -3027,6 +3027,14 @@
"kind": "Content",
"text": "(value: object, variant: string) => UnknownValue"
},
{
"kind": "Content",
"text": ", useNumberKeys: "
},
{
"kind": "Content",
"text": "boolean"
},
{
"kind": "Content",
"text": ");"
@ -3059,6 +3067,14 @@
"endIndex": 6
},
"isOptional": false
},
{
"parameterName": "useNumberKeys",
"parameterTypeTokenRange": {
"startIndex": 7,
"endIndex": 8
},
"isOptional": false
}
]
},
@ -4260,6 +4276,14 @@
"kind": "Content",
"text": "(value: object, variant: string) => UnknownValue"
},
{
"kind": "Content",
"text": ", useNumberKeys: "
},
{
"kind": "Content",
"text": "boolean"
},
{
"kind": "Content",
"text": ");"
@ -4292,6 +4316,14 @@
"endIndex": 6
},
"isOptional": false
},
{
"parameterName": "useNumberKeys",
"parameterTypeTokenRange": {
"startIndex": 7,
"endIndex": 8
},
"isOptional": false
}
]
},

View file

@ -394,7 +394,8 @@ export class UnionValidator<
constructor(
private readonly key: Key,
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(
(input) => {
@ -442,11 +443,13 @@ export class UnionValidator<
matchingSchema: Validatable<any> | undefined
variant: string
} {
const variant = getOwnProperty(object, this.key) as keyof Config | undefined
if (typeof variant !== 'string') {
const variant = getOwnProperty(object, this.key) as string & keyof Config
if (!this.useNumberKeys && typeof variant !== 'string') {
throw new ValidationError(
`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
@ -456,7 +459,7 @@ export class UnionValidator<
validateUnknownVariants<Unknown>(
unknownValueValidation: (value: object, variant: string) => 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,
config: Config
): UnionValidator<Key, Config> {
return new UnionValidator(key, config, (unknownValue, unknownVariant) => {
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]
)
})
},
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
)
}
/**