Revision 0.31.8 (#566)

* Discard on Mapped Object Types

* Discard Identifier Tests
This commit is contained in:
sinclairzx81
2023-08-31 05:35:49 +09:00
committed by GitHub
parent 010ff1840c
commit 9c42cbc1e0
7 changed files with 103 additions and 61 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@sinclair/typebox",
"version": "0.31.7",
"version": "0.31.8",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@sinclair/typebox",
"version": "0.31.7",
"version": "0.31.8",
"license": "MIT",
"devDependencies": {
"@sinclair/hammer": "^0.17.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@sinclair/typebox",
"version": "0.31.7",
"version": "0.31.8",
"description": "JSONSchema Type Builder with Static Type Resolution for TypeScript",
"keywords": [
"typescript",
+12 -10
View File
@@ -2842,10 +2842,12 @@ export class TypeBuilder {
protected Throw(message: string): never {
throw new TypeBuilderError(message)
}
/** `[Internal]` Discards a property key from the given schema */
protected Discard(schema: TSchema, key: PropertyKey): TSchema {
const { [key as any]: _, ...rest } = schema
return rest as TSchema
/** `[Internal]` Discards property keys from the given record type */
protected Discard(record: Record<PropertyKey, any>, keys: PropertyKey[]) {
return keys.reduce((acc, key) => {
const { [key as any]: _, ...rest } = acc
return rest
}, record) as any
}
/** `[Json]` Omits compositing symbols from this schema */
public Strict<T extends TSchema>(schema: T): T {
@@ -3082,7 +3084,7 @@ export class JsonTypeBuilder extends TypeBuilder {
public Omit(schema: TSchema, unresolved: any, options: SchemaOptions = {}): any {
const keys = KeyArrayResolver.Resolve(unresolved)
// prettier-ignore
return ObjectMap.Map(this.Discard(TypeClone.Type(schema), Transform), (object) => {
return ObjectMap.Map(this.Discard(TypeClone.Type(schema), ['$id', Transform]), (object) => {
if (ValueGuard.IsArray(object.required)) {
object.required = object.required.filter((key: string) => !keys.includes(key as any))
if (object.required.length === 0) delete object.required
@@ -3096,11 +3098,11 @@ export class JsonTypeBuilder extends TypeBuilder {
/** `[Json]` Constructs a type where all properties are optional */
public Partial<T extends TSchema>(schema: T, options: ObjectOptions = {}): TPartial<T> {
// prettier-ignore
return ObjectMap.Map(this.Discard(TypeClone.Type(schema), Transform), (object) => {
return ObjectMap.Map(this.Discard(TypeClone.Type(schema), ['$id', Transform]), (object) => {
const properties = Object.getOwnPropertyNames(object.properties).reduce((acc, key) => {
return { ...acc, [key]: this.Optional(object.properties[key]) }
}, {} as TProperties)
return this.Object(properties, this.Discard(object, 'required') /* object used as options to retain other constraints */)
return this.Object(properties, this.Discard(object, ['required']) /* object used as options to retain other constraints */)
}, options)
}
/** `[Json]` Constructs a type whose keys are picked from the given type */
@@ -3117,7 +3119,7 @@ export class JsonTypeBuilder extends TypeBuilder {
public Pick(schema: TSchema, unresolved: any, options: SchemaOptions = {}): any {
const keys = KeyArrayResolver.Resolve(unresolved)
// prettier-ignore
return ObjectMap.Map(this.Discard(TypeClone.Type(schema), Transform), (object) => {
return ObjectMap.Map(this.Discard(TypeClone.Type(schema), ['$id', Transform]), (object) => {
if (ValueGuard.IsArray(object.required)) {
object.required = object.required.filter((key: any) => keys.includes(key))
if (object.required.length === 0) delete object.required
@@ -3182,9 +3184,9 @@ export class JsonTypeBuilder extends TypeBuilder {
/** `[Json]` Constructs a type where all properties are required */
public Required<T extends TSchema>(schema: T, options: SchemaOptions = {}): TRequired<T> {
// prettier-ignore
return ObjectMap.Map(this.Discard(TypeClone.Type(schema), Transform), (object) => {
return ObjectMap.Map(this.Discard(TypeClone.Type(schema), ['$id', Transform]), (object) => {
const properties = Object.getOwnPropertyNames(object.properties).reduce((acc, key) => {
return { ...acc, [key]: this.Discard(object.properties[key], Optional) as TSchema }
return { ...acc, [key]: this.Discard(object.properties[key], [Optional]) as TSchema }
}, {} as TProperties)
return this.Object(properties, object /* object used as options to retain other constraints */)
}, options)
+22 -12
View File
@@ -102,18 +102,28 @@ describe('type/guard/TOmit', () => {
Assert.IsTrue(TypeGuard.TNumber(T.properties.ad))
Assert.IsEqual(T.required, ['ad'])
})
// ----------------------------------------------------------------
// Discard
// ----------------------------------------------------------------
it('Should override $id', () => {
const A = Type.Object({ x: Type.Number() }, { $id: 'A' })
const T = Type.Omit(A, ['x'], { $id: 'T' })
Assert.IsEqual(T.$id!, 'T')
})
it('Should discard $id', () => {
const A = Type.Object({ x: Type.Number() }, { $id: 'A' })
const T = Type.Omit(A, ['x'])
Assert.IsFalse('$id' in T)
})
it('Should discard transform', () => {
const S = Type.Transform(
Type.Object({
x: Type.Number(),
y: Type.String(),
}),
{
Decode: (value) => value,
Encode: (value) => value,
},
)
const T = Type.Omit(S, ['x'])
Assert.IsFalse(Transform in T)
const T = Type.Object({
x: Type.Number(),
y: Type.String(),
})
const S = Type.Transform(T)
.Decode((value) => value)
.Encode((value) => value)
const R = Type.Omit(S, ['x'])
Assert.IsFalse(Transform in R)
})
})
+22 -12
View File
@@ -40,18 +40,28 @@ describe('type/guard/TPartial', () => {
Assert.IsEqual(T.anyOf[0].required, undefined)
Assert.IsEqual(T.anyOf[1].required, undefined)
})
// ----------------------------------------------------------------
// Discard
// ----------------------------------------------------------------
it('Should override $id', () => {
const A = Type.Object({ x: Type.Number() }, { $id: 'A' })
const T = Type.Partial(A, { $id: 'T' })
Assert.IsEqual(T.$id!, 'T')
})
it('Should discard $id', () => {
const A = Type.Object({ x: Type.Number() }, { $id: 'A' })
const T = Type.Partial(A)
Assert.IsFalse('$id' in T)
})
it('Should discard transform', () => {
const S = Type.Transform(
Type.Object({
x: Type.Number(),
y: Type.String(),
}),
{
Decode: (value) => value,
Encode: (value) => value,
},
)
const T = Type.Partial(S)
Assert.IsFalse(Transform in T)
const T = Type.Object({
x: Type.Number(),
y: Type.String(),
})
const S = Type.Transform(T)
.Decode((value) => value)
.Encode((value) => value)
const R = Type.Partial(S)
Assert.IsFalse(Transform in R)
})
})
+22 -12
View File
@@ -104,18 +104,28 @@ describe('type/guard/TPick', () => {
Assert.IsTrue(TypeGuard.TNumber(T.properties.ac))
Assert.IsEqual(T.required, ['ab', 'ac'])
})
// ----------------------------------------------------------------
// Discard
// ----------------------------------------------------------------
it('Should override $id', () => {
const A = Type.Object({ x: Type.Number() }, { $id: 'A' })
const T = Type.Pick(A, ['x'], { $id: 'T' })
Assert.IsEqual(T.$id!, 'T')
})
it('Should discard $id', () => {
const A = Type.Object({ x: Type.Number() }, { $id: 'A' })
const T = Type.Pick(A, ['x'])
Assert.IsFalse('$id' in T)
})
it('Should discard transform', () => {
const S = Type.Transform(
Type.Object({
x: Type.Number(),
y: Type.String(),
}),
{
Decode: (value) => value,
Encode: (value) => value,
},
)
const T = Type.Pick(S, ['x'])
Assert.IsFalse(Transform in T)
const T = Type.Object({
x: Type.Number(),
y: Type.String(),
})
const S = Type.Transform(T)
.Decode((value) => value)
.Encode((value) => value)
const R = Type.Pick(S, ['x'])
Assert.IsFalse(Transform in R)
})
})
+22 -12
View File
@@ -37,18 +37,28 @@ describe('type/guard/TRequired', () => {
Assert.IsEqual(T.anyOf[0].required, ['x'])
Assert.IsEqual(T.anyOf[1].required, ['y'])
})
// ----------------------------------------------------------------
// Discard
// ----------------------------------------------------------------
it('Should override $id', () => {
const A = Type.Object({ x: Type.Number() }, { $id: 'A' })
const T = Type.Required(A, { $id: 'T' })
Assert.IsEqual(T.$id!, 'T')
})
it('Should discard $id', () => {
const A = Type.Object({ x: Type.Number() }, { $id: 'A' })
const T = Type.Required(A)
Assert.IsFalse('$id' in T)
})
it('Should discard transform', () => {
const S = Type.Transform(
Type.Object({
x: Type.Number(),
y: Type.String(),
}),
{
Decode: (value) => value,
Encode: (value) => value,
},
)
const T = Type.Required(S)
Assert.IsFalse(Transform in T)
const T = Type.Object({
x: Type.Number(),
y: Type.String(),
})
const S = Type.Transform(T)
.Decode((value) => value)
.Encode((value) => value)
const R = Type.Required(S)
Assert.IsFalse(Transform in R)
})
})