@travetto/schema 6.0.1 → 7.0.0-rc.1

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.
@@ -4,10 +4,14 @@ import {
4
4
  DecoratorUtil, DocUtil, ParamDocumentation, TransformerState, transformCast,
5
5
  } from '@travetto/transformer';
6
6
 
7
+ export type ComputeConfig = { type?: AnyType, root?: ts.Node, name?: string, index?: number };
8
+
7
9
  export class SchemaTransformUtil {
8
10
 
9
11
  static SCHEMA_IMPORT = '@travetto/schema/src/decorator/schema.ts';
12
+ static METHOD_IMPORT = '@travetto/schema/src/decorator/method.ts';
10
13
  static FIELD_IMPORT = '@travetto/schema/src/decorator/field.ts';
14
+ static INPUT_IMPORT = '@travetto/schema/src/decorator/input.ts';
11
15
  static COMMON_IMPORT = '@travetto/schema/src/decorator/common.ts';
12
16
  static TYPES_IMPORT = '@travetto/schema/src/types.ts';
13
17
 
@@ -28,6 +32,32 @@ export class SchemaTransformUtil {
28
32
  }
29
33
  break;
30
34
  }
35
+ case 'mapped': {
36
+ const base = state.getOrImport(type);
37
+ const uniqueId = state.generateUniqueIdentifier(node, type, 'Δ');
38
+ const [id, existing] = state.registerIdentifier(uniqueId);
39
+ if (!existing) {
40
+ const cls = state.factory.createClassDeclaration(
41
+ [
42
+ state.createDecorator(this.SCHEMA_IMPORT, 'Schema', state.fromLiteral({
43
+ description: type.comment,
44
+ mappedOperation: type.operation,
45
+ mappedFields: type.fields,
46
+ })),
47
+ ],
48
+ id, [], [state.factory.createHeritageClause(
49
+ ts.SyntaxKind.ExtendsKeyword, [state.factory.createExpressionWithTypeArguments(base, [])]
50
+ )], []
51
+ );
52
+ cls.getText = (): string => `
53
+ class ${uniqueId} extends ${type.mappedClassName} {
54
+ fields: ${type.fields?.join(', ')}
55
+ operation: ${type.operation}
56
+ }`;
57
+ state.addStatements([cls], root || node);
58
+ }
59
+ return id;
60
+ }
31
61
  case 'unknown': {
32
62
  const imp = state.importFile(this.TYPES_IMPORT);
33
63
  return state.createAccess(imp.ident, 'UnknownType');
@@ -40,18 +70,14 @@ export class SchemaTransformUtil {
40
70
  if (!existing) {
41
71
  const cls = state.factory.createClassDeclaration(
42
72
  [
43
- state.createDecorator(this.SCHEMA_IMPORT, 'Schema'),
44
- state.createDecorator(this.COMMON_IMPORT, 'Describe',
45
- state.fromLiteral({
46
- title: type.name,
47
- description: type.comment
48
- })
49
- )
73
+ state.createDecorator(this.SCHEMA_IMPORT, 'Schema', state.fromLiteral({
74
+ description: type.comment
75
+ })),
50
76
  ],
51
77
  id, [], [],
52
78
  Object.entries(type.fieldTypes)
53
79
  .map(([k, v]) =>
54
- this.computeField(state, state.factory.createPropertyDeclaration(
80
+ this.computeInput(state, state.factory.createPropertyDeclaration(
55
81
  [], /\W/.test(k) ? state.factory.createComputedPropertyName(state.fromLiteral(k)) : k,
56
82
  v.undefinable || v.nullable ? state.factory.createToken(ts.SyntaxKind.QuestionToken) : undefined,
57
83
  v.key === 'unknown' ? state.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword) : undefined, undefined
@@ -83,45 +109,50 @@ export class SchemaTransformUtil {
83
109
  }
84
110
 
85
111
  /**
86
- * Compute property information from declaration
112
+ * Compute decorator params from property/parameter/getter/setter
87
113
  */
88
- static computeField<T extends ts.PropertyDeclaration | ts.ParameterDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration>(
89
- state: TransformerState, node: T, config: { type?: AnyType, root?: ts.Node, name?: string } = { root: node }
90
- ): T {
91
-
92
- const typeExpr = config.type ?? state.resolveType(ts.isSetAccessor(node) ? node.parameters[0] : node);
93
- const attrs: ts.PropertyAssignment[] = [];
114
+ static computeInputDecoratorParams<T extends ts.PropertyDeclaration | ts.ParameterDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration>(
115
+ state: TransformerState,
116
+ node: T,
117
+ config?: ComputeConfig
118
+ ): ts.Expression[] {
119
+ const typeExpr = config?.type ?? state.resolveType(ts.isSetAccessor(node) ? node.parameters[0] : node);
120
+ const attrs: Record<string, string | boolean | object | number | ts.Expression> = {};
94
121
 
95
122
  if (!ts.isGetAccessorDeclaration(node) && !ts.isSetAccessorDeclaration(node)) {
96
123
  // eslint-disable-next-line no-bitwise
97
124
  if ((ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Readonly) > 0) {
98
- attrs.push(state.factory.createPropertyAssignment('access', state.fromLiteral('readonly')));
99
- } else if (!node.questionToken && !typeExpr.undefinable && !node.initializer) {
100
- attrs.push(state.factory.createPropertyAssignment('required', state.fromLiteral({ active: true })));
125
+ attrs.access = 'readonly';
126
+ } else if (!!node.questionToken || !!typeExpr.undefinable || !!node.initializer) {
127
+ attrs.required = { active: false };
101
128
  }
102
- if (node.initializer && (
129
+ if (node.initializer !== undefined && (
103
130
  ts.isLiteralExpression(node.initializer) ||
131
+ node.initializer.kind === ts.SyntaxKind.TrueKeyword ||
132
+ node.initializer.kind === ts.SyntaxKind.FalseKeyword ||
104
133
  (ts.isArrayLiteralExpression(node.initializer) && node.initializer.elements.length === 0)
105
134
  )) {
106
- attrs.push(state.factory.createPropertyAssignment('default', node.initializer));
135
+ attrs.default = node.initializer;
107
136
  }
108
137
  } else {
109
138
  const acc = DeclarationUtil.getAccessorPair(node);
110
- attrs.push(state.factory.createPropertyAssignment('accessor', state.fromLiteral(true)));
139
+ attrs.accessor = true;
111
140
  if (!acc.setter) {
112
- attrs.push(state.factory.createPropertyAssignment('access', state.fromLiteral('readonly')));
141
+ attrs.access = 'readonly';
113
142
  }
114
143
  if (!acc.getter) {
115
- attrs.push(state.factory.createPropertyAssignment('access', state.fromLiteral('writeonly')));
116
- } else if (!typeExpr.undefinable) {
117
- attrs.push(state.factory.createPropertyAssignment('required', state.fromLiteral({ active: true })));
144
+ attrs.access = 'writeonly';
145
+ } else if (!!typeExpr.undefinable) {
146
+ attrs.required = { active: false };
118
147
  }
119
148
  }
120
149
 
121
- if (ts.isParameter(node) || config.name !== undefined) {
122
- attrs.push(state.factory.createPropertyAssignment('name', state.factory.createStringLiteral(
123
- config.name !== undefined ? config.name : node.name.getText())
124
- ));
150
+ const rawName = node.getSourceFile()?.text ? node.name.getText() ?? undefined : undefined;
151
+ const providedName = config?.name ?? rawName!;
152
+ attrs.name = providedName;
153
+
154
+ if (rawName !== providedName && rawName) {
155
+ attrs.sourceText = rawName;
125
156
  }
126
157
 
127
158
  const primaryExpr = typeExpr.key === 'literal' && typeExpr.typeArguments?.[0] ? typeExpr.typeArguments[0] : typeExpr;
@@ -133,79 +164,107 @@ export class SchemaTransformUtil {
133
164
  .filter(x => x !== undefined && x !== null);
134
165
 
135
166
  if (values.length === primaryExpr.subTypes.length) {
136
- attrs.push(state.factory.createPropertyAssignment('enum', state.fromLiteral({
167
+ attrs.enum = {
137
168
  values,
138
169
  message: `{path} is only allowed to be "${values.join('" or "')}"`
139
- })));
170
+ };
140
171
  }
141
172
  } else if (primaryExpr.key === 'template' && primaryExpr.template) {
142
173
  const re = LiteralUtil.templateLiteralToRegex(primaryExpr.template);
143
- attrs.push(state.factory.createPropertyAssignment('match', state.fromLiteral({
174
+ attrs.match = {
144
175
  re: new RegExp(re),
145
176
  template: primaryExpr.template,
146
177
  message: `{path} must match "${re}"`
147
- })));
178
+ };
148
179
  }
149
180
 
150
181
  if (ts.isParameter(node)) {
151
- const comments = DocUtil.describeDocs(node.parent);
152
- const commentConfig: Partial<ParamDocumentation> = (comments.params ?? []).find(x => x.name === node.name.getText()) || {};
153
- if (commentConfig.description) {
154
- attrs.push(state.factory.createPropertyAssignment('description', state.fromLiteral(commentConfig.description)));
182
+ const parentComments = DocUtil.describeDocs(node.parent);
183
+ const paramComments: Partial<ParamDocumentation> = (parentComments.params ?? []).find(x => x.name === node.name.getText()) || {};
184
+ if (paramComments.description) {
185
+ attrs.description = paramComments.description;
186
+ }
187
+ } else {
188
+ const comments = DocUtil.describeDocs(node);
189
+ if (comments.description) {
190
+ attrs.description = comments.description;
155
191
  }
156
192
  }
157
193
 
158
194
  const tags = ts.getJSDocTags(node);
159
195
  const aliases = tags.filter(x => x.tagName.getText() === 'alias');
160
196
  if (aliases.length) {
161
- attrs.push(state.factory.createPropertyAssignment('aliases', state.fromLiteral(aliases.map(x => x.comment).filter(x => !!x))));
197
+ attrs.aliases = aliases.map(x => x.comment).filter(x => !!x);
162
198
  }
163
199
 
164
200
  const params: ts.Expression[] = [];
165
201
 
166
- const existing = state.findDecorator('@travetto/schema', node, 'Field', this.FIELD_IMPORT);
202
+ const existing =
203
+ state.findDecorator('@travetto/schema', node, 'Field', this.FIELD_IMPORT) ??
204
+ state.findDecorator('@travetto/schema', node, 'Input', this.INPUT_IMPORT);
205
+
206
+ if (config?.index !== undefined) {
207
+ attrs.index = config.index;
208
+ }
209
+
210
+ if (Object.keys(attrs).length) {
211
+ params.push(state.fromLiteral(attrs));
212
+ }
213
+
167
214
  if (!existing) {
168
- const resolved = this.toConcreteType(state, typeExpr, node, config.root);
169
- params.push(resolved);
170
- if (attrs.length) {
171
- params.push(state.factory.createObjectLiteralExpression(attrs));
172
- }
215
+ const resolved = this.toConcreteType(state, typeExpr, node, config?.root ?? node);
216
+ const type = typeExpr.key === 'foreign' ? state.getConcreteType(node) :
217
+ ts.isArrayLiteralExpression(resolved) ? resolved.elements[0] : resolved;
218
+
219
+ params.unshift(LiteralUtil.fromLiteral(state.factory, {
220
+ array: ts.isArrayLiteralExpression(resolved),
221
+ type
222
+ }));
173
223
  } else {
174
224
  const args = DecoratorUtil.getArguments(existing) ?? [];
175
225
  if (args.length > 0) {
176
- params.push(args[0]);
226
+ params.unshift(args[0]);
177
227
  }
178
- params.push(state.factory.createObjectLiteralExpression(attrs));
179
228
  if (args.length > 1) {
180
229
  params.push(...args.slice(1));
181
230
  }
182
231
  }
183
232
 
184
- const newModifiers = [
185
- ...(node.modifiers ?? []).filter(x => x !== existing),
186
- state.createDecorator(this.FIELD_IMPORT, 'Field', ...params)
187
- ];
233
+ return params;
234
+ }
235
+
236
+ /**
237
+ * Compute property information from declaration
238
+ */
239
+ static computeInput<T extends ts.PropertyDeclaration | ts.ParameterDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration>(
240
+ state: TransformerState, node: T, config?: ComputeConfig
241
+ ): T {
242
+ const existingField = state.findDecorator('@travetto/schema', node, 'Field', this.FIELD_IMPORT);
243
+ const existingInput = state.findDecorator('@travetto/schema', node, 'Input', this.INPUT_IMPORT);
244
+ const decParams = this.computeInputDecoratorParams(state, node, config);
245
+
246
+ let modifiers: ts.ModifierLike[];
247
+ if (existingField) {
248
+ const dec = state.createDecorator(this.FIELD_IMPORT, 'Field', ...decParams);
249
+ modifiers = DecoratorUtil.spliceDecorators(node, existingField, [dec]);
250
+ } else {
251
+ const dec = state.createDecorator(this.INPUT_IMPORT, 'Input', ...decParams);
252
+ modifiers = DecoratorUtil.spliceDecorators(node, existingInput, [dec]);
253
+ }
188
254
 
189
255
  let result: unknown;
190
256
  if (ts.isPropertyDeclaration(node)) {
191
- const comments = DocUtil.describeDocs(node);
192
- if (comments.description) {
193
- newModifiers.push(state.createDecorator(this.COMMON_IMPORT, 'Describe', state.fromLiteral({
194
- description: comments.description
195
- })));
196
- }
197
-
198
257
  result = state.factory.updatePropertyDeclaration(node,
199
- newModifiers, node.name, node.questionToken, node.type, node.initializer);
258
+ modifiers, node.name, node.questionToken, node.type, node.initializer);
200
259
  } else if (ts.isParameter(node)) {
201
260
  result = state.factory.updateParameterDeclaration(node,
202
- newModifiers, node.dotDotDotToken, node.name, node.questionToken, node.type, node.initializer);
261
+ modifiers, node.dotDotDotToken, node.name, node.questionToken, node.type, node.initializer);
203
262
  } else if (ts.isGetAccessorDeclaration(node)) {
204
263
  result = state.factory.updateGetAccessorDeclaration(node,
205
- newModifiers, node.name, node.parameters, node.type, node.body);
264
+ modifiers, node.name, node.parameters, node.type, node.body);
206
265
  } else {
207
266
  result = state.factory.updateSetAccessorDeclaration(node,
208
- newModifiers, node.name, node.parameters, node.body);
267
+ modifiers, node.name, node.parameters, node.body);
209
268
  }
210
269
  return transformCast(result);
211
270
  }
@@ -233,7 +292,12 @@ export class SchemaTransformUtil {
233
292
  static ensureType(state: TransformerState, anyType: AnyType, target: ts.Node): Record<string, unknown> {
234
293
  const { out, type } = this.unwrapType(anyType);
235
294
  switch (type?.key) {
295
+ case 'foreign': {
296
+ out.type = state.getForeignTarget(type);
297
+ break;
298
+ }
236
299
  case 'managed': out.type = state.typeToIdentifier(type); break;
300
+ case 'mapped': out.type = this.toConcreteType(state, type, target); break;
237
301
  case 'shape': out.type = this.toConcreteType(state, type, target); break;
238
302
  case 'template': out.type = state.factory.createIdentifier(type.ctor.name); break;
239
303
  case 'literal': {
@@ -270,4 +334,26 @@ export class SchemaTransformUtil {
270
334
  return state.findMethodByName(cls, methodName);
271
335
  }
272
336
  }
337
+
338
+ /**
339
+ * Compute return type decorator params
340
+ */
341
+ static computeReturnTypeDecoratorParams(state: TransformerState, node: ts.MethodDeclaration): ts.Expression[] {
342
+ // If we have a valid response type, declare it
343
+ const returnType = state.resolveReturnType(node);
344
+ let targetType = returnType;
345
+
346
+ if (returnType.key === 'literal' && returnType.typeArguments?.length && returnType.name === 'Promise') {
347
+ targetType = returnType.typeArguments[0];
348
+ }
349
+
350
+ // TODO: Standardize this using jsdoc
351
+ let innerReturnType: AnyType | undefined;
352
+ if (targetType.key === 'managed' && targetType.importName.startsWith('@travetto/')) {
353
+ innerReturnType = state.getApparentTypeOfField(targetType.original!, 'body');
354
+ }
355
+
356
+ const finalReturnType = SchemaTransformUtil.ensureType(state, innerReturnType ?? returnType, node);
357
+ return finalReturnType ? [state.fromLiteral({ returnType: finalReturnType })] : [];
358
+ }
273
359
  }
@@ -1,17 +1,20 @@
1
1
  import ts from 'typescript';
2
2
 
3
3
  import {
4
- TransformerState, OnProperty, OnClass, AfterClass, DocUtil, DeclarationUtil, OnGetter, OnSetter,
5
- DecoratorUtil
4
+ TransformerState, OnProperty, OnClass, AfterClass, DocUtil, DeclarationUtil,
5
+ OnGetter, OnSetter, OnMethod, DecoratorUtil, OnStaticMethod
6
6
  } from '@travetto/transformer';
7
7
 
8
8
  import { SchemaTransformUtil } from './transformer/util.ts';
9
9
 
10
+ const CONSTRUCTOR_PROPERTY = 'CONSTRUCTOR';
10
11
  const InSchemaSymbol = Symbol();
11
12
  const AccessorsSymbol = Symbol();
13
+ const AutoEnrollMethods = Symbol();
12
14
 
13
15
  interface AutoState {
14
16
  [InSchemaSymbol]?: boolean;
17
+ [AutoEnrollMethods]?: Set<string>;
15
18
  [AccessorsSymbol]?: Set<string>;
16
19
  }
17
20
 
@@ -20,6 +23,30 @@ interface AutoState {
20
23
  */
21
24
  export class SchemaTransformer {
22
25
 
26
+ static isInvisible(state: AutoState & TransformerState, node: ts.Declaration): boolean {
27
+ const ignore = state.findDecorator(this, node, 'Ignore');
28
+ if (ignore) {
29
+ return true;
30
+ }
31
+
32
+ const manuallyOpted = !!(
33
+ state.findDecorator(this, node, 'Input') ??
34
+ state.findDecorator(this, node, 'Method')
35
+ );
36
+ if (manuallyOpted) {
37
+ return false;
38
+ }
39
+ if (ts.isMethodDeclaration(node)) {
40
+ if (!node.body || !state[AutoEnrollMethods]?.has(node.name.getText())) {
41
+ return true;
42
+ }
43
+ }
44
+ if (!state[InSchemaSymbol] || !DeclarationUtil.isPublic(node)) {
45
+ return true;
46
+ }
47
+ return false;
48
+ }
49
+
23
50
  /**
24
51
  * Track schema on start
25
52
  */
@@ -27,6 +54,17 @@ export class SchemaTransformer {
27
54
  static startSchema(state: AutoState & TransformerState, node: ts.ClassDeclaration): ts.ClassDeclaration {
28
55
  state[InSchemaSymbol] = true;
29
56
  state[AccessorsSymbol] = new Set();
57
+ state[AutoEnrollMethods] = new Set();
58
+
59
+ // Determine auto enrol methods
60
+ for (const item of state.getDecoratorList(node)) {
61
+ if (item.targets?.includes('@travetto/schema:Schema')) {
62
+ for (const opt of item.options ?? []) {
63
+ state[AutoEnrollMethods].add(opt);
64
+ }
65
+ }
66
+ }
67
+
30
68
  return node;
31
69
  }
32
70
 
@@ -35,56 +73,99 @@ export class SchemaTransformer {
35
73
  */
36
74
  @AfterClass('Schema')
37
75
  static finalizeSchema(state: AutoState & TransformerState, node: ts.ClassDeclaration): ts.ClassDeclaration {
38
- const modifiers = (node.modifiers ?? []).slice(0);
39
-
40
76
  const comments = DocUtil.describeDocs(node);
41
77
 
42
- if (!state.findDecorator(this, node, 'Schema', SchemaTransformUtil.SCHEMA_IMPORT)) {
43
- modifiers.unshift(state.createDecorator(SchemaTransformUtil.SCHEMA_IMPORT, 'Schema'));
44
- }
78
+ const existing = state.findDecorator(this, node, 'Schema', SchemaTransformUtil.SCHEMA_IMPORT);
79
+ const cons = node.members.find(x => ts.isConstructorDeclaration(x));
80
+
81
+ const attrs: Record<string, string | boolean | ts.Expression | number | object | unknown[]> = {};
45
82
 
46
83
  if (comments.description) {
47
- modifiers.push(state.createDecorator(SchemaTransformUtil.COMMON_IMPORT, 'Describe', state.fromLiteral({
48
- title: comments.description
49
- })));
84
+ attrs.description = comments.description;
85
+ }
86
+
87
+ // Extract all interfaces
88
+ const interfaces: ts.Node[] = [];
89
+ for (const clause of node.heritageClauses ?? []) {
90
+ if (clause.token === ts.SyntaxKind.ImplementsKeyword) {
91
+ for (const typeExpression of clause.types) {
92
+ const resolvedType = state.resolveType(typeExpression);
93
+ if (resolvedType.key === 'managed') {
94
+ const resolved = state.getOrImport(resolvedType);
95
+ interfaces.push(resolved);
96
+ }
97
+ }
98
+ }
99
+ }
100
+
101
+ if (interfaces.length > 0) {
102
+ attrs.interfaces = interfaces;
103
+ }
104
+
105
+ if (cons) {
106
+ attrs.methods = {
107
+ [CONSTRUCTOR_PROPERTY]: {
108
+ parameters: cons.parameters.map((p, i) => SchemaTransformUtil.computeInputDecoratorParams(state, p, { index: i })).map(x =>
109
+ state.extendObjectLiteral({}, ...x)
110
+ ),
111
+ }
112
+ };
113
+ }
114
+
115
+ let params = DecoratorUtil.getArguments(existing) ?? [];
116
+ if (Object.keys(attrs).length) {
117
+ params = [...params, state.fromLiteral(attrs)];
50
118
  }
51
119
 
52
120
  delete state[InSchemaSymbol];
53
121
  delete state[AccessorsSymbol];
54
- let members = node.members;
55
-
56
- const schemaMethods = [
57
- ...node.modifiers?.filter(x => ts.isDecorator(x))
58
- .flatMap(x => state.getDeclarations(DecoratorUtil.getDecoratorIdent(x))) ?? [],
59
- node
60
- ]
61
- .flatMap(v => state.readDocTagList(v, 'schemaMethods'));
62
-
63
- if (schemaMethods.length) {
64
- const methodSet = new Set(schemaMethods.flatMap(x => x.split(/\s*,\s*/g)));
65
- members = state.factory.createNodeArray(
66
- node.members.map(x => ts.isMethodDeclaration(x) && methodSet.has(x.name.getText()) ?
67
- state.factory.updateMethodDeclaration(
68
- x,
69
- x.modifiers,
70
- x.asteriskToken,
71
- x.name,
72
- x.questionToken,
73
- x.typeParameters,
74
- x.parameters.map(y => SchemaTransformUtil.computeField(state, y)),
75
- x.type,
76
- x.body
77
- ) : x)
78
- );
79
- }
80
122
 
81
123
  return state.factory.updateClassDeclaration(
82
124
  node,
83
- modifiers,
125
+ DecoratorUtil.spliceDecorators(node, existing, [
126
+ state.createDecorator(SchemaTransformUtil.SCHEMA_IMPORT, 'Schema', ...params)
127
+ ]),
84
128
  node.name,
85
129
  node.typeParameters,
86
130
  node.heritageClauses,
87
- members
131
+ node.members
132
+ );
133
+ }
134
+
135
+ /**
136
+ * Handle explicitly registered methods
137
+ */
138
+ @OnMethod()
139
+ @OnStaticMethod()
140
+ static processSchemaMethod(state: TransformerState & AutoState, node: ts.MethodDeclaration): ts.MethodDeclaration {
141
+ if (this.isInvisible(state, node) && !state[AutoEnrollMethods]?.has(node.name.getText())) {
142
+ return node;
143
+ }
144
+
145
+ const existing = state.findDecorator(this, node, 'Method', SchemaTransformUtil.METHOD_IMPORT);
146
+ const comments = DocUtil.describeDocs(node);
147
+ const params = DecoratorUtil.getArguments(existing) ?? [];
148
+
149
+ if (comments.description) {
150
+ params.unshift(state.fromLiteral({ description: comments.description }));
151
+ }
152
+ if (DeclarationUtil.isStatic(node)) {
153
+ params.push(state.fromLiteral({ isStatic: true }));
154
+ }
155
+ params.push(...SchemaTransformUtil.computeReturnTypeDecoratorParams(state, node));
156
+
157
+ return state.factory.updateMethodDeclaration(
158
+ node,
159
+ DecoratorUtil.spliceDecorators(node, existing, [
160
+ state.createDecorator(SchemaTransformUtil.METHOD_IMPORT, 'Method', ...params)
161
+ ]),
162
+ node.asteriskToken,
163
+ node.name,
164
+ node.questionToken,
165
+ node.typeParameters,
166
+ node.parameters.map((y, i) => SchemaTransformUtil.computeInput(state, y, { index: i })),
167
+ node.type,
168
+ node.body
88
169
  );
89
170
  }
90
171
 
@@ -93,9 +174,10 @@ export class SchemaTransformer {
93
174
  */
94
175
  @OnProperty()
95
176
  static processSchemaField(state: TransformerState & AutoState, node: ts.PropertyDeclaration): ts.PropertyDeclaration {
96
- const ignore = state.findDecorator(this, node, 'Ignore');
97
- return state[InSchemaSymbol] && !ignore && DeclarationUtil.isPublic(node) ?
98
- SchemaTransformUtil.computeField(state, node) : node;
177
+ if (this.isInvisible(state, node)) {
178
+ return node;
179
+ }
180
+ return SchemaTransformUtil.computeInput(state, node);
99
181
  }
100
182
 
101
183
  /**
@@ -103,12 +185,15 @@ export class SchemaTransformer {
103
185
  */
104
186
  @OnGetter()
105
187
  static processSchemaGetter(state: TransformerState & AutoState, node: ts.GetAccessorDeclaration): ts.GetAccessorDeclaration {
106
- const ignore = state.findDecorator(this, node, 'Ignore');
107
- if (state[InSchemaSymbol] && !ignore && DeclarationUtil.isPublic(node) && !state[AccessorsSymbol]?.has(node.name.getText())) {
188
+ if (this.isInvisible(state, node) || DeclarationUtil.isStatic(node)) {
189
+ return node;
190
+ }
191
+ if (state[AccessorsSymbol]?.has(node.name.getText())) {
192
+ return node;
193
+ } else {
108
194
  state[AccessorsSymbol]?.add(node.name.getText());
109
- return SchemaTransformUtil.computeField(state, node);
195
+ return SchemaTransformUtil.computeInput(state, node);
110
196
  }
111
- return node;
112
197
  }
113
198
 
114
199
  /**
@@ -116,11 +201,14 @@ export class SchemaTransformer {
116
201
  */
117
202
  @OnSetter()
118
203
  static processSchemaSetter(state: TransformerState & AutoState, node: ts.SetAccessorDeclaration): ts.SetAccessorDeclaration {
119
- const ignore = state.findDecorator(this, node, 'Ignore');
120
- if (state[InSchemaSymbol] && !ignore && DeclarationUtil.isPublic(node) && !state[AccessorsSymbol]?.has(node.name.getText())) {
204
+ if (this.isInvisible(state, node) || DeclarationUtil.isStatic(node)) {
205
+ return node;
206
+ }
207
+ if (state[AccessorsSymbol]?.has(node.name.getText())) {
208
+ return node;
209
+ } else {
121
210
  state[AccessorsSymbol]?.add(node.name.getText());
122
- return SchemaTransformUtil.computeField(state, node);
211
+ return SchemaTransformUtil.computeInput(state, node);
123
212
  }
124
- return node;
125
213
  }
126
214
  }