@hadss/turbo-trans-json-plugin 1.0.0-rc.0 → 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 (88) hide show
  1. package/README.md +1 -1
  2. package/dist/core/Types.d.ts +7 -0
  3. package/dist/core/Types.js +7 -1
  4. package/dist/core/analyzers/ClassAnalyzer.d.ts +15 -0
  5. package/dist/core/analyzers/ClassAnalyzer.js +200 -120
  6. package/dist/core/analyzers/CustomTypeAnalyzer.d.ts +3 -0
  7. package/dist/core/analyzers/CustomTypeAnalyzer.js +65 -60
  8. package/dist/core/constants/DecoratorConstants.d.ts +1 -0
  9. package/dist/core/constants/DecoratorConstants.js +3 -1
  10. package/dist/core/handlers/CustomClassHandler.js +0 -1
  11. package/dist/core/import-rewrite/services/BuildProfileUpdater.js +1 -1
  12. package/dist/core/import-rewrite/services/ImportRewriteService.js +1 -1
  13. package/dist/core/interfaces/index.d.ts +2 -2
  14. package/dist/core/services/CodeAnalysisService.js +2 -1
  15. package/dist/core/services/CodeGenerationService/CodeGenerationService.js +1 -1
  16. package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.d.ts +0 -1
  17. package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.js +0 -20
  18. package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.d.ts +4 -4
  19. package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.js +26 -45
  20. package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.d.ts +22 -0
  21. package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.js +194 -129
  22. package/dist/core/services/CodeGenerationService/generators/SerializerGenerator.js +20 -15
  23. package/dist/core/services/CodeGenerationService/generators/TempSerializerGenerator.js +2 -1
  24. package/dist/core/services/CodeGenerationService/shared/ImportManager.d.ts +2 -2
  25. package/dist/core/template/HandlebarsTemplateEngine.d.ts +2 -0
  26. package/dist/core/template/HandlebarsTemplateEngine.js +24 -2
  27. package/dist/core/utils/DeepCopyUtil.js +4 -2
  28. package/dist/core/utils/GenericTypeSubstitutionUtil.d.ts +1 -0
  29. package/dist/core/utils/GenericTypeSubstitutionUtil.js +27 -1
  30. package/dist/core/utils/SerializationPathUtil.d.ts +1 -1
  31. package/dist/core/utils/TsMorphUtil.js +6 -1
  32. package/dist/json-plugin/JSONExecuteController.d.ts +4 -0
  33. package/dist/json-plugin/JSONExecuteController.js +46 -36
  34. package/dist/json-plugin/interfaces/impl/TargetContext.js +4 -2
  35. package/dist/json-plugin/tasks/BaseTask.d.ts +2 -2
  36. package/dist/json-plugin/tasks/WatchTask.js +2 -1
  37. package/package.json +1 -1
  38. package/src/core/Types.ts +97 -89
  39. package/src/core/analyzers/ClassAnalyzer.ts +358 -197
  40. package/src/core/analyzers/CustomTypeAnalyzer.ts +145 -74
  41. package/src/core/constants/DecoratorConstants.ts +7 -5
  42. package/src/core/constants/PathConstants.ts +7 -7
  43. package/src/core/constants/StringConstants.ts +95 -97
  44. package/src/core/handlers/BaseTypeHandler.ts +11 -2
  45. package/src/core/handlers/CustomClassHandler.ts +4 -7
  46. package/src/core/handlers/DateHandler.ts +54 -46
  47. package/src/core/handlers/DecimalHandler.ts +53 -45
  48. package/src/core/handlers/EnumHandler.ts +2 -1
  49. package/src/core/handlers/GenericContainerHandler.ts +3 -1
  50. package/src/core/handlers/TupleHandler.ts +2 -1
  51. package/src/core/handlers/TypeHandlerRegistry.ts +3 -2
  52. package/src/core/handlers/UnionTypeHandler.ts +8 -7
  53. package/src/core/import-rewrite/services/BuildProfileUpdater.ts +7 -5
  54. package/src/core/import-rewrite/services/ImportRewriteService.ts +1 -3
  55. package/src/core/import-rewrite/services/ImportTransformService.ts +2 -2
  56. package/src/core/import-rewrite/types/ImportRewriteTypes.ts +3 -3
  57. package/src/core/index.ts +4 -4
  58. package/src/core/interfaces/ITask.ts +6 -5
  59. package/src/core/interfaces/ITaskContext.ts +9 -9
  60. package/src/core/interfaces/index.ts +2 -2
  61. package/src/core/logger/Logger.ts +28 -28
  62. package/src/core/services/CodeAnalysisService.ts +3 -2
  63. package/src/core/services/CodeGenerationEngine.ts +42 -42
  64. package/src/core/services/CodeGenerationService/CodeGenerationService.ts +1 -2
  65. package/src/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.ts +0 -29
  66. package/src/core/services/CodeGenerationService/generators/OriginalClassGenerator.ts +31 -64
  67. package/src/core/services/CodeGenerationService/generators/SendableClassGenerator.ts +261 -170
  68. package/src/core/services/CodeGenerationService/generators/SerializerGenerator.ts +26 -19
  69. package/src/core/services/CodeGenerationService/generators/TempSerializerGenerator.ts +5 -3
  70. package/src/core/services/CodeGenerationService/shared/ImportManager.ts +8 -8
  71. package/src/core/template/HandlebarsTemplateEngine.ts +43 -10
  72. package/src/core/utils/ConfigManager.ts +2 -1
  73. package/src/core/utils/DeepCopyUtil.ts +4 -2
  74. package/src/core/utils/GenericTypeSubstitutionUtil.ts +45 -2
  75. package/src/core/utils/SerializationPathUtil.ts +7 -6
  76. package/src/core/utils/TsMorphUtil.ts +9 -2
  77. package/src/index.ts +2 -2
  78. package/src/json-plugin/JSONExecuteController.ts +51 -38
  79. package/src/json-plugin/interfaces/IModuleContext.ts +8 -8
  80. package/src/json-plugin/interfaces/ITargetContext.ts +6 -6
  81. package/src/json-plugin/interfaces/impl/ModuleContext.ts +10 -10
  82. package/src/json-plugin/interfaces/impl/TargetContext.ts +63 -58
  83. package/src/json-plugin/tasks/BaseTask.ts +5 -4
  84. package/src/json-plugin/tasks/CleanTask.ts +7 -7
  85. package/src/json-plugin/tasks/WatchTask.ts +20 -18
  86. package/template/SerializerPerformanceTemplate.hbs +14 -4
  87. package/template/SerializerStrictTemplate.hbs +9 -1
  88. package/template/SerializerTemplate.hbs +71 -46
@@ -13,24 +13,24 @@
13
13
  * limitations under the License.
14
14
  */
15
15
 
16
- import { Target } from '@ohos/hvigor-ohos-plugin'
17
- import { ModuleBuildProfile } from '@ohos/hvigor-ohos-plugin/src/options/build/module-build-profile'
18
- import { PathConstants} from '../../../core';
19
- import { IModuleContext } from '../IModuleContext'
20
- import { ITargetContext } from '../ITargetContext'
16
+ import { Target } from '@ohos/hvigor-ohos-plugin';
17
+ import { ModuleBuildProfile } from '@ohos/hvigor-ohos-plugin/src/options/build/module-build-profile';
18
+ import { PathConstants } from '../../../core';
19
+ import { IModuleContext } from '../IModuleContext';
20
+ import { ITargetContext } from '../ITargetContext';
21
21
  import SerializationPathUtil from '../../../core/utils/SerializationPathUtil';
22
22
  import { CustomError, ErrorCodes } from '../../../core/utils/CustomError';
23
23
 
24
24
  export class TargetContextImpl implements ITargetContext {
25
- readonly target: Target
26
- readonly context: IModuleContext
25
+ readonly target: Target;
26
+ readonly context: IModuleContext;
27
27
 
28
- private readonly DEFAULT_SOURCE_ROOT = PathConstants.DEFAULT_SOURCE_ROOT
29
- private readonly GENERATED_ROOT = PathConstants.GENERATED_ROOT
28
+ private readonly DEFAULT_SOURCE_ROOT = PathConstants.DEFAULT_SOURCE_ROOT;
29
+ private readonly GENERATED_ROOT = PathConstants.GENERATED_ROOT;
30
30
 
31
31
  constructor(target: Target, context: IModuleContext) {
32
- this.target = target
33
- this.context = context
32
+ this.target = target;
33
+ this.context = context;
34
34
  }
35
35
 
36
36
  private get targetOpt(): ModuleBuildProfile.ModuleTargetBuildOpt {
@@ -46,21 +46,21 @@ export class TargetContextImpl implements ITargetContext {
46
46
  */
47
47
  getCurrentTargetScanFiles(): string[] {
48
48
  // 获取当前目标的所有源代码根目录的绝对路径
49
- const absoluteSourceRoots = this.getAbsoluteSourceRoots()
49
+ const absoluteSourceRoots = this.getAbsoluteSourceRoots();
50
50
 
51
51
  // 过滤扫描文件,只保留在当前目标源代码根目录下的文件
52
52
  return this.context.scanFiles.filter(item => {
53
53
  // 标准化文件路径格式,确保路径分隔符统一
54
- const normalizedFilePath = SerializationPathUtil.normalize(item)
54
+ const normalizedFilePath = SerializationPathUtil.normalize(item);
55
55
 
56
56
  // 检查文件路径是否以任一源代码根目录开头
57
57
  // 这样可以确保只处理属于当前目标的文件
58
- return absoluteSourceRoots.some(sourceRoot => normalizedFilePath.startsWith(sourceRoot))
59
- })
58
+ return absoluteSourceRoots.some(sourceRoot => normalizedFilePath.startsWith(sourceRoot));
59
+ });
60
60
  }
61
61
 
62
62
  getModuleName(): string {
63
- return this.context.moduleContext.getModuleName()
63
+ return this.context.moduleContext.getModuleName();
64
64
  }
65
65
 
66
66
  getModulePath(): string {
@@ -69,104 +69,108 @@ export class TargetContextImpl implements ITargetContext {
69
69
 
70
70
  getPackageName(): string {
71
71
  // 这里需要获取oh-package.json5中配置的name
72
- const packagePath = SerializationPathUtil.pathResolve(this.getModulePath(), 'oh-package.json5')
73
- const ohPackageObj = SerializationPathUtil.readJson5(packagePath)
74
- return ohPackageObj.name
72
+ const packagePath = SerializationPathUtil.pathResolve(this.getModulePath(), 'oh-package.json5');
73
+ const ohPackageObj = SerializationPathUtil.readJson5(packagePath);
74
+ return ohPackageObj.name;
75
75
  }
76
76
 
77
77
  mapToOutputPath(absSourceFile: string): string {
78
- const normalizedFilePath = SerializationPathUtil.normalize(absSourceFile)
79
- const moduleRoot = this.context.moduleContext.getModulePath()
80
- const srcMainAbs = SerializationPathUtil.normalize(SerializationPathUtil.pathResolve(moduleRoot, this.DEFAULT_SOURCE_ROOT))
81
- const generatedRootAbs = this.getOutputRoot()
78
+ const normalizedFilePath = SerializationPathUtil.normalize(absSourceFile);
79
+ const moduleRoot = this.context.moduleContext.getModulePath();
80
+ const srcMainAbs = SerializationPathUtil.normalize(
81
+ SerializationPathUtil.pathResolve(moduleRoot, this.DEFAULT_SOURCE_ROOT));
82
+ const generatedRootAbs = this.getOutputRoot();
82
83
 
83
84
  // 优先基于 src/main 做路径映射
84
85
  if (normalizedFilePath.startsWith(srcMainAbs + SerializationPathUtil.sep)) {
85
- const relativeToSrcMain = SerializationPathUtil.relative(srcMainAbs, normalizedFilePath)
86
- return SerializationPathUtil.join(generatedRootAbs, relativeToSrcMain)
86
+ const relativeToSrcMain = SerializationPathUtil.relative(srcMainAbs, normalizedFilePath);
87
+ return SerializationPathUtil.join(generatedRootAbs, relativeToSrcMain);
87
88
  }
88
89
 
89
90
  // 如果文件不在 src/main 下,退化为:找到匹配的任一 sourceRoot,映射到 generated 根下
90
- const absoluteSourceRoots = this.getAbsoluteSourceRoots()
91
- const matchedRoot = absoluteSourceRoots.find(root => normalizedFilePath.startsWith(root))
91
+ const absoluteSourceRoots = this.getAbsoluteSourceRoots();
92
+ const matchedRoot = absoluteSourceRoots.find(root => normalizedFilePath.startsWith(root));
92
93
  if (matchedRoot) {
93
- const rel = SerializationPathUtil.relative(matchedRoot, normalizedFilePath)
94
- return SerializationPathUtil.join(generatedRootAbs, rel)
94
+ const rel = SerializationPathUtil.relative(matchedRoot, normalizedFilePath);
95
+ return SerializationPathUtil.join(generatedRootAbs, rel);
95
96
  }
96
97
 
97
98
  // 否则直接放在 generated 根下,保持文件名
98
- return SerializationPathUtil.join(generatedRootAbs, SerializationPathUtil.basename(normalizedFilePath))
99
+ return SerializationPathUtil.join(generatedRootAbs, SerializationPathUtil.basename(normalizedFilePath));
99
100
  }
100
101
 
101
102
  getOutputRoot(): string {
102
- const moduleRoot = this.context.moduleContext.getModulePath()
103
- const absolutePath = SerializationPathUtil.pathResolve(moduleRoot, this.GENERATED_ROOT)
104
- return SerializationPathUtil.normalize(absolutePath)
103
+ const moduleRoot = this.context.moduleContext.getModulePath();
104
+ const absolutePath = SerializationPathUtil.pathResolve(moduleRoot, this.GENERATED_ROOT);
105
+ return SerializationPathUtil.normalize(absolutePath);
105
106
  }
106
107
 
107
108
  getRelativePath(absolutePath: string): string {
108
- const outputRoot = this.getOutputRoot()
109
+ const outputRoot = this.getOutputRoot();
109
110
  // 从输出根目录推断项目根目录
110
111
  // 假设输出根目录为: <module>/src/generated
111
- const moduleRoot = SerializationPathUtil.dirname(SerializationPathUtil.dirname(outputRoot))
112
+ const moduleRoot = SerializationPathUtil.dirname(SerializationPathUtil.dirname(outputRoot));
112
113
 
113
114
  try {
114
- return SerializationPathUtil.relative(moduleRoot, absolutePath).replaceAll(SerializationPathUtil.sep, '/')
115
+ return SerializationPathUtil.relative(moduleRoot, absolutePath).replaceAll(SerializationPathUtil.sep, '/');
115
116
  } catch (error) {
116
117
  // 如果相对路径计算失败,返回原路径
117
- return absolutePath
118
+ return absolutePath;
118
119
  }
119
120
  }
120
121
 
121
122
  isValidOutputPath(outputPath: string): boolean {
122
123
  try {
123
- const outputRoot = this.getOutputRoot()
124
- const resolvedOutputPath = SerializationPathUtil.pathResolve(outputPath)
125
- const resolvedOutputRoot = SerializationPathUtil.pathResolve(outputRoot)
124
+ const outputRoot = this.getOutputRoot();
125
+ const resolvedOutputPath = SerializationPathUtil.pathResolve(outputPath);
126
+ const resolvedOutputRoot = SerializationPathUtil.pathResolve(outputRoot);
126
127
 
127
128
  // 检查输出路径是否在输出根目录下
128
- return resolvedOutputPath.startsWith(resolvedOutputRoot)
129
+ return resolvedOutputPath.startsWith(resolvedOutputRoot);
129
130
  } catch (error) {
130
- return false
131
+ return false;
131
132
  }
132
133
  }
133
134
 
134
135
  ensureOutputDirectory(outputPath: string): void {
135
- SerializationPathUtil.ensureDirSync(SerializationPathUtil.dirname(outputPath))
136
+ SerializationPathUtil.ensureDirSync(SerializationPathUtil.dirname(outputPath));
136
137
  }
137
138
 
138
139
  calculateSourceRootToModuleRoot(absolutePath: string): string {
139
140
  // 处理Windows环境路径兼容性
140
- const normalizedAbsolutePath = absolutePath.replaceAll(SerializationPathUtil.sep, '/')
141
+ const normalizedAbsolutePath = absolutePath.replaceAll(SerializationPathUtil.sep, '/');
141
142
 
142
143
  // 获取所有源根路径并标准化为统一格式(以 / 结尾)
143
144
  const sourceRoots = this.getAbsoluteSourceRoots().map(root =>
144
145
  root.replaceAll(SerializationPathUtil.sep, '/').replace(/\/$/, '') + '/'
145
- )
146
+ );
146
147
 
147
148
  // 找到匹配的源根路径
148
- const sourceRoot = sourceRoots.find(root => normalizedAbsolutePath.startsWith(root))
149
+ const sourceRoot = sourceRoots.find(root => normalizedAbsolutePath.startsWith(root));
149
150
 
150
151
  if (!sourceRoot) {
151
- throw new CustomError(`无法找到匹配的源根路径: ${normalizedAbsolutePath}。可用的源根路径: ${sourceRoots.join(', ')}`, ErrorCodes.ROOT_DIRECTROY_NOT_FOUND)
152
+ throw new CustomError(
153
+ `无法找到匹配的源根路径: ${normalizedAbsolutePath}。可用的源根路径: ${sourceRoots.join(', ')}`,
154
+ ErrorCodes.ROOT_DIRECTROY_NOT_FOUND);
152
155
  }
153
156
 
154
157
  // 计算相对路径,移除源根路径的尾部分隔符进行计算
155
- const sourceRootForRelative = sourceRoot.replace(/\/$/, '')
156
- const absolutePathForRelative = normalizedAbsolutePath.replace(/\/$/, '')
158
+ const sourceRootForRelative = sourceRoot.replace(/\/$/, '');
159
+ const absolutePathForRelative = normalizedAbsolutePath.replace(/\/$/, '');
157
160
 
158
- return SerializationPathUtil.relative(sourceRootForRelative, absolutePathForRelative).replaceAll(SerializationPathUtil.sep, '/')
161
+ return SerializationPathUtil.relative(sourceRootForRelative, absolutePathForRelative)
162
+ .replaceAll(SerializationPathUtil.sep, '/');
159
163
  }
160
164
 
161
165
  private get targetSourceRoots(): string[] {
162
166
  if (!this.targetOpt.source?.sourceRoots) {
163
- return [this.DEFAULT_SOURCE_ROOT]
167
+ return [this.DEFAULT_SOURCE_ROOT];
164
168
  }
165
169
  // 检查默认路径是否已包含在sourceRoots中
166
170
  if (!this.targetOpt.source.sourceRoots.includes(this.DEFAULT_SOURCE_ROOT)) {
167
- return [this.DEFAULT_SOURCE_ROOT, ...this.targetOpt.source.sourceRoots]
171
+ return [this.DEFAULT_SOURCE_ROOT, ...this.targetOpt.source.sourceRoots];
168
172
  }
169
- return this.targetOpt.source.sourceRoots
173
+ return this.targetOpt.source.sourceRoots;
170
174
  }
171
175
 
172
176
  /**
@@ -177,20 +181,21 @@ export class TargetContextImpl implements ITargetContext {
177
181
  */
178
182
  private getAbsoluteSourceRoots(): string[] {
179
183
  // 获取当前模块的根目录路径
180
- const moduleRoot = this.context.moduleContext.getModulePath()
184
+ const moduleRoot = this.context.moduleContext.getModulePath();
181
185
 
182
186
  // 将每个相对路径源代码根目录转换为绝对路径
183
187
  return this.targetSourceRoots.map((sourceRoot: string) => {
184
188
  // 将相对路径解析为基于模块根目录的绝对路径
185
189
  // path.resolve 会处理相对路径符号(如 ../ ./)
186
- const absolutePath = SerializationPathUtil.pathResolve(moduleRoot, sourceRoot)
190
+ const absolutePath = SerializationPathUtil.pathResolve(moduleRoot, sourceRoot);
187
191
 
188
192
  // 标准化路径格式,确保路径分隔符统一,处理多余的分隔符
189
- const normalizedPath = SerializationPathUtil.normalize(absolutePath)
193
+ const normalizedPath = SerializationPathUtil.normalize(absolutePath);
190
194
 
191
195
  // 确保路径以分隔符结尾,避免路径匹配错误
192
196
  // 例如:/project/src 不会错误匹配 /project/src2
193
- return normalizedPath.endsWith(SerializationPathUtil.sep) ? normalizedPath : normalizedPath + SerializationPathUtil.sep
194
- })
197
+ return normalizedPath.endsWith(SerializationPathUtil.sep) ? normalizedPath :
198
+ normalizedPath + SerializationPathUtil.sep;
199
+ });
195
200
  }
196
201
  }
@@ -13,11 +13,12 @@
13
13
  * limitations under the License.
14
14
  */
15
15
 
16
- import { ITask, Logger, ImportRewriteServiceImpl, ConfigManager, CodeGenerationEngine } from '../../core';
16
+ import {
17
+ ITask, Logger, ImportRewriteServiceImpl, ConfigManager, CodeGenerationEngine, IGenerationResult
18
+ } from '../../core';
17
19
  import { BuildProfileUpdaterImpl } from '../../core/import-rewrite/services/BuildProfileUpdater';
18
20
  import { ITargetContext } from '../interfaces/ITargetContext';
19
- import {logger} from 'handlebars';
20
- import {TaskConstants} from '../constants/TaskConstants';
21
+ import { TaskConstants } from '../constants/TaskConstants';
21
22
  import SerializationPathUtil from '../../core/utils/SerializationPathUtil';
22
23
 
23
24
  export abstract class BaseTask implements ITask {
@@ -39,7 +40,7 @@ export abstract class BaseTask implements ITask {
39
40
  return scanFiles;
40
41
  }
41
42
 
42
- protected processWithLogging(scanFiles: string[], context: ITargetContext, taskName: string) {
43
+ protected processWithLogging(scanFiles: string[], context: ITargetContext, taskName: string): IGenerationResult {
43
44
  Logger.debug(`Start executing ${taskName} and process ${scanFiles.length} files`);
44
45
 
45
46
  this.buildProfileUpdater.updateSourceRoots(context); // 更新builde-profile.json5中的sourceRoot
@@ -19,18 +19,18 @@ import { ITargetContext } from '../interfaces/ITargetContext';
19
19
  import SerializationPathUtil from '../../core/utils/SerializationPathUtil';
20
20
 
21
21
  export class CleanTask implements ITask {
22
- readonly taskName: string = TaskConstants.CLEAN_TASK
23
- readonly dependencies: string[] = [] // CLI任务无依赖
24
- readonly postDependencies: string[] = [] // CLI任务无依赖
22
+ readonly taskName: string = TaskConstants.CLEAN_TASK;
23
+ readonly dependencies: string[] = []; // CLI任务无依赖
24
+ readonly postDependencies: string[] = []; // CLI任务无依赖
25
25
 
26
26
  run(context: ITargetContext): void {
27
- Logger.info('Start the code cleaning task')
27
+ Logger.info('Start the code cleaning task');
28
28
 
29
- const generatedRootDir = context.getOutputRoot()
29
+ const generatedRootDir: string = context.getOutputRoot();
30
30
 
31
31
  if (SerializationPathUtil.exist(generatedRootDir)) {
32
- Logger.info(`Clean up the generated directory: ${generatedRootDir}`)
33
- SerializationPathUtil.rmSync(generatedRootDir, { recursive: true, force: true })
32
+ Logger.info(`Clean up the generated directory: ${generatedRootDir}`);
33
+ SerializationPathUtil.rmSync(generatedRootDir, { recursive: true, force: true });
34
34
  }
35
35
  }
36
36
  }
@@ -55,45 +55,47 @@ export class WatchTask extends BaseTask {
55
55
  }
56
56
 
57
57
  private setupWatchEvents(context: ITargetContext): void {
58
- if (!this.watcher) return
58
+ if (!this.watcher) {
59
+ return;
60
+ }
59
61
 
60
- let debounceTimer: NodeJS.Timeout | null = null
62
+ let debounceTimer: NodeJS.Timeout | null = null;
61
63
 
62
64
  // 防抖处理,避免频繁触发
63
- const debouncedGenerate = (filePath: string) => {
65
+ const debouncedGenerate: (filePath: string) => void = (filePath: string) => {
64
66
  if (debounceTimer) {
65
- clearTimeout(debounceTimer)
67
+ clearTimeout(debounceTimer);
66
68
  }
67
69
  debounceTimer = setTimeout(() => {
68
- this.generateCode(filePath, context)
69
- }, 500) // 500ms 防抖
70
- }
70
+ this.generateCode(filePath, context);
71
+ }, 500); // 500ms 防抖
72
+ };
71
73
 
72
74
  this.watcher
73
75
  .on('add', (filePath: string) => {
74
- Logger.info(`New file detected: ${filePath}`)
75
- debouncedGenerate(filePath)
76
+ Logger.info(`New file detected: ${filePath}`);
77
+ debouncedGenerate(filePath);
76
78
  })
77
79
  .on('change', (filePath: string) => {
78
- Logger.info(`File change detected: ${filePath}`)
79
- debouncedGenerate(filePath)
80
+ Logger.info(`File change detected: ${filePath}`);
81
+ debouncedGenerate(filePath);
80
82
  })
81
83
  .on('unlink', (filePath: string) => {
82
- Logger.info(`File deletion detected: ${filePath}`)
83
- debouncedGenerate(filePath)
84
+ Logger.info(`File deletion detected: ${filePath}`);
85
+ debouncedGenerate(filePath);
84
86
  })
85
87
  .on('error', (error: unknown) => {
86
- Logger.error(`File monitoring error: ${error}`)
88
+ Logger.error(`File monitoring error: ${error}`);
87
89
  })
88
90
  .on('ready', () => {
89
- Logger.info('The initial file scan is complete. Start listening for file changes...')
90
- })
91
+ Logger.info('The initial file scan is complete. Start listening for file changes...');
92
+ });
91
93
  }
92
94
 
93
95
  private generateCode(scanFile: string, context: ITargetContext): void {
94
96
  // 统一处理:逐文件分析 → 直接生成
95
- const processingResult = this.engine.processFileUnified(scanFile, context)
97
+ const processingResult = this.engine.processFileUnified(scanFile, context);
96
98
 
97
- Logger.info(`The code generation is complete, and the output path is ${processingResult?.outputPath}`)
99
+ Logger.info(`The code generation is complete, and the output path is ${processingResult?.outputPath}`);
98
100
  }
99
101
  }
@@ -7,13 +7,13 @@ deserialize(decoder: Decoder, plain: ESObject): {{class.className}}{{#if class.g
7
7
  const result = new {{class.className}}{{#if class.generics.isGeneric}}<{{genericParametersString class.generics.parameters}}>{{/if}}(
8
8
  {{#each (getCtorProperties class.constructorParams properties)}}
9
9
  {{#unless analysis.decorators.isTransient}}
10
- {{#if (and (eqPrimitiveType analysis.type.kind) (not (hasDecoratorWith analysis.decorators)))}}decoder.{{serializer.decodeMethod}}(plain[keys[{{getPropertyIndex this ../properties}}]]){{else}}this.{{analysis.name}}Serializer.deserialize(decoder, plain[keys[{{getPropertyIndex this ../properties}}]]){{/if}}{{#if serializer.needsTypeAssertion}} as {{analysis.type.sourceText}}{{/if}}{{#unless @last}},{{/unless}}
10
+ {{#if analysis.decorators.isPlainValue}}plain[keys[{{getPropertyIndex this ../properties}}]]{{else}}{{#if (and (eqPrimitiveType analysis.type.kind) (not (hasDecoratorWith analysis.decorators)))}}decoder.{{serializer.decodeMethod}}(plain[keys[{{getPropertyIndex this ../properties}}]]){{else}}this.{{getSerializer analysis}}.deserialize(decoder, plain[keys[{{getPropertyIndex this ../properties}}]]){{/if}}{{#if serializer.needsTypeAssertion}} as {{analysis.type.sourceText}}{{/if}}{{/if}}{{#unless @last}},{{/unless}}
11
11
  {{/unless}}
12
12
  {{/each}});
13
13
  {{else}}
14
14
  const result: ESObject = {};
15
15
  {{/if}}
16
-
16
+
17
17
 
18
18
  {{! 可选属性赋值(构造函数外的属性)}}
19
19
  {{#each (postConstructorAssignments class.constructorParams properties)}}
@@ -21,12 +21,22 @@ deserialize(decoder: Decoder, plain: ESObject): {{class.className}}{{#if class.g
21
21
  const {{analysis.name}}PlainValue: ESObject = plain[keys[{{getPropertyIndex this ../properties}}]];
22
22
  {{#if analysis.defaultValue}}
23
23
  {{! 有默认值的属性 }}
24
+ {{#if (eq analysis.visibility "private")}}
25
+ ObjectUtils.setProp(result, '{{analysis.name}}', {{analysis.name}}PlainValue === undefined ? {{analysis.defaultValue}} :
26
+ {{#if analysis.decorators.isPlainValue}}plain[keys[{{getPropertyIndex this ../properties}}]]{{else}}{{#if (and (eqPrimitiveType analysis.type.kind) (not (hasDecoratorWith analysis.decorators)))}}decoder.{{serializer.decodeMethod}}(plain[keys[{{getPropertyIndex this ../properties}}]]){{else}}this.{{getSerializer analysis}}.deserialize(decoder, plain[keys[{{getPropertyIndex this ../properties}}]]){{/if}}{{#if serializer.needsTypeAssertion}} as {{analysis.type.sourceText}}{{/if}}{{/if}});
27
+ {{else}}
24
28
  result.{{analysis.name}} = {{analysis.name}}PlainValue === undefined ? {{analysis.defaultValue}} :
25
- {{#if (and (eqPrimitiveType analysis.type.kind) (not (hasDecoratorWith analysis.decorators)))}}decoder.{{serializer.decodeMethod}}(plain[keys[{{getPropertyIndex this ../properties}}]]){{else}}this.{{analysis.name}}Serializer.deserialize(decoder, plain[keys[{{getPropertyIndex this ../properties}}]]){{/if}}{{#if serializer.needsTypeAssertion}} as {{analysis.type.sourceText}}{{/if}};
29
+ {{#if analysis.decorators.isPlainValue}}plain[keys[{{getPropertyIndex this ../properties}}]]{{else}}{{#if (and (eqPrimitiveType analysis.type.kind) (not (hasDecoratorWith analysis.decorators)))}}decoder.{{serializer.decodeMethod}}(plain[keys[{{getPropertyIndex this ../properties}}]]){{else}}this.{{getSerializer analysis}}.deserialize(decoder, plain[keys[{{getPropertyIndex this ../properties}}]]){{/if}}{{#if serializer.needsTypeAssertion}} as {{analysis.type.sourceText}}{{/if}}{{/if}};
30
+ {{/if}}
26
31
  {{else}}
27
32
  {{! 无默认值的属性 }}
33
+ {{#if (eq analysis.visibility "private")}}
34
+ ObjectUtils.setProp(result, '{{analysis.name}}', {{analysis.name}}PlainValue === undefined ? undefined :
35
+ {{#if analysis.decorators.isPlainValue}}plain[keys[{{getPropertyIndex this ../properties}}]]{{else}}{{#if (and (eqPrimitiveType analysis.type.kind) (not (hasDecoratorWith analysis.decorators)))}}decoder.{{serializer.decodeMethod}}(plain[keys[{{getPropertyIndex this ../properties}}]]){{else}}this.{{getSerializer analysis}}.deserialize(decoder, plain[keys[{{getPropertyIndex this ../properties}}]]){{/if}}{{#if serializer.needsTypeAssertion}} as {{analysis.type.sourceText}}{{/if}}{{/if}});
36
+ {{else}}
28
37
  result.{{analysis.name}} = {{analysis.name}}PlainValue === undefined ? undefined :
29
- {{#if (and (eqPrimitiveType analysis.type.kind) (not (hasDecoratorWith analysis.decorators)))}}decoder.{{serializer.decodeMethod}}(plain[keys[{{getPropertyIndex this ../properties}}]]){{else}}this.{{analysis.name}}Serializer.deserialize(decoder, plain[keys[{{getPropertyIndex this ../properties}}]]){{/if}}{{#if serializer.needsTypeAssertion}} as {{analysis.type.sourceText}}{{/if}};
38
+ {{#if analysis.decorators.isPlainValue}}plain[keys[{{getPropertyIndex this ../properties}}]]{{else}}{{#if (and (eqPrimitiveType analysis.type.kind) (not (hasDecoratorWith analysis.decorators)))}}decoder.{{serializer.decodeMethod}}(plain[keys[{{getPropertyIndex this ../properties}}]]){{else}}this.{{getSerializer analysis}}.deserialize(decoder, plain[keys[{{getPropertyIndex this ../properties}}]]){{/if}}{{#if serializer.needsTypeAssertion}} as {{analysis.type.sourceText}}{{/if}}{{/if}};
39
+ {{/if}}
30
40
  {{/if}}
31
41
  {{/unless}}
32
42
  {{/each}}
@@ -27,10 +27,14 @@ deserialize(decoder: Decoder, plain: ESObject): {{class.className}}{{#if class.g
27
27
  {{#each properties}}
28
28
  case {{@index}}:
29
29
  {{analysis.name}}Seen = true;
30
+ {{#if analysis.decorators.isPlainValue}}
31
+ {{analysis.name}}Value = value;
32
+ {{else}}
30
33
  {{#if (and (eqPrimitiveType analysis.type.kind) (not (hasDecoratorWith analysis.decorators)))}}
31
34
  {{analysis.name}}Value = decoder.{{serializer.decodeMethod}}(value);
32
35
  {{else}}
33
- {{analysis.name}}Value = this.{{analysis.name}}Serializer.deserialize(decoder, value){{#if serializer.needsTypeAssertion}} as {{analysis.type.sourceText}}{{/if}};
36
+ {{analysis.name}}Value = this.{{getSerializer analysis}}.deserialize(decoder, value){{#if serializer.needsTypeAssertion}} as {{analysis.type.sourceText}}{{/if}};
37
+ {{/if}}
34
38
  {{/if}}
35
39
  break;
36
40
  {{/each}}
@@ -80,7 +84,11 @@ deserialize(decoder: Decoder, plain: ESObject): {{class.className}}{{#if class.g
80
84
  {{#each (postConstructorAssignments class.constructorParams properties)}}
81
85
  {{#unless analysis.decorators.isTransient}}
82
86
  if ({{analysis.name}}Seen) {
87
+ {{#if (eq analysis.visibility "private")}}
88
+ ObjectUtils.setProp(result, '{{analysis.name}}', {{analysis.name}}Value!{{#if serializer.needsTypeAssertion}} as {{analysis.type.sourceText}}{{/if}});
89
+ {{else}}
83
90
  result.{{analysis.name}} = {{analysis.name}}Value!{{#if serializer.needsTypeAssertion}} as {{analysis.type.sourceText}}{{/if}};
91
+ {{/if}}
84
92
  }
85
93
  {{/unless}}
86
94
  {{/each}}
@@ -14,11 +14,15 @@ export class {{class.className}}Serializer<{{genericParametersString class.gener
14
14
  {{! 属性序列化器声明 }}
15
15
  {{#each properties}}
16
16
  {{#unless (eqPrimitiveType analysis.type.kind)}}
17
- private readonly {{analysis.name}}Serializer: {{serializer.typeDeclaration}};
17
+ private get{{toUpperCase analysis.name}}Serializer: () => {{serializer.typeDeclaration}};
18
18
  {{/unless}}
19
19
  {{/each}}
20
20
 
21
- readonly serialDescriptor: SerialDescriptor;
21
+ private getSerialDescriptor: () => SerialDescriptor;
22
+
23
+ get serialDescriptor(): SerialDescriptor {
24
+ return this.getSerialDescriptor();
25
+ }
22
26
 
23
27
  constructor(
24
28
  {{#each class.generics.parameters}}
@@ -29,39 +33,37 @@ export class {{class.className}}Serializer<{{genericParametersString class.gener
29
33
  {{! 初始化属性序列化器 }}
30
34
  {{#each properties}}
31
35
  {{#unless (eqPrimitiveType analysis.type.kind)}}
32
- this.{{analysis.name}}Serializer = {{serializer.instantiationTemplate}};
36
+ this.get{{toUpperCase analysis.name}}Serializer = () => {
37
+ const serializer: {{serializer.typeDeclaration}} = {{serializer.instantiationTemplate}};
38
+ this.get{{toUpperCase analysis.name}}Serializer = () => serializer;
39
+ return serializer;
40
+ };
33
41
  {{/unless}}
34
42
  {{/each}}
35
43
 
36
- this.serialDescriptor = buildClassSerialDescriptor(
37
- {{class.className}}_SERIAL_NAME,
38
- builder => {
39
- {{#each properties}}
40
- {{! 处理数字属性名的特殊情况 }}
41
- {{#if (isNumericPropertyName (formatPropertyName analysis))}}
42
- builder.element({
43
- elementName: '{{formatPropertyName analysis}}',
44
- elementDecodingName: this.fixNonNegativeIntegerElementName('{{formatPropertyName analysis}}'),
45
- descriptor:
46
- {{#if (eqPrimitiveType analysis.type.kind)}}
47
- {{serializer.name}}.INSTANCE.serialDescriptor
48
- {{else}}
49
- this.{{analysis.name}}Serializer.serialDescriptor
50
- {{/if}}
51
- });
52
- {{else}}
53
- builder.element({
54
- elementName: '{{formatPropertyName analysis}}',
55
- descriptor:
56
- {{#if (eqPrimitiveType analysis.type.kind)}}
57
- {{serializer.name}}.INSTANCE.serialDescriptor
58
- {{else}}
59
- this.{{analysis.name}}Serializer.serialDescriptor
44
+ this.getSerialDescriptor = () => {
45
+ const descriptor: SerialDescriptor = buildClassSerialDescriptor(
46
+ {{class.className}}_SERIAL_NAME,
47
+ builder => {
48
+ {{#each properties}}
49
+ {{! 处理数字属性名的特殊情况 }}
50
+ builder.element({
51
+ elementName: '{{formatPropertyName analysis}}',
52
+ {{#if (isNumericPropertyName (formatPropertyName analysis))}}
53
+ elementDecodingName: this.fixNonNegativeIntegerElementName('{{formatPropertyName analysis}}'),
60
54
  {{/if}}
61
- });
62
- {{/if}}
63
- {{/each}}
64
- });
55
+ descriptor:
56
+ {{#if (eqPrimitiveType analysis.type.kind)}}
57
+ {{serializer.name}}.INSTANCE.serialDescriptor
58
+ {{else}}
59
+ lazy(() => this.{{getSerializer analysis}}.serialDescriptor)
60
+ {{/if}}
61
+ });
62
+ {{/each}}
63
+ });
64
+ this.getSerialDescriptor = () => descriptor;
65
+ return descriptor;
66
+ }
65
67
  }
66
68
  {{else}}
67
69
  {{! 非泛型类:单例模式 }}
@@ -78,30 +80,45 @@ export class {{class.className}}Serializer extends Serializer<{{class.className}
78
80
 
79
81
  {{! 属性序列化器声明 }}
80
82
  {{#each properties}}
83
+ {{#if (eqPrimitiveType analysis.type.kind)}}
81
84
  private readonly {{analysis.name}}Serializer: {{serializer.typeDeclaration}} = {{serializer.instantiationTemplate}};
85
+ {{else}}
86
+ private get{{toUpperCase analysis.name}}Serializer: () => {{serializer.typeDeclaration}} = () => {
87
+ const serializer: {{serializer.typeDeclaration}} = {{serializer.instantiationTemplate}};
88
+ this.get{{toUpperCase analysis.name}}Serializer = () => serializer;
89
+ return serializer;
90
+ };
91
+ {{/if}}
82
92
  {{/each}}
83
93
 
84
94
  {{! 序列描述符构建 }}
85
- readonly serialDescriptor: SerialDescriptor = buildClassSerialDescriptor(
95
+ private getSerialDescriptor: () => SerialDescriptor = () => {
96
+ const descriptor: SerialDescriptor = buildClassSerialDescriptor(
86
97
  {{class.className}}_SERIAL_NAME,
87
98
  builder => {
88
99
  {{#each properties}}
89
- {{! 处理数字属性名的特殊情况 }}
90
- {{#if (isNumericPropertyName (formatPropertyName analysis))}}
91
100
  builder.element({
92
101
  elementName: '{{formatPropertyName analysis}}',
102
+ {{! 处理数字属性名的特殊情况 }}
103
+ {{#if (isNumericPropertyName (formatPropertyName analysis))}}
93
104
  elementDecodingName: this.fixNonNegativeIntegerElementName('{{formatPropertyName analysis}}'),
105
+ {{/if}}
106
+ {{#if (eqPrimitiveType analysis.type.kind)}}
94
107
  descriptor: this.{{analysis.name}}Serializer.serialDescriptor
108
+ {{else}}
109
+ descriptor: lazy(() => this.{{getSerializer analysis}}.serialDescriptor)
110
+ {{/if}}
95
111
  });
96
- {{else}}
97
- builder.element({
98
- elementName: '{{formatPropertyName analysis}}',
99
- descriptor: this.{{analysis.name}}Serializer.serialDescriptor
100
- });
101
- {{/if}}
102
112
  {{/each}}
103
113
  }
104
114
  )
115
+ this.getSerialDescriptor = () => descriptor;
116
+ return descriptor;
117
+ }
118
+
119
+ get serialDescriptor(): SerialDescriptor {
120
+ return this.getSerialDescriptor();
121
+ }
105
122
 
106
123
  private constructor() {
107
124
  super();
@@ -121,21 +138,29 @@ export class {{class.className}}Serializer extends Serializer<{{class.className}
121
138
  {{/if}}
122
139
  }
123
140
 
124
- private innerSerialize(encoder: Encoder, value: {{#if class.generics.isGeneric}}{{class.className}}<{{genericParametersString class.generics.parameters}}>{{else}}{{class.className}}{{/if}}): ESObject {
141
+ private innerSerialize(encoder: Encoder, value: {{#if class.generics.isGeneric}}{{class.className}}<{{genericParametersString class.generics.parameters}}>{{else}}{{class.className}}{{/if}}): ESObject {
125
142
  const keys = this.serialDescriptor.elementNames;
126
143
  const result = encoder.newObject();
127
144
  {{#each properties}}
128
- {{! 根据类型选择编码方法 }}
129
- {{#if (and (eqPrimitiveType analysis.type.kind) (not (hasDecoratorWith analysis.decorators)))}}
130
- encoder.{{serializer.encodeMethod}}(result, keys[{{@index}}], value.{{analysis.name}});
145
+ {{! 根据类型选择编码方法 }}
146
+ {{#if (eq analysis.visibility "private")}}
147
+ {{#if (and (eqPrimitiveType analysis.type.kind) (not (hasDecoratorWith analysis.decorators)))}}
148
+ encoder.{{serializer.encodeMethod}}(result, keys[{{@index}}], ObjectUtils.getProp(value, '{{analysis.name}}'));
149
+ {{else}}
150
+ encoder.encodeSerializableElement(result, keys[{{@index}}], this.{{getSerializer analysis}}, ObjectUtils.getProp(value, '{{analysis.name}}'));
151
+ {{/if}}
131
152
  {{else}}
132
- encoder.encodeSerializableElement(result, keys[{{@index}}], this.{{analysis.name}}Serializer, value.{{analysis.name}});
153
+ {{#if (and (eqPrimitiveType analysis.type.kind) (not (hasDecoratorWith analysis.decorators)))}}
154
+ encoder.{{serializer.encodeMethod}}(result, keys[{{@index}}], value.{{analysis.name}});
155
+ {{else}}
156
+ encoder.encodeSerializableElement(result, keys[{{@index}}], this.{{getSerializer analysis}}, value.{{analysis.name}});
157
+ {{/if}}
133
158
  {{/if}}
134
159
  {{/each}}
135
160
 
136
161
  return result;
137
162
  }
138
-
163
+
139
164
  {{! 动态包含反序列化模板 - 使用从上下文传递的deserializeTemplate参数 }}
140
165
  {{> (lookup . "deserializeTemplate")}}
141
166
  }