@hadss/turbo-trans-json-plugin 1.0.0-rc.1 → 1.0.0-rc.2

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.
Files changed (76) hide show
  1. package/dist/core/analyzers/ClassAnalyzer.d.ts +15 -0
  2. package/dist/core/analyzers/ClassAnalyzer.js +193 -144
  3. package/dist/core/analyzers/CustomTypeAnalyzer.d.ts +3 -0
  4. package/dist/core/analyzers/CustomTypeAnalyzer.js +65 -60
  5. package/dist/core/constants/DecoratorConstants.js +2 -1
  6. package/dist/core/import-rewrite/services/BuildProfileUpdater.js +1 -1
  7. package/dist/core/import-rewrite/services/ImportRewriteService.js +1 -1
  8. package/dist/core/interfaces/index.d.ts +2 -2
  9. package/dist/core/services/CodeAnalysisService.js +2 -1
  10. package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.d.ts +2 -0
  11. package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.js +22 -15
  12. package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.d.ts +22 -0
  13. package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.js +194 -129
  14. package/dist/core/services/CodeGenerationService/generators/SerializerGenerator.js +1 -1
  15. package/dist/core/services/CodeGenerationService/generators/TempSerializerGenerator.js +2 -1
  16. package/dist/core/services/CodeGenerationService/shared/ImportManager.d.ts +2 -2
  17. package/dist/core/template/HandlebarsTemplateEngine.d.ts +2 -0
  18. package/dist/core/template/HandlebarsTemplateEngine.js +21 -2
  19. package/dist/core/utils/DeepCopyUtil.js +1 -1
  20. package/dist/core/utils/SerializationPathUtil.d.ts +1 -1
  21. package/dist/core/utils/TsMorphUtil.js +2 -1
  22. package/dist/json-plugin/JSONExecuteController.d.ts +4 -0
  23. package/dist/json-plugin/JSONExecuteController.js +46 -36
  24. package/dist/json-plugin/interfaces/impl/TargetContext.js +4 -2
  25. package/dist/json-plugin/tasks/BaseTask.d.ts +2 -2
  26. package/dist/json-plugin/tasks/WatchTask.js +2 -1
  27. package/package.json +1 -1
  28. package/src/core/Types.ts +90 -90
  29. package/src/core/analyzers/ClassAnalyzer.ts +335 -230
  30. package/src/core/analyzers/CustomTypeAnalyzer.ts +145 -73
  31. package/src/core/constants/DecoratorConstants.ts +7 -6
  32. package/src/core/constants/PathConstants.ts +7 -7
  33. package/src/core/constants/StringConstants.ts +95 -95
  34. package/src/core/handlers/BaseTypeHandler.ts +11 -2
  35. package/src/core/handlers/CustomClassHandler.ts +4 -4
  36. package/src/core/handlers/DateHandler.ts +54 -46
  37. package/src/core/handlers/DecimalHandler.ts +53 -45
  38. package/src/core/handlers/EnumHandler.ts +2 -1
  39. package/src/core/handlers/GenericContainerHandler.ts +3 -1
  40. package/src/core/handlers/TupleHandler.ts +2 -1
  41. package/src/core/handlers/TypeHandlerRegistry.ts +2 -1
  42. package/src/core/handlers/UnionTypeHandler.ts +8 -7
  43. package/src/core/import-rewrite/services/BuildProfileUpdater.ts +6 -4
  44. package/src/core/import-rewrite/services/ImportRewriteService.ts +1 -1
  45. package/src/core/import-rewrite/services/ImportTransformService.ts +2 -2
  46. package/src/core/import-rewrite/types/ImportRewriteTypes.ts +3 -3
  47. package/src/core/index.ts +4 -4
  48. package/src/core/interfaces/ITask.ts +6 -5
  49. package/src/core/interfaces/ITaskContext.ts +9 -9
  50. package/src/core/interfaces/index.ts +2 -2
  51. package/src/core/logger/Logger.ts +28 -28
  52. package/src/core/services/CodeAnalysisService.ts +2 -1
  53. package/src/core/services/CodeGenerationEngine.ts +42 -42
  54. package/src/core/services/CodeGenerationService/generators/OriginalClassGenerator.ts +25 -22
  55. package/src/core/services/CodeGenerationService/generators/SendableClassGenerator.ts +261 -170
  56. package/src/core/services/CodeGenerationService/generators/SerializerGenerator.ts +1 -1
  57. package/src/core/services/CodeGenerationService/generators/TempSerializerGenerator.ts +5 -3
  58. package/src/core/services/CodeGenerationService/shared/ImportManager.ts +8 -8
  59. package/src/core/template/HandlebarsTemplateEngine.ts +39 -11
  60. package/src/core/utils/ConfigManager.ts +2 -1
  61. package/src/core/utils/DeepCopyUtil.ts +1 -1
  62. package/src/core/utils/GenericTypeSubstitutionUtil.ts +1 -8
  63. package/src/core/utils/SerializationPathUtil.ts +7 -6
  64. package/src/core/utils/TsMorphUtil.ts +4 -1
  65. package/src/index.ts +2 -2
  66. package/src/json-plugin/JSONExecuteController.ts +51 -38
  67. package/src/json-plugin/interfaces/IModuleContext.ts +8 -8
  68. package/src/json-plugin/interfaces/ITargetContext.ts +6 -6
  69. package/src/json-plugin/interfaces/impl/ModuleContext.ts +10 -10
  70. package/src/json-plugin/interfaces/impl/TargetContext.ts +63 -58
  71. package/src/json-plugin/tasks/BaseTask.ts +5 -3
  72. package/src/json-plugin/tasks/CleanTask.ts +7 -7
  73. package/src/json-plugin/tasks/WatchTask.ts +20 -18
  74. package/template/SerializerPerformanceTemplate.hbs +5 -5
  75. package/template/SerializerStrictTemplate.hbs +1 -1
  76. package/template/SerializerTemplate.hbs +59 -42
@@ -6,12 +6,25 @@ export declare class ClassAnalyzer {
6
6
  private static analyzeInheritanceInfo;
7
7
  private static analyzeConstructorParameters;
8
8
  private static parseSerializableOptions;
9
+ private static extractOptionsFromObjectLiteral;
10
+ private static extractSingleOption;
11
+ private static parseBooleanInitializer;
12
+ private static parseDeserializationMode;
9
13
  private static parseSerialNameOptions;
14
+ private static extractNameFromProperties;
10
15
  private static analyzeOwnProperties;
16
+ private static checkUnknownType;
11
17
  private static classifyProperties;
18
+ private static buildPropertyClassification;
12
19
  private static collectAllAncestorProperties;
20
+ private static collectAncestorPropertiesRecursively;
21
+ private static resolveGenericTypeArgs;
13
22
  private static extractConstructorParams;
14
23
  private static createPropertyAnalysis;
24
+ private static getTypeNode;
25
+ private static getPropertyVisibility;
26
+ private static calculateIsMust;
27
+ private static validateTransientConstructorParam;
15
28
  private static analyzePropertyType;
16
29
  private static simplifyImportType;
17
30
  private static getTypeFromInitializer;
@@ -20,4 +33,6 @@ export declare class ClassAnalyzer {
20
33
  private static hasUndefinedInUnion;
21
34
  private static splitUnionType;
22
35
  private static analyzePropertyDecorators;
36
+ private static checkTransientConflicts;
37
+ private static checkPlainValueConflicts;
23
38
  }
@@ -118,41 +118,54 @@ class ClassAnalyzer {
118
118
  return undefined;
119
119
  }
120
120
  const args = decorator.getArguments();
121
- let generateSendable;
122
- let _with;
123
- let deserializationMode;
124
121
  const firstArg = args[0];
125
- if (!firstArg) {
122
+ if (!firstArg || firstArg.getKind() !== ts_morph_1.SyntaxKind.ObjectLiteralExpression) {
126
123
  return {};
127
124
  }
128
- if (firstArg.getKind() === ts_morph_1.SyntaxKind.ObjectLiteralExpression) {
129
- const properties = firstArg.asKindOrThrow(ts_morph_1.SyntaxKind.ObjectLiteralExpression).getProperties();
130
- for (const prop of properties) {
131
- if (prop.getKind() === ts_morph_1.SyntaxKind.PropertyAssignment) {
132
- const propAssignment = prop.asKindOrThrow(ts_morph_1.SyntaxKind.PropertyAssignment);
133
- const propertyName = propAssignment.getName();
134
- const initializer = propAssignment.getInitializer();
135
- if (propertyName === 'generateSendable' && initializer) {
136
- if (initializer.getKind() === ts_morph_1.SyntaxKind.TrueKeyword) {
137
- generateSendable = true;
138
- }
139
- else if (initializer.getKind() === ts_morph_1.SyntaxKind.FalseKeyword) {
140
- generateSendable = false;
141
- }
142
- }
143
- else if (propertyName === 'with' && initializer) {
144
- _with = initializer.getText();
145
- }
146
- else if (propertyName === 'deserializationMode' && initializer) {
147
- const modeText = initializer.getText().replace(/['"]/g, '');
148
- if (modeText === Types_1.DeserializationMode.PERFORMANCE || modeText === Types_1.DeserializationMode.STRICT) {
149
- deserializationMode = modeText;
150
- }
151
- }
152
- }
125
+ return this.extractOptionsFromObjectLiteral(firstArg.asKindOrThrow(ts_morph_1.SyntaxKind.ObjectLiteralExpression));
126
+ }
127
+ static extractOptionsFromObjectLiteral(objectLiteral) {
128
+ const options = {};
129
+ const properties = objectLiteral.getProperties();
130
+ for (const prop of properties) {
131
+ if (prop.getKind() !== ts_morph_1.SyntaxKind.PropertyAssignment) {
132
+ continue;
153
133
  }
134
+ const propAssignment = prop.asKindOrThrow(ts_morph_1.SyntaxKind.PropertyAssignment);
135
+ const initializer = propAssignment.getInitializer();
136
+ if (!initializer) {
137
+ continue;
138
+ }
139
+ this.extractSingleOption(options, propAssignment.getName(), initializer);
140
+ }
141
+ return options;
142
+ }
143
+ static extractSingleOption(options, propertyName, initializer) {
144
+ if (propertyName === 'generateSendable') {
145
+ options.generateSendable = this.parseBooleanInitializer(initializer);
146
+ }
147
+ else if (propertyName === 'with') {
148
+ options.with = initializer.getText();
149
+ }
150
+ else if (propertyName === 'deserializationMode') {
151
+ this.parseDeserializationMode(options, initializer);
152
+ }
153
+ }
154
+ static parseBooleanInitializer(initializer) {
155
+ const kind = initializer.getKind();
156
+ if (kind === ts_morph_1.SyntaxKind.TrueKeyword) {
157
+ return true;
158
+ }
159
+ if (kind === ts_morph_1.SyntaxKind.FalseKeyword) {
160
+ return false;
161
+ }
162
+ return undefined;
163
+ }
164
+ static parseDeserializationMode(options, initializer) {
165
+ const modeText = initializer.getText().replace(/['"]/g, '');
166
+ if (modeText === Types_1.DeserializationMode.PERFORMANCE || modeText === Types_1.DeserializationMode.STRICT) {
167
+ options.deserializationMode = modeText;
154
168
  }
155
- return { with: _with, generateSendable, deserializationMode };
156
169
  }
157
170
  static parseSerialNameOptions(decorator) {
158
171
  if (!decorator) {
@@ -163,21 +176,26 @@ class ClassAnalyzer {
163
176
  return undefined;
164
177
  }
165
178
  const firstArg = args[0];
166
- if (firstArg.getKind() === ts_morph_1.SyntaxKind.ObjectLiteralExpression) {
167
- const properties = firstArg.asKindOrThrow(ts_morph_1.SyntaxKind.ObjectLiteralExpression).getProperties();
168
- for (const prop of properties) {
169
- if (prop.getKind() === ts_morph_1.SyntaxKind.PropertyAssignment) {
170
- const propAssignment = prop.asKindOrThrow(ts_morph_1.SyntaxKind.PropertyAssignment);
171
- const name = propAssignment.getName();
172
- if (name === 'name') {
173
- const initializer = propAssignment.getInitializer();
174
- if (initializer && initializer.getKind() === ts_morph_1.SyntaxKind.StringLiteral) {
175
- const stringLiteral = initializer.asKindOrThrow(ts_morph_1.SyntaxKind.StringLiteral);
176
- return stringLiteral.getLiteralValue();
177
- }
178
- }
179
- }
179
+ if (firstArg.getKind() !== ts_morph_1.SyntaxKind.ObjectLiteralExpression) {
180
+ return undefined;
181
+ }
182
+ const properties = firstArg.asKindOrThrow(ts_morph_1.SyntaxKind.ObjectLiteralExpression).getProperties();
183
+ return this.extractNameFromProperties(properties);
184
+ }
185
+ static extractNameFromProperties(properties) {
186
+ for (const prop of properties) {
187
+ if (prop.getKind() !== ts_morph_1.SyntaxKind.PropertyAssignment) {
188
+ continue;
189
+ }
190
+ const propAssignment = prop.asKindOrThrow(ts_morph_1.SyntaxKind.PropertyAssignment);
191
+ if (propAssignment.getName() !== 'name') {
192
+ continue;
180
193
  }
194
+ const initializer = propAssignment.getInitializer();
195
+ if (!initializer || initializer.getKind() !== ts_morph_1.SyntaxKind.StringLiteral) {
196
+ continue;
197
+ }
198
+ return initializer.asKindOrThrow(ts_morph_1.SyntaxKind.StringLiteral).getLiteralValue();
181
199
  }
182
200
  return undefined;
183
201
  }
@@ -186,29 +204,34 @@ class ClassAnalyzer {
186
204
  const props = cls.getProperties();
187
205
  for (const prop of props) {
188
206
  const propertyAnalysis = this.createPropertyAnalysis(prop, constructorParams, genericParameters);
189
- if (propertyAnalysis.type.kind === Types_1.PropertyKind.UNKNOWN) {
190
- const hasTransient = propertyAnalysis.decorators?.isTransient;
191
- const hasCustomSerializer = !!propertyAnalysis.decorators?.with;
192
- if (!hasTransient && !hasCustomSerializer) {
193
- if (prop instanceof ts_morph_1.PropertyDeclaration) {
194
- throw new CustomError_1.CustomError(`不支持的类型 '${propertyAnalysis.type.sourceText}' 用于属性 '${propertyAnalysis.name}' (类: ${cls.getName()})。\n` +
195
- `请选择以下任一解决方案:\n` +
196
- ` 1. 添加 @Transient() 跳过序列化(属性仍会参与 Sendable 转换和对象拷贝):\n` +
197
- ` @Transient()\n` +
198
- ` ${propertyAnalysis.name}: ${propertyAnalysis.type.sourceText};\n\n` +
199
- ` 2. 添加 @Serializable({with: CustomSerializer}) 指定自定义序列化器:\n` +
200
- ` @Serializable({with: DateSerializer.INSTANCE})\n` +
201
- ` ${propertyAnalysis.name}: ${propertyAnalysis.type.sourceText};`, CustomError_1.ErrorCodes.TYPE_NOT_SUPPORT);
202
- }
203
- else {
204
- throw new CustomError_1.CustomError(`不支持的类型 '${propertyAnalysis.type.sourceText}' 用于属性 '${propertyAnalysis.name}' (接口: ${cls.getName()})`, CustomError_1.ErrorCodes.TYPE_NOT_SUPPORT);
205
- }
206
- }
207
- }
207
+ this.checkUnknownType(cls, prop, propertyAnalysis);
208
208
  ownProperties.push(propertyAnalysis);
209
209
  }
210
210
  return ownProperties;
211
211
  }
212
+ static checkUnknownType(cls, prop, propertyAnalysis) {
213
+ if (propertyAnalysis.type.kind !== Types_1.PropertyKind.UNKNOWN) {
214
+ return;
215
+ }
216
+ const hasTransient = propertyAnalysis.decorators?.isTransient;
217
+ const hasCustomSerializer = !!propertyAnalysis.decorators?.with;
218
+ if (hasTransient || hasCustomSerializer) {
219
+ return;
220
+ }
221
+ if (prop instanceof ts_morph_1.PropertyDeclaration) {
222
+ throw new CustomError_1.CustomError(`不支持的类型 '${propertyAnalysis.type.sourceText}' 用于属性 '${propertyAnalysis.name}' (类: ${cls.getName()})。\n` +
223
+ `请选择以下任一解决方案:\n` +
224
+ ` 1. 添加 @Transient() 跳过序列化(属性仍会参与 Sendable 转换和对象拷贝):\n` +
225
+ ` @Transient()\n` +
226
+ ` ${propertyAnalysis.name}: ${propertyAnalysis.type.sourceText};\n\n` +
227
+ ` 2. 添加 @Serializable({with: CustomSerializer}) 指定自定义序列化器:\n` +
228
+ ` @Serializable({with: DateSerializer.INSTANCE})\n` +
229
+ ` ${propertyAnalysis.name}: ${propertyAnalysis.type.sourceText};`, CustomError_1.ErrorCodes.TYPE_NOT_SUPPORT);
230
+ }
231
+ else {
232
+ throw new CustomError_1.CustomError(`不支持的类型 '${propertyAnalysis.type.sourceText}' 用于属性 '${propertyAnalysis.name}' (接口: ${cls.getName()})`, CustomError_1.ErrorCodes.TYPE_NOT_SUPPORT);
233
+ }
234
+ }
212
235
  static classifyProperties(ownProperties, inheritance, currentClassGenericParams = []) {
213
236
  if (!inheritance.isInherited || !inheritance.baseClassAnalysis) {
214
237
  return {
@@ -218,20 +241,14 @@ class ClassAnalyzer {
218
241
  };
219
242
  }
220
243
  const allAncestorProperties = this.collectAllAncestorProperties(inheritance.baseClassAnalysis, inheritance.genericTypeArguments || [], currentClassGenericParams);
244
+ return this.buildPropertyClassification(ownProperties, allAncestorProperties);
245
+ }
246
+ static buildPropertyClassification(ownProperties, allAncestorProperties) {
221
247
  const ownPropertyNames = new Set(ownProperties.map((prop) => prop.name));
222
- const inheritedProperties = [];
223
- for (const ancestorProp of allAncestorProperties) {
224
- if (!ownPropertyNames.has(ancestorProp.name)) {
225
- inheritedProperties.push(ancestorProp);
226
- }
227
- }
248
+ const inheritedProperties = allAncestorProperties.filter((ancestorProp) => !ownPropertyNames.has(ancestorProp.name));
228
249
  const overriddenProperties = ownProperties.filter((prop) => allAncestorProperties.some((ancestorProp) => ancestorProp.name === prop.name));
229
250
  const properties = [...inheritedProperties, ...ownProperties];
230
- return {
231
- inheritedProperties,
232
- overriddenProperties,
233
- properties
234
- };
251
+ return { inheritedProperties, overriddenProperties, properties };
235
252
  }
236
253
  static collectAllAncestorProperties(classAnalysis, childGenericArguments = [], currentClassGenericParams = []) {
237
254
  const allProperties = [];
@@ -239,24 +256,31 @@ class ClassAnalyzer {
239
256
  const genericMapping = GenericTypeSubstitutionUtil_1.GenericTypeSubstitutionUtil.buildGenericMapping(parentGenericParams, childGenericArguments);
240
257
  const substitutedProperties = classAnalysis.ownProperties.map((property) => GenericTypeSubstitutionUtil_1.GenericTypeSubstitutionUtil.substitutePropertyType(property, genericMapping, currentClassGenericParams));
241
258
  allProperties.push(...substitutedProperties);
242
- if (classAnalysis.inheritance.isInherited && classAnalysis.inheritance.baseClassAnalysis) {
243
- const parentGenericTypeArgs = classAnalysis.inheritance.genericTypeArguments || [];
244
- const resolvedParentGenericArgs = parentGenericTypeArgs.map(typeArg => {
245
- const typeStructure = handlers_1.TypeHandlerRegistry.getInstance().parseType(typeArg, {
246
- depth: 0,
247
- genericParams: parentGenericParams
248
- });
249
- if (typeStructure.kind === Types_1.PropertyKind.GENERIC && genericMapping.has(typeStructure.sourceText)) {
250
- return genericMapping.get(typeStructure.sourceText);
251
- }
252
- return typeArg;
253
- });
254
- Logger_1.Logger.debug(`[CollectAncestors] Resolved parent generic args: ${resolvedParentGenericArgs.map(a => a.getText()).join(', ')}`);
255
- const ancestorProperties = this.collectAllAncestorProperties(classAnalysis.inheritance.baseClassAnalysis, resolvedParentGenericArgs, currentClassGenericParams);
256
- allProperties.push(...ancestorProperties);
257
- }
259
+ this.collectAncestorPropertiesRecursively(classAnalysis, parentGenericParams, genericMapping, currentClassGenericParams, allProperties);
258
260
  return allProperties;
259
261
  }
262
+ static collectAncestorPropertiesRecursively(classAnalysis, parentGenericParams, genericMapping, currentClassGenericParams, allProperties) {
263
+ if (!classAnalysis.inheritance.isInherited || !classAnalysis.inheritance.baseClassAnalysis) {
264
+ return;
265
+ }
266
+ const parentGenericTypeArgs = classAnalysis.inheritance.genericTypeArguments || [];
267
+ const resolvedParentGenericArgs = this.resolveGenericTypeArgs(parentGenericTypeArgs, parentGenericParams, genericMapping);
268
+ Logger_1.Logger.debug(`[CollectAncestors] Resolved parent generic args: ${resolvedParentGenericArgs.map(a => a.getText()).join(', ')}`);
269
+ const ancestorProperties = this.collectAllAncestorProperties(classAnalysis.inheritance.baseClassAnalysis, resolvedParentGenericArgs, currentClassGenericParams);
270
+ allProperties.push(...ancestorProperties);
271
+ }
272
+ static resolveGenericTypeArgs(typeArgs, parentGenericParams, genericMapping) {
273
+ return typeArgs.map(typeArg => {
274
+ const typeStructure = handlers_1.TypeHandlerRegistry.getInstance().parseType(typeArg, {
275
+ depth: 0,
276
+ genericParams: parentGenericParams
277
+ });
278
+ if (typeStructure.kind === Types_1.PropertyKind.GENERIC && genericMapping.has(typeStructure.sourceText)) {
279
+ return genericMapping.get(typeStructure.sourceText);
280
+ }
281
+ return typeArg;
282
+ });
283
+ }
260
284
  static extractConstructorParams(constructor) {
261
285
  const parameters = [];
262
286
  for (const param of constructor.getParameters()) {
@@ -271,49 +295,66 @@ class ClassAnalyzer {
271
295
  }
272
296
  static createPropertyAnalysis(prop, constructorParams, genericParameters) {
273
297
  const name = prop.getName();
298
+ const typeNode = this.getTypeNode(prop);
299
+ const type = handlers_1.TypeHandlerRegistry.getInstance().parseType(typeNode, { genericParams: genericParameters, depth: 0 });
300
+ type.isOptional = prop.hasQuestionToken();
301
+ const defaultValue = prop instanceof ts_morph_1.PropertyDeclaration ?
302
+ this.analyzeDefaultValue(prop, constructorParams) : undefined;
303
+ const decorators = prop instanceof ts_morph_1.PropertyDeclaration ? this.analyzePropertyDecorators(prop) : undefined;
304
+ const visibility = this.getPropertyVisibility(prop);
305
+ const constructorParam = constructorParams.find((param) => param.name === name);
306
+ const isMust = this.calculateIsMust(prop, type, constructorParam, decorators, defaultValue);
307
+ if (decorators?.isTransient && constructorParam) {
308
+ this.validateTransientConstructorParam(name, constructorParam);
309
+ }
310
+ return {
311
+ name,
312
+ defaultValue,
313
+ decorators,
314
+ type,
315
+ isMust,
316
+ visibility
317
+ };
318
+ }
319
+ static getTypeNode(prop) {
274
320
  let typeNode = prop.getTypeNode();
275
321
  if (!typeNode) {
276
322
  typeNode = this.analyzePropertyType(prop);
277
323
  }
278
324
  if (!typeNode) {
279
- throw new CustomError_1.CustomError(`无法分析属性 '${name}' 的类型。请检查属性声明。`, CustomError_1.ErrorCodes.TYPE_NOT_SUPPORT);
325
+ throw new CustomError_1.CustomError(`无法分析属性 '${prop.getName()}' 的类型。请检查属性声明。`, CustomError_1.ErrorCodes.TYPE_NOT_SUPPORT);
280
326
  }
281
- const defaultValue = prop instanceof ts_morph_1.PropertyDeclaration ?
282
- this.analyzeDefaultValue(prop, constructorParams) : undefined;
283
- const decorators = prop instanceof ts_morph_1.PropertyDeclaration ? this.analyzePropertyDecorators(prop) : undefined;
284
- const type = handlers_1.TypeHandlerRegistry.getInstance().parseType(typeNode, { genericParams: genericParameters, depth: 0 });
285
- type.isOptional = prop.hasQuestionToken();
286
- const visibility = prop.hasModifier(ts_morph_1.SyntaxKind.PrivateKeyword) ? Types_1.PropertyVisibility.PRIVATE :
287
- prop.hasModifier(ts_morph_1.SyntaxKind.ProtectedKeyword) ? Types_1.PropertyVisibility.PROTECTED :
288
- Types_1.PropertyVisibility.PUBLIC;
289
- const constructorParam = constructorParams.find((param) => param.name === name);
290
- const isParamOptional = constructorParam
291
- ? constructorParam.isOptional ||
292
- constructorParam.defaultValue !== undefined ||
293
- this.hasUndefinedInUnion(constructorParam.type)
294
- : true;
295
- let isMust;
296
- if (constructorParam) {
297
- isMust = !isParamOptional;
327
+ return typeNode;
328
+ }
329
+ static getPropertyVisibility(prop) {
330
+ if (prop.hasModifier(ts_morph_1.SyntaxKind.PrivateKeyword)) {
331
+ return Types_1.PropertyVisibility.PRIVATE;
298
332
  }
299
- else {
300
- isMust = decorators?.isRequired || !this.isOptional(prop, defaultValue, type);
333
+ if (prop.hasModifier(ts_morph_1.SyntaxKind.ProtectedKeyword)) {
334
+ return Types_1.PropertyVisibility.PROTECTED;
301
335
  }
302
- if (decorators?.isTransient && constructorParam && !isParamOptional) {
336
+ return Types_1.PropertyVisibility.PUBLIC;
337
+ }
338
+ static calculateIsMust(prop, type, constructorParam, decorators, defaultValue) {
339
+ if (constructorParam) {
340
+ const isParamOptional = constructorParam.isOptional ||
341
+ constructorParam.defaultValue !== undefined ||
342
+ this.hasUndefinedInUnion(constructorParam.type);
343
+ return !isParamOptional;
344
+ }
345
+ return decorators?.isRequired || !this.isOptional(prop, defaultValue, type);
346
+ }
347
+ static validateTransientConstructorParam(name, constructorParam) {
348
+ const isParamOptional = constructorParam.isOptional ||
349
+ constructorParam.defaultValue !== undefined ||
350
+ this.hasUndefinedInUnion(constructorParam.type);
351
+ if (!isParamOptional) {
303
352
  throw new CustomError_1.CustomError(`@Transient 属性 '${name}' 的构造函数参数必须是可选的或有默认值。\n` +
304
353
  `因为 @Transient 属性不参与序列化,反序列化时无法从外部数据获取值。\n` +
305
354
  `请修改构造函数参数为以下任一形式:\n` +
306
355
  ` 1. 可选参数: constructor(..., ${name}?: ${constructorParam.type})\n` +
307
356
  ` 2. 带默认值: constructor(..., ${name}: ${constructorParam.type} = defaultValue)`, CustomError_1.ErrorCodes.TRANSIENT_ATTR_OPTIONAL);
308
357
  }
309
- return {
310
- name,
311
- defaultValue,
312
- decorators,
313
- type,
314
- isMust,
315
- visibility
316
- };
317
358
  }
318
359
  static analyzePropertyType(prop) {
319
360
  const name = prop.getName();
@@ -472,33 +513,11 @@ class ClassAnalyzer {
472
513
  break;
473
514
  case constants_1.DecoratorConstants.SERIALIZABLE:
474
515
  _with = this.parseSerializableOptions(decorator).with;
516
+ break;
475
517
  }
476
518
  });
477
- if (isTransient) {
478
- const conflictingDecorators = [];
479
- if (isRequired) {
480
- conflictingDecorators.push('@Required');
481
- }
482
- if (serialName) {
483
- conflictingDecorators.push('@SerialName');
484
- }
485
- if (_with) {
486
- conflictingDecorators.push('@Serializable');
487
- }
488
- if (isPlainValue) {
489
- conflictingDecorators.push('@PlainValue');
490
- }
491
- if (conflictingDecorators.length > 0) {
492
- throw new CustomError_1.CustomError(`属性 '${prop.getName()}' 的注解冲突:@Transient 与 ${conflictingDecorators.join(', ')} 不能同时使用。\n` +
493
- `@Transient 表示跳过序列化,与其他序列化配置注解互斥。\n` +
494
- `请移除 @Transient 或移除其他序列化注解。`, CustomError_1.ErrorCodes.ANNOTATION_CONFLICT);
495
- }
496
- }
497
- if (isPlainValue && _with) {
498
- throw new CustomError_1.CustomError(`属性 '${prop.getName()}' 的注解冲突:@PlainValue 与 @Serializable(with:) 不能同时使用。\n` +
499
- `@PlainValue 跳过类型转换直接使用原始值,与自定义序列化器冲突。\n` +
500
- `请移除 @PlainValue 或移除自定义序列化器。`, CustomError_1.ErrorCodes.ANNOTATION_CONFLICT);
501
- }
519
+ this.checkTransientConflicts(prop.getName(), isTransient, isRequired, !!serialName, !!_with, isPlainValue);
520
+ this.checkPlainValueConflicts(prop.getName(), isPlainValue, !!_with);
502
521
  return {
503
522
  isRequired,
504
523
  isTransient,
@@ -507,5 +526,35 @@ class ClassAnalyzer {
507
526
  with: _with
508
527
  };
509
528
  }
529
+ static checkTransientConflicts(propName, isTransient, isRequired, hasSerialName, hasWith, isPlainValue) {
530
+ if (!isTransient) {
531
+ return;
532
+ }
533
+ const conflictingDecorators = [];
534
+ if (isRequired) {
535
+ conflictingDecorators.push('@Required');
536
+ }
537
+ if (hasSerialName) {
538
+ conflictingDecorators.push('@SerialName');
539
+ }
540
+ if (hasWith) {
541
+ conflictingDecorators.push('@Serializable');
542
+ }
543
+ if (isPlainValue) {
544
+ conflictingDecorators.push('@PlainValue');
545
+ }
546
+ if (conflictingDecorators.length > 0) {
547
+ throw new CustomError_1.CustomError(`属性 '${propName}' 的注解冲突:@Transient 与 ${conflictingDecorators.join(', ')} 不能同时使用。\n` +
548
+ `@Transient 表示跳过序列化,与其他序列化配置注解互斥。\n` +
549
+ `请移除 @Transient 或移除其他序列化注解。`, CustomError_1.ErrorCodes.ANNOTATION_CONFLICT);
550
+ }
551
+ }
552
+ static checkPlainValueConflicts(propName, isPlainValue, hasWith) {
553
+ if (isPlainValue && hasWith) {
554
+ throw new CustomError_1.CustomError(`属性 '${propName}' 的注解冲突:@PlainValue 与 @Serializable(with:) 不能同时使用。\n` +
555
+ `@PlainValue 跳过类型转换直接使用原始值,与自定义序列化器冲突。\n` +
556
+ `请移除 @PlainValue 或移除自定义序列化器。`, CustomError_1.ErrorCodes.ANNOTATION_CONFLICT);
557
+ }
558
+ }
510
559
  }
511
560
  exports.ClassAnalyzer = ClassAnalyzer;
@@ -10,9 +10,12 @@ export declare class CustomTypeAnalyzer {
10
10
  clearCache(): void;
11
11
  private findInCurrentFile;
12
12
  private findInImports;
13
+ private processImportMatch;
13
14
  private findInCrossModule;
14
15
  private searchInSourceFile;
15
16
  private parseEnumDetails;
17
+ private parseEnumMember;
18
+ private createStringEnumResult;
16
19
  private parseClassDetails;
17
20
  private parseInterfaceDetails;
18
21
  private parseTypeAliasDetails;
@@ -80,36 +80,44 @@ class CustomTypeAnalyzer {
80
80
  const imports = sourceFile.getImportDeclarations();
81
81
  for (const importDecl of imports) {
82
82
  const namedImports = importDecl.getNamedImports();
83
+ const matchedImport = namedImports.find(ni => ni.getName() === targetName);
84
+ if (!matchedImport) {
85
+ continue;
86
+ }
83
87
  const specifierValue = importDecl.getModuleSpecifierValue();
84
- for (const namedImport of namedImports) {
85
- const importName = namedImport.getName();
86
- if (importName === targetName) {
87
- const moduleSpecifier = importDecl.getModuleSpecifierValue();
88
- const resolvedPath = this.resolveImportPath(moduleSpecifier, sourceFile);
89
- if (resolvedPath && SerializationPathUtil_1.default.exist(resolvedPath)) {
90
- const externalSourceFile = this.getOrLoadSourceFile(resolvedPath);
91
- if (externalSourceFile) {
92
- const typeDetail = this.searchInSourceFile(targetName, externalSourceFile);
93
- if (typeDetail) {
94
- return {
95
- typeName: targetName,
96
- typeKind: typeDetail.kind,
97
- importPath: specifierValue,
98
- source: {
99
- type: 'imported',
100
- sourceFilePath: externalSourceFile.getFilePath(),
101
- originalImport: specifierValue
102
- },
103
- details: typeDetail
104
- };
105
- }
106
- }
107
- }
108
- }
88
+ const result = this.processImportMatch(importDecl, targetName, sourceFile, specifierValue);
89
+ if (result) {
90
+ return result;
109
91
  }
110
92
  }
111
93
  return null;
112
94
  }
95
+ processImportMatch(importDecl, targetName, sourceFile, specifierValue) {
96
+ const moduleSpecifier = importDecl.getModuleSpecifierValue();
97
+ const resolvedPath = this.resolveImportPath(moduleSpecifier, sourceFile);
98
+ if (!resolvedPath || !SerializationPathUtil_1.default.exist(resolvedPath)) {
99
+ return null;
100
+ }
101
+ const externalSourceFile = this.getOrLoadSourceFile(resolvedPath);
102
+ if (!externalSourceFile) {
103
+ return null;
104
+ }
105
+ const typeDetail = this.searchInSourceFile(targetName, externalSourceFile);
106
+ if (!typeDetail) {
107
+ return null;
108
+ }
109
+ return {
110
+ typeName: targetName,
111
+ typeKind: typeDetail.kind,
112
+ importPath: specifierValue,
113
+ source: {
114
+ type: 'imported',
115
+ sourceFilePath: externalSourceFile.getFilePath(),
116
+ originalImport: specifierValue
117
+ },
118
+ details: typeDetail
119
+ };
120
+ }
113
121
  findInCrossModule(targetName, sourceFile) {
114
122
  return null;
115
123
  }
@@ -146,49 +154,46 @@ class CustomTypeAnalyzer {
146
154
  let numericValue = 0;
147
155
  const enumMembers = enumDecl.getMembers();
148
156
  for (const member of enumMembers) {
149
- const memberName = member.getName();
150
- let memberValue;
151
- let literalValue;
152
- const initializer = member.getInitializer();
153
- if (initializer) {
154
- const initText = initializer.getText().trim();
155
- if (initText.startsWith('"') && initText.endsWith('"')) {
156
- memberValue = initText.slice(1, -1);
157
- literalValue = initText;
158
- valueType = 'string';
159
- }
160
- else if (initText.startsWith("'") && initText.endsWith("'")) {
161
- memberValue = initText.slice(1, -1);
162
- literalValue = `"${memberValue}"`;
163
- valueType = 'string';
164
- }
165
- else {
166
- const numValue = parseInt(initText, 10);
167
- if (!isNaN(numValue)) {
168
- memberValue = numValue;
169
- literalValue = numValue.toString();
170
- numericValue = numValue + 1;
171
- }
172
- else {
173
- memberValue = initText;
174
- literalValue = `"${initText}"`;
175
- valueType = 'string';
176
- }
177
- }
178
- }
179
- else {
180
- memberValue = numericValue;
181
- literalValue = numericValue.toString();
182
- numericValue++;
157
+ const { memberValue, literalValue, type, nextValue } = this.parseEnumMember(member, numericValue);
158
+ numericValue = nextValue;
159
+ if (type === 'string') {
160
+ valueType = 'string';
183
161
  }
184
162
  members.push({
185
- name: memberName,
163
+ name: member.getName(),
186
164
  value: memberValue,
187
165
  literalValue
188
166
  });
189
167
  }
190
168
  return { kind: __1.TypeKind.ENUM, valueType, members };
191
169
  }
170
+ parseEnumMember(member, numericValue) {
171
+ const initializer = member.getInitializer();
172
+ if (!initializer) {
173
+ return {
174
+ memberValue: numericValue,
175
+ literalValue: numericValue.toString(),
176
+ type: 'number',
177
+ nextValue: numericValue + 1
178
+ };
179
+ }
180
+ const initText = initializer.getText().trim();
181
+ if (initText.startsWith('"') && initText.endsWith('"')) {
182
+ return this.createStringEnumResult(initText.slice(1, -1), initText, numericValue);
183
+ }
184
+ if (initText.startsWith("'") && initText.endsWith("'")) {
185
+ const val = initText.slice(1, -1);
186
+ return this.createStringEnumResult(val, `"${val}"`, numericValue);
187
+ }
188
+ const numValue = parseInt(initText, 10);
189
+ if (!isNaN(numValue)) {
190
+ return { memberValue: numValue, literalValue: numValue.toString(), type: 'number', nextValue: numValue + 1 };
191
+ }
192
+ return this.createStringEnumResult(initText, `"${initText}"`, numericValue);
193
+ }
194
+ createStringEnumResult(memberValue, literalValue, numericValue) {
195
+ return { memberValue, literalValue, type: 'string', nextValue: numericValue };
196
+ }
192
197
  parseClassDetails(classDecl) {
193
198
  return {
194
199
  kind: __1.TypeKind.CLASS,
@@ -11,4 +11,5 @@ DecoratorConstants.SERIAL_NAME = 'SerialName';
11
11
  DecoratorConstants.REQUIRED = 'Required';
12
12
  DecoratorConstants.TRANSIENT = 'Transient';
13
13
  DecoratorConstants.PLAIN_VALUE = 'PlainValue';
14
- DecoratorConstants.SERIAL_DECORATORS = [_a.SERIALIZABLE, _a.SERIAL_NAME, _a.REQUIRED, _a.TRANSIENT, _a.PLAIN_VALUE];
14
+ DecoratorConstants.SERIAL_DECORATORS = [_a.SERIALIZABLE, _a.SERIAL_NAME, _a.REQUIRED, _a.TRANSIENT,
15
+ _a.PLAIN_VALUE];
@@ -64,7 +64,7 @@ class BuildProfileUpdaterImpl {
64
64
  }
65
65
  updateSourceRootsConfig(config) {
66
66
  let updated = false;
67
- const generatedSourceRoot = "./src/generated";
67
+ const generatedSourceRoot = './src/generated';
68
68
  __1.Logger.info(`target.source.sourceRoots start`);
69
69
  if (config.targets && Array.isArray(config.targets)) {
70
70
  for (const target of config.targets) {
@@ -25,7 +25,7 @@ class ImportRewriteServiceImpl {
25
25
  this.transformService.rewriteFileImports(filePath, context, generatedFileInfos, options.preserveOriginalImports);
26
26
  successCount++;
27
27
  }
28
- catch (error) {
28
+ catch {
29
29
  errorCount++;
30
30
  }
31
31
  }
@@ -1,2 +1,2 @@
1
- export { ITask } from './ITask';
2
- export { ITaskContext } from './ITaskContext';
1
+ export type { ITask } from './ITask';
2
+ export type { ITaskContext } from './ITaskContext';