@travetto/schema 3.1.9 → 3.2.0

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/README.md CHANGED
@@ -36,6 +36,7 @@ export class User {
36
36
  name: string;
37
37
  age: number;
38
38
  favoriteFood?: 'pizza' | 'burrito' | 'salad';
39
+ height?: `${number}${'m' | 'ft'}`;
39
40
  }
40
41
  ```
41
42
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/schema",
3
- "version": "3.1.9",
3
+ "version": "3.2.0",
4
4
  "description": "Data type registry for runtime validation, reflection and binding.",
5
5
  "keywords": [
6
6
  "schema",
@@ -27,10 +27,10 @@
27
27
  "directory": "module/schema"
28
28
  },
29
29
  "dependencies": {
30
- "@travetto/registry": "^3.1.5"
30
+ "@travetto/registry": "^3.2.0"
31
31
  },
32
32
  "peerDependencies": {
33
- "@travetto/transformer": "^3.1.5"
33
+ "@travetto/transformer": "^3.2.0"
34
34
  },
35
35
  "peerDependenciesMeta": {
36
36
  "@travetto/transformer": {
@@ -189,6 +189,7 @@ class $SchemaRegistry extends MetadataRegistry<ClassConfig, FieldConfig> {
189
189
  baseType: RootIndex.getFunctionMetadata(cls)?.abstract,
190
190
  metadata: {},
191
191
  methods: {},
192
+ externalName: cls.name.replace('Ⲑsyn', ''),
192
193
  views: {
193
194
  [AllViewⲐ]: {
194
195
  schema: {},
@@ -5,6 +5,9 @@ import { ValidatorFn } from '../validate/types';
5
5
 
6
6
  export type ClassList = Class | [Class];
7
7
 
8
+ type TemplateLiteralPart = string | NumberConstructor | StringConstructor | BooleanConstructor;
9
+ export type TemplateLiteral = { op: 'and' | 'or', values: (TemplateLiteralPart | TemplateLiteral)[] };
10
+
8
11
  /**
9
12
  * Basic describable configuration
10
13
  */
@@ -83,6 +86,10 @@ export interface ClassConfig extends DescribableConfig {
83
86
  * Method parameter configs
84
87
  */
85
88
  methods: Record<string, FieldConfig[]>;
89
+ /**
90
+ * Name for consuming clients
91
+ */
92
+ externalName: string;
86
93
  }
87
94
 
88
95
  /**
@@ -135,7 +142,7 @@ export interface FieldConfig extends DescribableConfig {
135
142
  /**
136
143
  * Does the field expect a match
137
144
  */
138
- match?: { re: RegExp, message?: string };
145
+ match?: { re: RegExp, message?: string, template?: TemplateLiteral };
139
146
  /**
140
147
  * Minimum value configuration
141
148
  */
@@ -1,5 +1,8 @@
1
1
  import ts from 'typescript';
2
- import { type AnyType, DeclarationUtil, DecoratorUtil, DocUtil, ParamDocumentation, TransformerState } from '@travetto/transformer';
2
+ import {
3
+ type AnyType, DeclarationUtil, LiteralUtil,
4
+ DecoratorUtil, DocUtil, ParamDocumentation, TransformerState
5
+ } from '@travetto/transformer';
3
6
 
4
7
  const SCHEMA_MOD = '@travetto/schema/src/decorator/schema';
5
8
  const FIELD_MOD = '@travetto/schema/src/decorator/field';
@@ -15,6 +18,7 @@ export class SchemaTransformUtil {
15
18
  case 'pointer': return this.toConcreteType(state, type.target, node, root);
16
19
  case 'managed': return state.getOrImport(type);
17
20
  case 'tuple': return state.fromLiteral(type.subTypes.map(x => this.toConcreteType(state, x, node, root)!));
21
+ case 'template': return state.createIdentifier(type.ctor.name);
18
22
  case 'literal': {
19
23
  if ((type.ctor === Array) && type.typeArguments?.length) {
20
24
  return state.fromLiteral([this.toConcreteType(state, type.typeArguments[0], node, root)]);
@@ -108,18 +112,28 @@ export class SchemaTransformUtil {
108
112
  ));
109
113
  }
110
114
 
115
+ const primaryExpr = typeExpr.key === 'literal' && typeExpr.typeArguments?.[0] ? typeExpr.typeArguments[0] : typeExpr;
116
+
117
+ // We need to ensure we aren't being tripped up by the wrapper for arrays, sets, etc.
111
118
  // If we have a union type
112
- if (typeExpr.key === 'union') {
113
- const values = typeExpr.subTypes.map(x => x.key === 'literal' ? x.value : undefined)
119
+ if (primaryExpr.key === 'union') {
120
+ const values = primaryExpr.subTypes.map(x => x.key === 'literal' ? x.value : undefined)
114
121
  .filter(x => x !== undefined && x !== null)
115
122
  .sort();
116
123
 
117
- if (values.length === typeExpr.subTypes.length) {
124
+ if (values.length === primaryExpr.subTypes.length) {
118
125
  attrs.push(state.factory.createPropertyAssignment('enum', state.fromLiteral({
119
126
  values,
120
127
  message: `{path} is only allowed to be "${values.join('" or "')}"`
121
128
  })));
122
129
  }
130
+ } else if (primaryExpr.key === 'template' && primaryExpr.template) {
131
+ const re = LiteralUtil.templateLiteralToRegex(primaryExpr.template);
132
+ attrs.push(state.factory.createPropertyAssignment('match', state.fromLiteral({
133
+ re: new RegExp(re),
134
+ template: primaryExpr.template,
135
+ message: `{path} must match "${re}"`
136
+ })));
123
137
  }
124
138
 
125
139
  if (ts.isParameter(node)) {
@@ -212,6 +226,7 @@ export class SchemaTransformUtil {
212
226
  switch (type?.key) {
213
227
  case 'managed': out.type = state.typeToIdentifier(type); break;
214
228
  case 'shape': out.type = this.toConcreteType(state, type, target); break;
229
+ case 'template': out.type = state.factory.createIdentifier(type.ctor.name); break;
215
230
  case 'literal': {
216
231
  if (type.ctor) {
217
232
  out.type = out.array ?