@sinclair/typebox 0.28.7 → 0.28.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sinclair/typebox",
3
- "version": "0.28.7",
3
+ "version": "0.28.9",
4
4
  "description": "JSONSchema Type Builder with Static Type Resolution for TypeScript",
5
5
  "keywords": [
6
6
  "typescript",
package/readme.md CHANGED
@@ -83,7 +83,7 @@ License MIT
83
83
  - [References](#types-references)
84
84
  - [Recursive](#types-recursive)
85
85
  - [Conditional](#types-conditional)
86
- - [Template](#types-template-literal)
86
+ - [Template Literal](#types-template-literal)
87
87
  - [Indexed](#types-indexed)
88
88
  - [Rest](#types-rest)
89
89
  - [Guards](#types-guards)
@@ -814,11 +814,13 @@ type T2 = Static<typeof T2> // type T2 = string
814
814
 
815
815
  ### Template Literal Types
816
816
 
817
- Template Literal types are supported with `Type.TemplateLiteral`
817
+ TypeBox supports Template Literal types using `Type.TemplateLiteral`. These types can be created using a simple template DSL syntax, however more complex template literals can be created by passing an array of literal and union types. The examples below show the template DSL syntax.
818
818
 
819
819
  ```typescript
820
820
  // TypeScript
821
821
 
822
+ type P = `/post/${string}/user/${number}` // type P = `/post/${string}/user/${number}`
823
+
822
824
  type T = `option${'A'|'B'}` // type T = 'optionA' | 'optionB'
823
825
 
824
826
  type R = Record<T, string> // type R = {
@@ -828,13 +830,17 @@ type R = Record<T, string> // type R = {
828
830
 
829
831
  // TypeBox
830
832
 
831
- const T = Type.TemplateLiteral([ // const T = {
832
- Type.Literal('option'), // pattern: '^option(A|B)$',
833
- Type.Union([ // type: 'string'
834
- Type.Literal('A'), // }
835
- Type.Literal('B')
836
- ])
837
- ])
833
+ const P = Type.TemplateLiteral('/post/${string}/user/${number}')
834
+
835
+ // const P = {
836
+ // type: 'string',
837
+ // pattern: '^/post/(.*)/user/(0|[1-9][0-9]*)$'
838
+ // }
839
+
840
+ const T = Type.TemplateLiteral('option${A|B}') // const T = {
841
+ // pattern: '^option(A|B)$',
842
+ // type: 'string'
843
+ // }
838
844
 
839
845
  const R = Type.Record(T, Type.String()) // const R = {
840
846
  // type: 'object',
@@ -848,37 +854,48 @@ const R = Type.Record(T, Type.String()) // const R = {
848
854
  // }
849
855
  // }
850
856
  // }
851
-
852
- type T = Static<typeof T> // type T = 'optionA' | 'optionB'
853
-
854
- type R = Static<typeof R> // type R = {
855
- // optionA: string
856
- // optionB: string
857
- // }
858
857
  ```
859
858
 
860
859
  <a name='types-indexed'></a>
861
860
 
862
861
  ### Indexed Access Types
863
862
 
864
- Indexed Access types are supported with `Type.Index`
863
+ TypeBox supports Indexed Access types using `Type.Index`. This feature provides a consistent way to access property types without having to extract them from the underlying schema representation. Indexed accessors are supported for object and tuples, as well as nested union and intersect types.
865
864
 
866
865
  ```typescript
867
- const T = Type.Object({ // type T = {
868
- x: Type.Number(), // x: number
869
- y: Type.String(), // y: string
870
- z: Type.Boolean() // z: boolean
871
- }) // }
866
+ const T = Type.Object({ // const T = {
867
+ x: Type.Number(), // type: 'object',
868
+ y: Type.String(), // required: ['x', 'y', 'z'],
869
+ z: Type.Boolean() // properties: {
870
+ }) // x: { type: 'number' },
871
+ // y: { type: 'string' },
872
+ // z: { type: 'string' },
873
+ // }
874
+ // }
872
875
 
873
- const A = Type.Index(T, ['x']) // type A = T['x']
876
+ const A = Type.Index(T, ['x']) // const A = { type: 'number' }
874
877
 
875
- const B = Type.Index(T, Type.KeyOf(T)) // type B = T[keyof T]
878
+ const B = Type.Index(T, ['x', 'y']) // const B = {
879
+ // anyOf: [
880
+ // { type: 'number' },
881
+ // { type: 'string' }
882
+ // ]
883
+ // }
884
+
885
+ const C = Type.Index(T, Type.KeyOf(T)) // const C = {
886
+ // anyOf: [
887
+ // { type: 'number' },
888
+ // { type: 'string' },
889
+ // { type: 'boolean' }
890
+ // ]
891
+ // }
876
892
  ```
893
+
877
894
  <a name='types-rest'></a>
878
895
 
879
896
  ### Rest Types
880
897
 
881
- Rest parameters are supported with `Type.Rest`. This function is used to extract interior arrays from tuples to allow them to compose with the JavaScript spread operator `...`. This type can be used for tuple concatination and variadic function composition.
898
+ Rest parameters are supported with `Type.Rest`. This function is used to extract interior type elements from tuples which enables them to compose with the JavaScript spread operator `...`. This type can be used for tuple concatination as well as for variadic functions.
882
899
 
883
900
  ```typescript
884
901
  // TypeScript
package/typebox.d.ts CHANGED
@@ -16,6 +16,7 @@ export type UnionLast<U> = UnionToIntersect<U extends unknown ? (x: U) => 0 : ne
16
16
  export type UnionToTuple<U, L = UnionLast<U>> = [U] extends [never] ? [] : [...UnionToTuple<Exclude<U, L>>, L];
17
17
  export type Discard<T extends unknown[], D extends unknown> = T extends [infer L, ...infer R] ? (L extends D ? Discard<R, D> : [L, ...Discard<R, D>]) : [];
18
18
  export type Flat<T> = T extends [] ? [] : T extends [infer L] ? [...Flat<L>] : T extends [infer L, ...infer R] ? [...Flat<L>, ...Flat<R>] : [T];
19
+ export type Trim<T> = T extends `${' '}${infer U}` ? Trim<U> : T extends `${infer U}${' '}` ? Trim<U> : T;
19
20
  export type Assert<T, E> = T extends E ? T : never;
20
21
  export type Evaluate<T> = T extends infer O ? {
21
22
  [K in keyof O]: O[K];
@@ -96,20 +97,11 @@ export interface TBoolean extends TSchema {
96
97
  }
97
98
  export type TConstructorParameters<T extends TConstructor<TSchema[], TSchema>> = TTuple<T['parameters']>;
98
99
  export type TInstanceType<T extends TConstructor<TSchema[], TSchema>> = T['returns'];
99
- export type TCompositeIsOptional<T extends TSchema> = T extends TOptional<T> | TReadonlyOptional<T> ? true : false;
100
- export type TCompositeOptional<T extends TSchema[]> = T extends [infer L, ...infer R] ? TCompositeIsOptional<AssertType<L>> extends false ? false : TCompositeOptional<AssertRest<R>> : true;
101
- export type TCompositeKeyOfUnion1<T extends TObject> = keyof T['properties'];
102
- export type TCompositeKeyOfUnion2<T extends TObject[]> = T extends [infer L, ...infer R] ? TCompositeKeyOfUnion1<Assert<L, TObject>> | TCompositeKeyOfUnion2<Assert<R, TObject[]>> : never;
103
- export type TCompositeKeyOf<T extends TObject[]> = UnionToTuple<TCompositeKeyOfUnion2<T>>;
104
- export type TCompositePropertiesWithKey1<T extends TObject, K extends Key> = K extends keyof T['properties'] ? [T['properties'][K]] : [];
105
- export type TCompositePropertiesWithKey2<T extends TObject[], K extends Key> = T extends [infer L, ...infer R] ? [...TCompositePropertiesWithKey1<Assert<L, TObject>, K>, ...TCompositePropertiesWithKey2<Assert<R, TObject[]>, K>] : [];
106
- export type TCompositeObjectProperty<T extends TObject[], K extends Key> = TCompositePropertiesWithKey2<T, K> extends infer S ? TCompositeOptional<AssertRest<S>> extends true ? {
107
- [_ in K]: TOptional<IntersectType<AssertRest<S>>>;
108
- } : {
109
- [_ in K]: IntersectType<AssertRest<S>>;
110
- } : {};
111
- export type TCompositeObjectsWithKeys<T extends TObject[], K extends Key[]> = K extends [infer L, ...infer R] ? L extends Key ? TCompositeObjectProperty<T, L> & TCompositeObjectsWithKeys<T, Assert<R, Key[]>> : {} : {};
112
- export type TComposite<T extends TObject[]> = Ensure<TObject<Evaluate<TCompositeObjectsWithKeys<T, Assert<TCompositeKeyOf<T>, Key[]>>>>>;
100
+ export type TCompositeReduce<T extends TIntersect<TObject[]>, K extends string[]> = K extends [infer L, ...infer R] ? {
101
+ [_ in Assert<L, string>]: TIndexType<T, Assert<L, string>>;
102
+ } & TCompositeReduce<T, Assert<R, string[]>> : {};
103
+ export type TCompositeSelect<T extends TIntersect<TObject[]>> = UnionToTuple<keyof Static<T>> extends infer K ? Evaluate<TCompositeReduce<T, Assert<K, string[]>>> : {};
104
+ export type TComposite<T extends TObject[]> = TIntersect<T> extends infer R ? TObject<TCompositeSelect<Assert<R, TIntersect<TObject[]>>>> : TObject<{}>;
113
105
  export type TConstructorParameterArray<T extends readonly TSchema[], P extends unknown[]> = [...{
114
106
  [K in keyof T]: Static<AssertType<T[K]>, P>;
115
107
  }];
@@ -367,6 +359,13 @@ export interface TSymbol extends TSchema, SchemaOptions {
367
359
  type: 'null';
368
360
  typeOf: 'Symbol';
369
361
  }
362
+ export type TTemplateLiteralDslParserUnionLiteral<T extends string> = T extends `${infer L}|${infer R}` ? [TLiteral<Trim<L>>, ...TTemplateLiteralDslParserUnionLiteral<R>] : T extends `${infer L}` ? [TLiteral<Trim<L>>] : [
363
+ ];
364
+ export type TTemplateLiteralDslParserUnion<T extends string> = UnionType<TTemplateLiteralDslParserUnionLiteral<T>>;
365
+ export type TTemplateLiteralDslParserTerminal<T extends string> = T extends 'boolean' ? TBoolean : T extends 'bigint' ? TBigInt : T extends 'number' ? TNumber : T extends 'string' ? TString : TTemplateLiteralDslParserUnion<T>;
366
+ export type TTemplateLiteralDslParserTemplate<T extends string> = T extends `{${infer L}}${infer R}` ? [TTemplateLiteralDslParserTerminal<L>, ...TTemplateLiteralDslParserTemplate<R>] : T extends `${infer L}$${infer R}` ? [TLiteral<L>, ...TTemplateLiteralDslParserTemplate<R>] : T extends `${infer L}` ? [TLiteral<L>] : [
367
+ ];
368
+ export type TTemplateLiteralDslParser<T extends string> = Ensure<TTemplateLiteral<Assert<TTemplateLiteralDslParserTemplate<T>, TTemplateLiteralKind[]>>>;
370
369
  export type IsTemplateLiteralFiniteCheck<T> = T extends TTemplateLiteral<infer U> ? IsTemplateLiteralFiniteArray<Assert<U, TTemplateLiteralKind[]>> : T extends TUnion<infer U> ? IsTemplateLiteralFiniteArray<Assert<U, TTemplateLiteralKind[]>> : T extends TString ? false : T extends TBoolean ? false : T extends TNumber ? false : T extends TInteger ? false : T extends TBigInt ? false : T extends TLiteral ? true : false;
371
370
  export type IsTemplateLiteralFiniteArray<T extends TTemplateLiteralKind[]> = T extends [infer L, ...infer R] ? IsTemplateLiteralFiniteCheck<L> extends false ? false : IsTemplateLiteralFiniteArray<Assert<R, TTemplateLiteralKind[]>> : true;
372
371
  export type IsTemplateLiteralFinite<T> = T extends TTemplateLiteral<infer U> ? IsTemplateLiteralFiniteArray<U> : false;
@@ -630,6 +629,9 @@ export declare namespace TemplateLiteralFinite {
630
629
  export declare namespace TemplateLiteralGenerator {
631
630
  function Generate(expression: TemplateLiteralParser.Expression): IterableIterator<string>;
632
631
  }
632
+ export declare namespace TemplateLiteralDslParser {
633
+ function Parse(template_dsl: string): TTemplateLiteralKind[];
634
+ }
633
635
  export declare class TypeBuilder {
634
636
  /** `[Utility]` Creates a schema without `static` and `params` types */
635
637
  protected Create<T>(schema: Omit<T, 'static' | 'params'>): T;
@@ -726,6 +728,8 @@ export declare class StandardTypeBuilder extends TypeBuilder {
726
728
  Rest<T extends TSchema>(schema: T): TRest<T>;
727
729
  /** `[Standard]` Creates a String type */
728
730
  String(options?: StringOptions): TString;
731
+ /** `[Experimental]` Creates a template literal type from dsl string */
732
+ TemplateLiteral<T extends string>(dsl: T, options?: SchemaOptions): TTemplateLiteralDslParser<T>;
729
733
  /** `[Standard]` Creates a template literal type */
730
734
  TemplateLiteral<T extends TTemplateLiteralKind[]>(kinds: [...T], options?: SchemaOptions): TTemplateLiteral<T>;
731
735
  /** `[Standard]` Creates a Tuple type */
package/typebox.js CHANGED
@@ -27,7 +27,7 @@ THE SOFTWARE.
27
27
 
28
28
  ---------------------------------------------------------------------------*/
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
- exports.Type = exports.StandardType = exports.ExtendedTypeBuilder = exports.StandardTypeBuilder = exports.TypeBuilder = exports.TemplateLiteralGenerator = exports.TemplateLiteralFinite = exports.TemplateLiteralParser = exports.TemplateLiteralParserError = exports.TemplateLiteralResolver = exports.TemplateLiteralPattern = exports.UnionResolver = exports.KeyArrayResolver = exports.KeyResolver = exports.ObjectMap = exports.IndexedAccessor = exports.TypeClone = exports.TypeExtends = exports.TypeExtendsResult = exports.ExtendsUndefined = exports.TypeGuard = exports.TypeGuardUnknownTypeError = exports.FormatRegistry = exports.TypeRegistry = exports.PatternStringExact = exports.PatternNumberExact = exports.PatternBooleanExact = exports.PatternString = exports.PatternNumber = exports.PatternBoolean = exports.Kind = exports.Hint = exports.Modifier = void 0;
30
+ exports.Type = exports.StandardType = exports.ExtendedTypeBuilder = exports.StandardTypeBuilder = exports.TypeBuilder = exports.TemplateLiteralDslParser = exports.TemplateLiteralGenerator = exports.TemplateLiteralFinite = exports.TemplateLiteralParser = exports.TemplateLiteralParserError = exports.TemplateLiteralResolver = exports.TemplateLiteralPattern = exports.UnionResolver = exports.KeyArrayResolver = exports.KeyResolver = exports.ObjectMap = exports.IndexedAccessor = exports.TypeClone = exports.TypeExtends = exports.TypeExtendsResult = exports.ExtendsUndefined = exports.TypeGuard = exports.TypeGuardUnknownTypeError = exports.FormatRegistry = exports.TypeRegistry = exports.PatternStringExact = exports.PatternNumberExact = exports.PatternBooleanExact = exports.PatternString = exports.PatternNumber = exports.PatternBoolean = exports.Kind = exports.Hint = exports.Modifier = void 0;
31
31
  // --------------------------------------------------------------------------
32
32
  // Symbols
33
33
  // --------------------------------------------------------------------------
@@ -1847,6 +1847,54 @@ var TemplateLiteralGenerator;
1847
1847
  }
1848
1848
  TemplateLiteralGenerator.Generate = Generate;
1849
1849
  })(TemplateLiteralGenerator = exports.TemplateLiteralGenerator || (exports.TemplateLiteralGenerator = {}));
1850
+ // ---------------------------------------------------------------------
1851
+ // TemplateLiteralDslParser
1852
+ // ---------------------------------------------------------------------
1853
+ var TemplateLiteralDslParser;
1854
+ (function (TemplateLiteralDslParser) {
1855
+ function* ParseUnion(template) {
1856
+ const trim = template.trim().replace(/"|'/g, '');
1857
+ if (trim === 'boolean')
1858
+ return yield exports.Type.Boolean();
1859
+ if (trim === 'number')
1860
+ return yield exports.Type.Number();
1861
+ if (trim === 'bigint')
1862
+ return yield exports.Type.BigInt();
1863
+ if (trim === 'string')
1864
+ return yield exports.Type.String();
1865
+ const literals = trim.split('|').map((literal) => exports.Type.Literal(literal.trim()));
1866
+ return yield literals.length === 0 ? exports.Type.Never() : literals.length === 1 ? literals[0] : exports.Type.Union(literals);
1867
+ }
1868
+ function* ParseTerminal(template) {
1869
+ if (template[1] !== '{') {
1870
+ const L = exports.Type.Literal('$');
1871
+ const R = ParseLiteral(template.slice(1));
1872
+ return yield* [L, ...R];
1873
+ }
1874
+ for (let i = 2; i < template.length; i++) {
1875
+ if (template[i] === '}') {
1876
+ const L = ParseUnion(template.slice(2, i));
1877
+ const R = ParseLiteral(template.slice(i + 1));
1878
+ return yield* [...L, ...R];
1879
+ }
1880
+ }
1881
+ yield exports.Type.Literal(template);
1882
+ }
1883
+ function* ParseLiteral(template) {
1884
+ for (let i = 0; i < template.length; i++) {
1885
+ if (template[i] === '$') {
1886
+ const L = exports.Type.Literal(template.slice(0, i));
1887
+ const R = ParseTerminal(template.slice(i));
1888
+ return yield* [L, ...R];
1889
+ }
1890
+ }
1891
+ yield exports.Type.Literal(template);
1892
+ }
1893
+ function Parse(template_dsl) {
1894
+ return [...ParseLiteral(template_dsl)];
1895
+ }
1896
+ TemplateLiteralDslParser.Parse = Parse;
1897
+ })(TemplateLiteralDslParser = exports.TemplateLiteralDslParser || (exports.TemplateLiteralDslParser = {}));
1850
1898
  // --------------------------------------------------------------------------
1851
1899
  // TypeOrdinal: Used for auto $id generation
1852
1900
  // --------------------------------------------------------------------------
@@ -1901,44 +1949,10 @@ class StandardTypeBuilder extends TypeBuilder {
1901
1949
  }
1902
1950
  /** `[Standard]` Creates a Composite object type. */
1903
1951
  Composite(objects, options) {
1904
- const isOptionalAll = (objects, key) => objects.every((object) => !(key in object.properties) || IsOptional(object.properties[key]));
1905
- const IsOptional = (schema) => TypeGuard.TOptional(schema) || TypeGuard.TReadonlyOptional(schema);
1906
- const [required, optional] = [new Set(), new Set()];
1907
- for (const object of objects) {
1908
- for (const key of globalThis.Object.getOwnPropertyNames(object.properties)) {
1909
- if (isOptionalAll(objects, key))
1910
- optional.add(key);
1911
- }
1912
- }
1913
- for (const object of objects) {
1914
- for (const key of globalThis.Object.getOwnPropertyNames(object.properties)) {
1915
- if (!optional.has(key))
1916
- required.add(key);
1917
- }
1918
- }
1919
- const properties = {};
1920
- for (const object of objects) {
1921
- for (const [key, schema] of Object.entries(object.properties)) {
1922
- const property = TypeClone.Clone(schema, {});
1923
- if (!optional.has(key))
1924
- delete property[exports.Modifier];
1925
- if (key in properties) {
1926
- properties[key] = TypeGuard.TIntersect(properties[key]) ? this.Intersect([...properties[key].allOf, property]) : this.Intersect([properties[key], property]);
1927
- }
1928
- else {
1929
- properties[key] = property;
1930
- }
1931
- }
1932
- }
1933
- for (const key of globalThis.Object.getOwnPropertyNames(properties)) {
1934
- properties[key] = optional.has(key) ? this.Optional(properties[key]) : properties[key];
1935
- }
1936
- if (required.size > 0) {
1937
- return this.Create({ ...options, [exports.Kind]: 'Object', type: 'object', properties, required: [...required] });
1938
- }
1939
- else {
1940
- return this.Create({ ...options, [exports.Kind]: 'Object', type: 'object', properties });
1941
- }
1952
+ const intersect = exports.Type.Intersect(objects, {});
1953
+ const keys = KeyResolver.ResolveKeys(intersect, { includePatterns: false });
1954
+ const properties = keys.reduce((acc, key) => ({ ...acc, [key]: exports.Type.Index(intersect, [key]) }), {});
1955
+ return exports.Type.Object(properties, options);
1942
1956
  }
1943
1957
  /** `[Standard]` Creates a Enum type */
1944
1958
  Enum(item, options = {}) {
@@ -2232,8 +2246,11 @@ class StandardTypeBuilder extends TypeBuilder {
2232
2246
  return this.Create({ ...options, [exports.Kind]: 'String', type: 'string' });
2233
2247
  }
2234
2248
  /** `[Standard]` Creates a template literal type */
2235
- TemplateLiteral(kinds, options = {}) {
2236
- const pattern = TemplateLiteralPattern.Create(kinds);
2249
+ TemplateLiteral(unresolved, options = {}) {
2250
+ // prettier-ignore
2251
+ const pattern = (typeof unresolved === 'string')
2252
+ ? TemplateLiteralPattern.Create(TemplateLiteralDslParser.Parse(unresolved))
2253
+ : TemplateLiteralPattern.Create(unresolved);
2237
2254
  return this.Create({ ...options, [exports.Kind]: 'TemplateLiteral', type: 'string', pattern });
2238
2255
  }
2239
2256
  /** `[Standard]` Creates a Tuple type */