@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.
- package/README.md +1 -1
- package/dist/core/Types.d.ts +7 -0
- package/dist/core/Types.js +7 -1
- package/dist/core/analyzers/ClassAnalyzer.d.ts +15 -0
- package/dist/core/analyzers/ClassAnalyzer.js +200 -120
- package/dist/core/analyzers/CustomTypeAnalyzer.d.ts +3 -0
- package/dist/core/analyzers/CustomTypeAnalyzer.js +65 -60
- package/dist/core/constants/DecoratorConstants.d.ts +1 -0
- package/dist/core/constants/DecoratorConstants.js +3 -1
- package/dist/core/handlers/CustomClassHandler.js +0 -1
- package/dist/core/import-rewrite/services/BuildProfileUpdater.js +1 -1
- package/dist/core/import-rewrite/services/ImportRewriteService.js +1 -1
- package/dist/core/interfaces/index.d.ts +2 -2
- package/dist/core/services/CodeAnalysisService.js +2 -1
- package/dist/core/services/CodeGenerationService/CodeGenerationService.js +1 -1
- package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.d.ts +0 -1
- package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.js +0 -20
- package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.d.ts +4 -4
- package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.js +26 -45
- package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.d.ts +22 -0
- package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.js +194 -129
- package/dist/core/services/CodeGenerationService/generators/SerializerGenerator.js +20 -15
- package/dist/core/services/CodeGenerationService/generators/TempSerializerGenerator.js +2 -1
- package/dist/core/services/CodeGenerationService/shared/ImportManager.d.ts +2 -2
- package/dist/core/template/HandlebarsTemplateEngine.d.ts +2 -0
- package/dist/core/template/HandlebarsTemplateEngine.js +24 -2
- package/dist/core/utils/DeepCopyUtil.js +4 -2
- package/dist/core/utils/GenericTypeSubstitutionUtil.d.ts +1 -0
- package/dist/core/utils/GenericTypeSubstitutionUtil.js +27 -1
- package/dist/core/utils/SerializationPathUtil.d.ts +1 -1
- package/dist/core/utils/TsMorphUtil.js +6 -1
- package/dist/json-plugin/JSONExecuteController.d.ts +4 -0
- package/dist/json-plugin/JSONExecuteController.js +46 -36
- package/dist/json-plugin/interfaces/impl/TargetContext.js +4 -2
- package/dist/json-plugin/tasks/BaseTask.d.ts +2 -2
- package/dist/json-plugin/tasks/WatchTask.js +2 -1
- package/package.json +1 -1
- package/src/core/Types.ts +97 -89
- package/src/core/analyzers/ClassAnalyzer.ts +358 -197
- package/src/core/analyzers/CustomTypeAnalyzer.ts +145 -74
- package/src/core/constants/DecoratorConstants.ts +7 -5
- package/src/core/constants/PathConstants.ts +7 -7
- package/src/core/constants/StringConstants.ts +95 -97
- package/src/core/handlers/BaseTypeHandler.ts +11 -2
- package/src/core/handlers/CustomClassHandler.ts +4 -7
- package/src/core/handlers/DateHandler.ts +54 -46
- package/src/core/handlers/DecimalHandler.ts +53 -45
- package/src/core/handlers/EnumHandler.ts +2 -1
- package/src/core/handlers/GenericContainerHandler.ts +3 -1
- package/src/core/handlers/TupleHandler.ts +2 -1
- package/src/core/handlers/TypeHandlerRegistry.ts +3 -2
- package/src/core/handlers/UnionTypeHandler.ts +8 -7
- package/src/core/import-rewrite/services/BuildProfileUpdater.ts +7 -5
- package/src/core/import-rewrite/services/ImportRewriteService.ts +1 -3
- package/src/core/import-rewrite/services/ImportTransformService.ts +2 -2
- package/src/core/import-rewrite/types/ImportRewriteTypes.ts +3 -3
- package/src/core/index.ts +4 -4
- package/src/core/interfaces/ITask.ts +6 -5
- package/src/core/interfaces/ITaskContext.ts +9 -9
- package/src/core/interfaces/index.ts +2 -2
- package/src/core/logger/Logger.ts +28 -28
- package/src/core/services/CodeAnalysisService.ts +3 -2
- package/src/core/services/CodeGenerationEngine.ts +42 -42
- package/src/core/services/CodeGenerationService/CodeGenerationService.ts +1 -2
- package/src/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.ts +0 -29
- package/src/core/services/CodeGenerationService/generators/OriginalClassGenerator.ts +31 -64
- package/src/core/services/CodeGenerationService/generators/SendableClassGenerator.ts +261 -170
- package/src/core/services/CodeGenerationService/generators/SerializerGenerator.ts +26 -19
- package/src/core/services/CodeGenerationService/generators/TempSerializerGenerator.ts +5 -3
- package/src/core/services/CodeGenerationService/shared/ImportManager.ts +8 -8
- package/src/core/template/HandlebarsTemplateEngine.ts +43 -10
- package/src/core/utils/ConfigManager.ts +2 -1
- package/src/core/utils/DeepCopyUtil.ts +4 -2
- package/src/core/utils/GenericTypeSubstitutionUtil.ts +45 -2
- package/src/core/utils/SerializationPathUtil.ts +7 -6
- package/src/core/utils/TsMorphUtil.ts +9 -2
- package/src/index.ts +2 -2
- package/src/json-plugin/JSONExecuteController.ts +51 -38
- package/src/json-plugin/interfaces/IModuleContext.ts +8 -8
- package/src/json-plugin/interfaces/ITargetContext.ts +6 -6
- package/src/json-plugin/interfaces/impl/ModuleContext.ts +10 -10
- package/src/json-plugin/interfaces/impl/TargetContext.ts +63 -58
- package/src/json-plugin/tasks/BaseTask.ts +5 -4
- package/src/json-plugin/tasks/CleanTask.ts +7 -7
- package/src/json-plugin/tasks/WatchTask.ts +20 -18
- package/template/SerializerPerformanceTemplate.hbs +14 -4
- package/template/SerializerStrictTemplate.hbs +9 -1
- 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(
|
|
81
|
-
|
|
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(
|
|
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)
|
|
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 :
|
|
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 {
|
|
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 {
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
17
|
+
private get{{toUpperCase analysis.name}}Serializer: () => {{serializer.typeDeclaration}};
|
|
18
18
|
{{/unless}}
|
|
19
19
|
{{/each}}
|
|
20
20
|
|
|
21
|
-
|
|
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 = {
|
|
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.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
{
|
|
40
|
-
{{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
63
|
-
|
|
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
|
-
|
|
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 (
|
|
130
|
-
|
|
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
|
-
|
|
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
|
}
|