@travetto/schema 7.0.0-rc.4 → 7.0.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
@@ -64,7 +64,7 @@ User:
64
64
 
65
65
  ### Fields
66
66
  This schema provides a powerful base for data binding and validation at runtime. Additionally there may be types that cannot be detected, or some information that the programmer would like to override. Below are the supported field decorators:
67
- * [@Field](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L23) defines a field that will be serialized.
67
+ * [@Field](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L24) defines a field that will be serialized.
68
68
  * [@Required](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L49) defines a that field should be required
69
69
  * [@Enum](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L58) defines the allowable values that a field can have
70
70
  * [@Match](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L84) defines a regular expression that the field value should match
@@ -81,9 +81,9 @@ This schema provides a powerful base for data binding and validation at runtime.
81
81
  * [@Currency](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L187) provides support for standard currency
82
82
  * [@Text](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L68) indicates that a field is expecting natural language input, not just discrete values
83
83
  * [@LongText](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L75) same as text, but expects longer form content
84
- * [@Readonly](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L39) defines a that field should not be bindable external to the class
85
- * [@Writeonly](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L32) defines a that field should not be exported in serialization, but that it can be bound to
86
- * [@Secret](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L47) marks a field as being sensitive. This is used by certain logging activities to ensure sensitive information is not logged out.
84
+ * [@Readonly](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L40) defines a that field should not be bindable external to the class
85
+ * [@Writeonly](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L33) defines a that field should not be exported in serialization, but that it can be bound to
86
+ * [@Secret](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L48) marks a field as being sensitive. This is used by certain logging activities to ensure sensitive information is not logged out.
87
87
  * [@Specifier](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L195) attributes additional specifiers to a field, allowing for more specification beyond just the field's type.
88
88
  * [@DiscriminatorField](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L202) allows for promoting a given field as the owner of the sub type discriminator.
89
89
 
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@travetto/schema",
3
- "version": "7.0.0-rc.4",
3
+ "version": "7.0.0",
4
+ "type": "module",
4
5
  "description": "Data type registry for runtime validation, reflection and binding.",
5
6
  "keywords": [
6
7
  "schema",
@@ -27,10 +28,10 @@
27
28
  "directory": "module/schema"
28
29
  },
29
30
  "dependencies": {
30
- "@travetto/registry": "^7.0.0-rc.4"
31
+ "@travetto/registry": "^7.0.0"
31
32
  },
32
33
  "peerDependencies": {
33
- "@travetto/transformer": "^7.0.0-rc.3"
34
+ "@travetto/transformer": "^7.0.0"
34
35
  },
35
36
  "peerDependenciesMeta": {
36
37
  "@travetto/transformer": {
@@ -18,10 +18,11 @@ function field<V>(...configs: Partial<SchemaFieldConfig>[]): PropType<V> {
18
18
  * @param type The type for the field
19
19
  * @param configs The field configuration
20
20
  * @augments `@travetto/schema:Input`
21
+ * @augments `@travetto/schema:Field`
21
22
  * @kind decorator
22
23
  */
23
- export function Field(type: Pick<SchemaFieldConfig, 'type' | 'array'>, ...configs: Partial<SchemaFieldConfig>[]): PropType<unknown> {
24
- return field(type, ...configs);
24
+ export function Field(type?: Pick<SchemaFieldConfig, 'type' | 'array'>, ...configs: Partial<SchemaFieldConfig>[]): PropType<unknown> {
25
+ return field(type!, ...configs);
25
26
  }
26
27
 
27
28
  /**
@@ -34,17 +34,19 @@ function combineCore<T extends SchemaCoreConfig>(base: T, config: Partial<T>): T
34
34
 
35
35
  function combineInputs<T extends SchemaInputConfig>(base: T, configs: Partial<T>[]): T {
36
36
  for (const config of configs) {
37
- safeAssign(base, {
38
- ...config,
39
- ...config.aliases ? { aliases: [...base.aliases ?? [], ...config.aliases ?? []] } : {},
40
- ...config.specifiers ? { specifiers: [...base.specifiers ?? [], ...config.specifiers ?? []] } : {},
41
- ...config.enum ? {
42
- enum: {
43
- message: config.enum?.message ?? base.enum?.message,
44
- values: (config.enum?.values ?? base.enum?.values ?? []).toSorted()
45
- }
46
- } : {},
47
- });
37
+ if (config) {
38
+ safeAssign(base, {
39
+ ...config,
40
+ ...config.aliases ? { aliases: [...base.aliases ?? [], ...config.aliases ?? []] } : {},
41
+ ...config.specifiers ? { specifiers: [...base.specifiers ?? [], ...config.specifiers ?? []] } : {},
42
+ ...config.enum ? {
43
+ enum: {
44
+ message: config.enum?.message ?? base.enum?.message,
45
+ values: (config.enum?.values ?? base.enum?.values ?? []).toSorted()
46
+ }
47
+ } : {},
48
+ });
49
+ }
48
50
  combineCore(base, config);
49
51
  }
50
52
  return base;
@@ -214,19 +214,19 @@ class ${uniqueId} extends ${type.mappedClassName} {
214
214
  params.push(state.fromLiteral(attrs));
215
215
  }
216
216
 
217
- if (!existing) {
218
- const resolved = this.toConcreteType(state, typeExpr, node, config?.root ?? node);
219
- const type = typeExpr.key === 'foreign' ? state.getConcreteType(node) :
220
- ts.isArrayLiteralExpression(resolved) ? resolved.elements[0] : resolved;
221
-
222
- params.unshift(LiteralUtil.fromLiteral(state.factory, {
223
- array: ts.isArrayLiteralExpression(resolved),
224
- type
225
- }));
226
- } else {
217
+ const resolved = this.toConcreteType(state, typeExpr, node, config?.root ?? node);
218
+ const type = typeExpr.key === 'foreign' ? state.getConcreteType(node) :
219
+ ts.isArrayLiteralExpression(resolved) ? resolved.elements[0] : resolved;
220
+
221
+ params.unshift(LiteralUtil.fromLiteral(state.factory, {
222
+ array: ts.isArrayLiteralExpression(resolved),
223
+ type
224
+ }));
225
+
226
+ if (existing) {
227
227
  const args = DecoratorUtil.getArguments(existing) ?? [];
228
228
  if (args.length > 0) {
229
- params.unshift(args[0]);
229
+ params[0] = args[0]; // Overwrite
230
230
  }
231
231
  if (args.length > 1) {
232
232
  params.push(...args.slice(1));
@@ -2,18 +2,20 @@ import ts from 'typescript';
2
2
 
3
3
  import {
4
4
  TransformerState, OnProperty, OnClass, AfterClass, DocUtil, DeclarationUtil,
5
- OnGetter, OnSetter, OnMethod, DecoratorUtil, OnStaticMethod
5
+ OnGetter, OnSetter, OnMethod, DecoratorUtil, OnStaticMethod, type DecoratorMeta
6
6
  } from '@travetto/transformer';
7
7
 
8
8
  import { SchemaTransformUtil } from './transformer/util.ts';
9
9
 
10
10
  const CONSTRUCTOR_PROPERTY = 'CONSTRUCTOR';
11
- const InSchemaSymbol = Symbol();
11
+ const InSchema = Symbol();
12
+ const IsOptIn = Symbol();
12
13
  const AccessorsSymbol = Symbol();
13
14
  const AutoEnrollMethods = Symbol();
14
15
 
15
16
  interface AutoState {
16
- [InSchemaSymbol]?: boolean;
17
+ [InSchema]?: boolean;
18
+ [IsOptIn]?: boolean;
17
19
  [AutoEnrollMethods]?: Set<string>;
18
20
  [AccessorsSymbol]?: Set<string>;
19
21
  }
@@ -23,7 +25,11 @@ interface AutoState {
23
25
  */
24
26
  export class SchemaTransformer {
25
27
 
26
- static isInvisible(state: AutoState & TransformerState, node: ts.Declaration): boolean {
28
+ static isInvisible(state: AutoState & TransformerState, node: ts.Declaration, isStatic?: boolean): boolean {
29
+ if (!state[InSchema] && !isStatic) {
30
+ return true;
31
+ }
32
+
27
33
  const ignore = state.findDecorator(this, node, 'Ignore');
28
34
  if (ignore) {
29
35
  return true;
@@ -31,6 +37,7 @@ export class SchemaTransformer {
31
37
 
32
38
  const manuallyOpted = !!(
33
39
  state.findDecorator(this, node, 'Input') ??
40
+ state.findDecorator(this, node, 'Field') ??
34
41
  state.findDecorator(this, node, 'Method')
35
42
  );
36
43
  if (manuallyOpted) {
@@ -41,7 +48,7 @@ export class SchemaTransformer {
41
48
  return true;
42
49
  }
43
50
  }
44
- if (!state[InSchemaSymbol] || !DeclarationUtil.isPublic(node)) {
51
+ if (state[IsOptIn] || !DeclarationUtil.isPublic(node)) {
45
52
  return true;
46
53
  }
47
54
  return false;
@@ -52,15 +59,17 @@ export class SchemaTransformer {
52
59
  */
53
60
  @OnClass('Schema')
54
61
  static startSchema(state: AutoState & TransformerState, node: ts.ClassDeclaration): ts.ClassDeclaration {
55
- state[InSchemaSymbol] = true;
56
62
  state[AccessorsSymbol] = new Set();
57
63
  state[AutoEnrollMethods] = new Set();
64
+ state[InSchema] = true;
58
65
 
59
66
  // Determine auto enrol methods
60
67
  for (const item of state.getDecoratorList(node)) {
61
68
  if (item.targets?.includes('@travetto/schema:Schema')) {
62
- for (const option of item.options ?? []) {
63
- state[AutoEnrollMethods].add(option);
69
+ state[IsOptIn] ||= item.options?.includes('opt-in') ?? false;
70
+ const methodEnrolls = item.options?.filter(item => item.startsWith('method:'))?.map(item => item.replace('method:', '')) ?? [];
71
+ for (const method of methodEnrolls) {
72
+ state[AutoEnrollMethods].add(method);
64
73
  }
65
74
  }
66
75
  }
@@ -117,8 +126,10 @@ export class SchemaTransformer {
117
126
  params = [...params, state.fromLiteral(attrs)];
118
127
  }
119
128
 
120
- delete state[InSchemaSymbol];
129
+ delete state[InSchema];
130
+ delete state[IsOptIn];
121
131
  delete state[AccessorsSymbol];
132
+ delete state[AutoEnrollMethods];
122
133
 
123
134
  return state.factory.updateClassDeclaration(
124
135
  node,
@@ -138,7 +149,9 @@ export class SchemaTransformer {
138
149
  @OnMethod()
139
150
  @OnStaticMethod()
140
151
  static processSchemaMethod(state: TransformerState & AutoState, node: ts.MethodDeclaration): ts.MethodDeclaration {
141
- if (this.isInvisible(state, node) && !state[AutoEnrollMethods]?.has(node.name.getText())) {
152
+ if (
153
+ this.isInvisible(state, node, node.modifiers?.some(m => m.kind === ts.SyntaxKind.StaticKeyword)) &&
154
+ !state[AutoEnrollMethods]?.has(node.name.getText())) {
142
155
  return node;
143
156
  }
144
157