@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.
- package/dist/core/analyzers/ClassAnalyzer.d.ts +15 -0
- package/dist/core/analyzers/ClassAnalyzer.js +193 -144
- package/dist/core/analyzers/CustomTypeAnalyzer.d.ts +3 -0
- package/dist/core/analyzers/CustomTypeAnalyzer.js +65 -60
- package/dist/core/constants/DecoratorConstants.js +2 -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/generators/OriginalClassGenerator.d.ts +2 -0
- package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.js +22 -15
- 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 +1 -1
- 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 +21 -2
- package/dist/core/utils/DeepCopyUtil.js +1 -1
- package/dist/core/utils/SerializationPathUtil.d.ts +1 -1
- package/dist/core/utils/TsMorphUtil.js +2 -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 +90 -90
- package/src/core/analyzers/ClassAnalyzer.ts +335 -230
- package/src/core/analyzers/CustomTypeAnalyzer.ts +145 -73
- package/src/core/constants/DecoratorConstants.ts +7 -6
- package/src/core/constants/PathConstants.ts +7 -7
- package/src/core/constants/StringConstants.ts +95 -95
- package/src/core/handlers/BaseTypeHandler.ts +11 -2
- package/src/core/handlers/CustomClassHandler.ts +4 -4
- 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 +2 -1
- package/src/core/handlers/UnionTypeHandler.ts +8 -7
- package/src/core/import-rewrite/services/BuildProfileUpdater.ts +6 -4
- package/src/core/import-rewrite/services/ImportRewriteService.ts +1 -1
- 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 +2 -1
- package/src/core/services/CodeGenerationEngine.ts +42 -42
- package/src/core/services/CodeGenerationService/generators/OriginalClassGenerator.ts +25 -22
- package/src/core/services/CodeGenerationService/generators/SendableClassGenerator.ts +261 -170
- package/src/core/services/CodeGenerationService/generators/SerializerGenerator.ts +1 -1
- 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 +39 -11
- package/src/core/utils/ConfigManager.ts +2 -1
- package/src/core/utils/DeepCopyUtil.ts +1 -1
- package/src/core/utils/GenericTypeSubstitutionUtil.ts +1 -8
- package/src/core/utils/SerializationPathUtil.ts +7 -6
- package/src/core/utils/TsMorphUtil.ts +4 -1
- 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 -3
- package/src/json-plugin/tasks/CleanTask.ts +7 -7
- package/src/json-plugin/tasks/WatchTask.ts +20 -18
- package/template/SerializerPerformanceTemplate.hbs +5 -5
- package/template/SerializerStrictTemplate.hbs +1 -1
- package/template/SerializerTemplate.hbs +59 -42
|
@@ -15,8 +15,16 @@
|
|
|
15
15
|
|
|
16
16
|
import * as Handlebars from 'handlebars';
|
|
17
17
|
import {
|
|
18
|
-
ClassAnalysis,
|
|
19
|
-
|
|
18
|
+
ClassAnalysis,
|
|
19
|
+
ConstructorParam,
|
|
20
|
+
DecoratorConstants,
|
|
21
|
+
DeserializationMode,
|
|
22
|
+
GenerationContext,
|
|
23
|
+
InterfaceAnalysis,
|
|
24
|
+
PropertyAnalysis,
|
|
25
|
+
PropertyDecorators,
|
|
26
|
+
PropertyGenerationInfo,
|
|
27
|
+
PropertyKind
|
|
20
28
|
} from '..';
|
|
21
29
|
import SerializationPathUtil from '../utils/SerializationPathUtil';
|
|
22
30
|
import { CustomError, ErrorCodes } from '../utils/CustomError';
|
|
@@ -97,14 +105,24 @@ export class HandlebarsTemplateEngine {
|
|
|
97
105
|
this.registerLogicHelpers();
|
|
98
106
|
}
|
|
99
107
|
|
|
108
|
+
private isPrimitiveType(kind: string): boolean {
|
|
109
|
+
return ['string', 'number', 'boolean', 'bigint', 'undefined', 'null'].includes(kind);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private toUpperCase(name: string): string {
|
|
113
|
+
if (!name) {
|
|
114
|
+
return '';
|
|
115
|
+
}
|
|
116
|
+
return name.charAt(0).toUpperCase() + name.substring(1);
|
|
117
|
+
}
|
|
118
|
+
|
|
100
119
|
private registerComparisonHelpers(): void {
|
|
101
120
|
this.registerHelper('eq', (arg1: unknown, arg2: unknown) => {
|
|
102
121
|
return (arg1 === arg2);
|
|
103
122
|
});
|
|
104
123
|
|
|
105
124
|
this.registerHelper('eqPrimitiveType', (kind: string) => {
|
|
106
|
-
|
|
107
|
-
return primitives.includes(kind);
|
|
125
|
+
return this.isPrimitiveType(kind);
|
|
108
126
|
});
|
|
109
127
|
|
|
110
128
|
this.registerHelper('eqEmptyType', (kind: string) => {
|
|
@@ -149,9 +167,7 @@ export class HandlebarsTemplateEngine {
|
|
|
149
167
|
|
|
150
168
|
private hasNonSerializableClassDecorator(classAnalysis: ClassAnalysis): boolean {
|
|
151
169
|
const classDecorators = classAnalysis.originalClass?.getDecorators() || [];
|
|
152
|
-
return classDecorators.some(decorator =>
|
|
153
|
-
decorator.getName() !== 'Serializable'
|
|
154
|
-
);
|
|
170
|
+
return classDecorators.some(decorator => decorator.getName() !== 'Serializable');
|
|
155
171
|
}
|
|
156
172
|
|
|
157
173
|
private hasNonSerializablePropertyDecorators(classAnalysis: ClassAnalysis): boolean {
|
|
@@ -163,9 +179,8 @@ export class HandlebarsTemplateEngine {
|
|
|
163
179
|
for (const prop of props) {
|
|
164
180
|
const decorators = prop.getDecorators();
|
|
165
181
|
if (decorators && Array.isArray(decorators)) {
|
|
166
|
-
const hasNonSerializableDecorator =
|
|
167
|
-
!DecoratorConstants.SERIAL_DECORATORS.includes(decorator.getName())
|
|
168
|
-
);
|
|
182
|
+
const hasNonSerializableDecorator =
|
|
183
|
+
decorators.some(decorator => !DecoratorConstants.SERIAL_DECORATORS.includes(decorator.getName()));
|
|
169
184
|
if (hasNonSerializableDecorator) {
|
|
170
185
|
return true;
|
|
171
186
|
}
|
|
@@ -223,6 +238,18 @@ export class HandlebarsTemplateEngine {
|
|
|
223
238
|
return str.toLowerCase();
|
|
224
239
|
});
|
|
225
240
|
|
|
241
|
+
this.registerHelper('toUpperCase', (str: string) => {
|
|
242
|
+
return this.toUpperCase(str);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
this.registerHelper('getSerializer', (analysis: PropertyAnalysis) => {
|
|
246
|
+
if (this.isPrimitiveType(analysis.type.kind)) {
|
|
247
|
+
return `${analysis.name}Serializer`;
|
|
248
|
+
} else {
|
|
249
|
+
return `get${this.toUpperCase(analysis.name)}Serializer()`;
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
226
253
|
this.registerHelper('genericParametersString', (parameters: string[]) => {
|
|
227
254
|
return parameters.join(', ');
|
|
228
255
|
});
|
|
@@ -233,7 +260,8 @@ export class HandlebarsTemplateEngine {
|
|
|
233
260
|
|
|
234
261
|
// 过滤出泛型类型的属性(用于生成静态方法的泛型序列化器参数)
|
|
235
262
|
this.registerHelper('filterGenericProperties', (properties: PropertyGenerationInfo[]) => {
|
|
236
|
-
return properties.filter(
|
|
263
|
+
return properties.filter(
|
|
264
|
+
p => p.analysis.type.kind === PropertyKind.GENERIC && !p.analysis.decorators?.isTransient);
|
|
237
265
|
});
|
|
238
266
|
}
|
|
239
267
|
|
|
@@ -19,7 +19,8 @@ export class ConfigManager {
|
|
|
19
19
|
private static instance: ConfigManager;
|
|
20
20
|
private config: TurboTransJsonPluginOptions | null = null;
|
|
21
21
|
|
|
22
|
-
private constructor() {
|
|
22
|
+
private constructor() {
|
|
23
|
+
}
|
|
23
24
|
|
|
24
25
|
public static getInstance(): ConfigManager {
|
|
25
26
|
if (!ConfigManager.instance) {
|
|
@@ -175,7 +175,7 @@ export class DeepCopyUtil {
|
|
|
175
175
|
if (typeof obj === 'object') {
|
|
176
176
|
const copy: any = {};
|
|
177
177
|
for (const key in obj) {
|
|
178
|
-
if (
|
|
178
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
179
179
|
copy[key] = this.deepCopy((obj as any)[key]);
|
|
180
180
|
}
|
|
181
181
|
}
|
|
@@ -111,13 +111,6 @@ export class GenericTypeSubstitutionUtil {
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
114
|
// 重新计算依赖信息
|
|
122
115
|
newStructure.dependencies = this.collectDependenciesFromChildren(newStructure);
|
|
123
116
|
|
|
@@ -131,7 +124,7 @@ export class GenericTypeSubstitutionUtil {
|
|
|
131
124
|
return TypeHandlerRegistry.getInstance().parseType(typeNode, {
|
|
132
125
|
depth: 0,
|
|
133
126
|
genericParams: currentClassGenericParams // ✅ 传递当前类的泛型参数上下文
|
|
134
|
-
})
|
|
127
|
+
});
|
|
135
128
|
}
|
|
136
129
|
|
|
137
130
|
/**
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { FileUtil } from '@ohos/hvigor';
|
|
17
|
-
import * as path from
|
|
18
|
-
import * as fs from
|
|
17
|
+
import * as path from 'path';
|
|
18
|
+
import * as fs from 'fs';
|
|
19
19
|
import { ITaskContext, PathConstants } from '..';
|
|
20
20
|
|
|
21
21
|
export default class SerializationPathUtil extends FileUtil {
|
|
@@ -34,11 +34,11 @@ export default class SerializationPathUtil extends FileUtil {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
static isAbsolute(p: string): boolean {
|
|
37
|
-
return path.isAbsolute(p)
|
|
37
|
+
return path.isAbsolute(p);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
static normalize(p: string): string {
|
|
41
|
-
return path.normalize(p)
|
|
41
|
+
return path.normalize(p);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
static relative(from: string, to: string): string {
|
|
@@ -101,7 +101,8 @@ export default class SerializationPathUtil extends FileUtil {
|
|
|
101
101
|
static scanEtsFiles(directory: string): string[] {
|
|
102
102
|
const etsFiles: string[] = [];
|
|
103
103
|
|
|
104
|
-
const deepScanEtsFiles
|
|
104
|
+
const deepScanEtsFiles: (scanPath: string, relativePath: string) => void = (scanPath: string,
|
|
105
|
+
relativePath: string) => {
|
|
105
106
|
let resolvePath = this.pathResolve(scanPath, relativePath);
|
|
106
107
|
|
|
107
108
|
if (!this.exist(resolvePath)) {
|
|
@@ -119,7 +120,7 @@ export default class SerializationPathUtil extends FileUtil {
|
|
|
119
120
|
etsFiles.push(resolvePath);
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
|
-
}
|
|
123
|
+
};
|
|
123
124
|
|
|
124
125
|
deepScanEtsFiles(directory, '');
|
|
125
126
|
|
|
@@ -18,7 +18,10 @@ import { Logger } from '../logger/Logger';
|
|
|
18
18
|
|
|
19
19
|
export class TsMorphUtil {
|
|
20
20
|
public static project: Project | null = null;
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
private constructor() {
|
|
23
|
+
}
|
|
24
|
+
|
|
22
25
|
public static getProject(options?: ProjectOptions): Project {
|
|
23
26
|
if (!this.project) {
|
|
24
27
|
Logger.info('创建ts-morph项目');
|
package/src/index.ts
CHANGED
|
@@ -51,7 +51,7 @@ class TurboTransJSONPluginManager {
|
|
|
51
51
|
return TurboTransJSONPluginManager.instance;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
initialization(node: HvigorNode, options: TurboTransJsonPluginOptions) {
|
|
54
|
+
initialization(node: HvigorNode, options: TurboTransJsonPluginOptions): void {
|
|
55
55
|
initializeTypeHandlers();
|
|
56
56
|
node.subNodes(subNode => {
|
|
57
57
|
const subNodeName = subNode.getNodeName();
|
|
@@ -63,7 +63,7 @@ class TurboTransJSONPluginManager {
|
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
private setupHvigorHooks(hvigor: Hvigor) {
|
|
66
|
+
private setupHvigorHooks(hvigor: Hvigor): void {
|
|
67
67
|
hvigor.nodesEvaluated(() => {
|
|
68
68
|
this.moduleExecuteControllers.forEach(controller => {
|
|
69
69
|
controller.execute();
|
|
@@ -65,7 +65,7 @@ export class JSONExecuteController {
|
|
|
65
65
|
// 编译结束后的清理逻辑由clean任务处理
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
private initTasks() {
|
|
68
|
+
private initTasks(): void {
|
|
69
69
|
this.tasks.add(new CodeProcessingTask());
|
|
70
70
|
this.tasks.add(new CleanTask());
|
|
71
71
|
this.tasks.add(new SyncTask());
|
|
@@ -82,53 +82,66 @@ export class JSONExecuteController {
|
|
|
82
82
|
SendableMergeabilityRegistry.clear();
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
private registerHvigorTasks(target: Target, context: IModuleContext) {
|
|
85
|
+
private registerHvigorTasks(target: Target, context: IModuleContext): void {
|
|
86
86
|
const targetContext = new TargetContextImpl(target, context);
|
|
87
87
|
this.tasks.forEach((task) => {
|
|
88
88
|
this.node.registerTask({
|
|
89
89
|
name: task.taskName,
|
|
90
|
-
run: async () =>
|
|
91
|
-
try {
|
|
92
|
-
Logger.info(`${task.taskName} run`);
|
|
93
|
-
TempSerializerGenerator.getInstance().init(targetContext);
|
|
94
|
-
const result = task.run(targetContext);
|
|
95
|
-
// clean任务不需要生成序列化器
|
|
96
|
-
if (task.taskName !== TaskConstants.CLEAN_TASK) {
|
|
97
|
-
TempSerializerGenerator.getInstance().saveFile();
|
|
98
|
-
}
|
|
99
|
-
if (result instanceof Promise) {
|
|
100
|
-
await result;
|
|
101
|
-
}
|
|
102
|
-
if (task.taskName === TaskConstants.SYNC_TASK || task.taskName === TaskConstants.CODE_PROCESSING_TASK) {
|
|
103
|
-
this.taskCleanUp();
|
|
104
|
-
}
|
|
105
|
-
Logger.info(`${task.taskName} end`);
|
|
106
|
-
} catch (error) {
|
|
107
|
-
if (error instanceof CustomError) {
|
|
108
|
-
Logger.error(`Error: ${error.constructor.name}: ${error.code} ${error.message}\n${error.stack}`);
|
|
109
|
-
} else {
|
|
110
|
-
const err = error as Error;
|
|
111
|
-
Logger.error(`Error: ${err.constructor.name}: ${ErrorCodes.INTERNAL_ERROR} ${err.message}\n${err.stack}`);
|
|
112
|
-
}
|
|
113
|
-
this.taskCleanUp();
|
|
114
|
-
throw new Error('serialization execute failed');
|
|
115
|
-
}
|
|
116
|
-
},
|
|
90
|
+
run: async () => this.runTask(task, targetContext),
|
|
117
91
|
dependencies: task.dependencies.map((dep) => `${target.getTargetName()}@${dep}`),
|
|
118
92
|
postDependencies: task.postDependencies.map((dep) => `${target.getTargetName()}@${dep}`)
|
|
119
93
|
});
|
|
120
94
|
});
|
|
121
95
|
|
|
96
|
+
this.registerCleanTaskHook(targetContext);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private async runTask(task: ITask, targetContext: TargetContextImpl): Promise<void> {
|
|
100
|
+
try {
|
|
101
|
+
Logger.info(`${task.taskName} run`);
|
|
102
|
+
TempSerializerGenerator.getInstance().init(targetContext);
|
|
103
|
+
const result = task.run(targetContext);
|
|
104
|
+
// clean任务不需要生成序列化器
|
|
105
|
+
if (task.taskName !== TaskConstants.CLEAN_TASK) {
|
|
106
|
+
TempSerializerGenerator.getInstance().saveFile();
|
|
107
|
+
}
|
|
108
|
+
if (result instanceof Promise) {
|
|
109
|
+
await result;
|
|
110
|
+
}
|
|
111
|
+
if (task.taskName === TaskConstants.SYNC_TASK || task.taskName === TaskConstants.CODE_PROCESSING_TASK) {
|
|
112
|
+
this.taskCleanUp();
|
|
113
|
+
}
|
|
114
|
+
Logger.info(`${task.taskName} end`);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
this.handleTaskError(error);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private handleTaskError(error: unknown): void {
|
|
121
|
+
if (error instanceof CustomError) {
|
|
122
|
+
Logger.error(`Error: ${error.constructor.name}: ${error.code} ${error.message}\n${error.stack}`);
|
|
123
|
+
} else {
|
|
124
|
+
const err = error as Error;
|
|
125
|
+
Logger.error(`Error: ${err.constructor.name}: ${ErrorCodes.INTERNAL_ERROR} ${err.message}\n${err.stack}`);
|
|
126
|
+
}
|
|
127
|
+
this.taskCleanUp();
|
|
128
|
+
throw new Error('serialization execute failed');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private registerCleanTaskHook(targetContext: TargetContextImpl): void {
|
|
122
132
|
const cleanTask = this.node.getTaskByName('clean');
|
|
123
|
-
if (cleanTask) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
133
|
+
if (!cleanTask) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
cleanTask.beforeRun(() => this.cleanGeneratedDirectory(targetContext));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private cleanGeneratedDirectory(targetContext: TargetContextImpl): void {
|
|
140
|
+
const generatedRootDir = targetContext.getOutputRoot();
|
|
141
|
+
if (!SerializationPathUtil.exist(generatedRootDir)) {
|
|
142
|
+
return;
|
|
132
143
|
}
|
|
144
|
+
Logger.info(`Clean up the generated directory: ${generatedRootDir}`);
|
|
145
|
+
SerializationPathUtil.rmSync(generatedRootDir, { recursive: true, force: true });
|
|
133
146
|
}
|
|
134
147
|
}
|
|
@@ -13,15 +13,15 @@
|
|
|
13
13
|
* limitations under the License.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { HvigorNode } from '@ohos/hvigor'
|
|
17
|
-
import { ModuleBuildProfile } from '@ohos/hvigor-ohos-plugin/src/options/build/module-build-profile'
|
|
18
|
-
import { OhosModuleContext } from '@ohos/hvigor-ohos-plugin/src/plugin/context/plugin-context'
|
|
16
|
+
import { HvigorNode } from '@ohos/hvigor';
|
|
17
|
+
import { ModuleBuildProfile } from '@ohos/hvigor-ohos-plugin/src/options/build/module-build-profile';
|
|
18
|
+
import { OhosModuleContext } from '@ohos/hvigor-ohos-plugin/src/plugin/context/plugin-context';
|
|
19
19
|
|
|
20
20
|
export interface IModuleContext {
|
|
21
|
-
readonly node: HvigorNode
|
|
22
|
-
readonly moduleContext: OhosModuleContext
|
|
23
|
-
readonly buildProfileOpt: ModuleBuildProfile.ModuleBuildOpt
|
|
24
|
-
readonly scanFiles: string[]
|
|
21
|
+
readonly node: HvigorNode;
|
|
22
|
+
readonly moduleContext: OhosModuleContext;
|
|
23
|
+
readonly buildProfileOpt: ModuleBuildProfile.ModuleBuildOpt;
|
|
24
|
+
readonly scanFiles: string[];
|
|
25
25
|
|
|
26
|
-
initScanFiles(scanDir: string[]): void
|
|
26
|
+
initScanFiles(scanDir: string[]): void;
|
|
27
27
|
}
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
* limitations under the License.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { Target } from '@ohos/hvigor-ohos-plugin'
|
|
17
|
-
import { IModuleContext } from './IModuleContext'
|
|
18
|
-
import { ITaskContext } from '../../core'
|
|
16
|
+
import { Target } from '@ohos/hvigor-ohos-plugin';
|
|
17
|
+
import { IModuleContext } from './IModuleContext';
|
|
18
|
+
import { ITaskContext } from '../../core';
|
|
19
19
|
|
|
20
20
|
export interface ITargetContext extends ITaskContext {
|
|
21
|
-
readonly target: Target
|
|
22
|
-
readonly context: IModuleContext
|
|
21
|
+
readonly target: Target;
|
|
22
|
+
readonly context: IModuleContext;
|
|
23
23
|
|
|
24
|
-
getCurrentTargetScanFiles(): string[]
|
|
24
|
+
getCurrentTargetScanFiles(): string[];
|
|
25
25
|
}
|
|
@@ -13,20 +13,20 @@
|
|
|
13
13
|
* limitations under the License.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { HvigorNode } from '@ohos/hvigor'
|
|
17
|
-
import { IModuleContext } from '../IModuleContext'
|
|
16
|
+
import { HvigorNode } from '@ohos/hvigor';
|
|
17
|
+
import { IModuleContext } from '../IModuleContext';
|
|
18
18
|
import SerializationPathUtil from '../../../core/utils/SerializationPathUtil';
|
|
19
19
|
import { OhosHapContext } from '@ohos/hvigor-ohos-plugin';
|
|
20
20
|
import { ModuleBuildProfile } from '@ohos/hvigor-ohos-plugin/src/options/build/module-build-profile';
|
|
21
21
|
|
|
22
22
|
export class ModuleContextImpl implements IModuleContext {
|
|
23
|
-
readonly node: HvigorNode
|
|
24
|
-
readonly moduleContext: OhosHapContext
|
|
25
|
-
readonly scanFiles: string[] = []
|
|
23
|
+
readonly node: HvigorNode;
|
|
24
|
+
readonly moduleContext: OhosHapContext;
|
|
25
|
+
readonly scanFiles: string[] = [];
|
|
26
26
|
|
|
27
27
|
constructor(node: HvigorNode, moduleContext: OhosHapContext) {
|
|
28
|
-
this.node = node
|
|
29
|
-
this.moduleContext = moduleContext
|
|
28
|
+
this.node = node;
|
|
29
|
+
this.moduleContext = moduleContext;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
@@ -38,8 +38,8 @@ export class ModuleContextImpl implements IModuleContext {
|
|
|
38
38
|
|
|
39
39
|
initScanFiles(scanDir: string[]): void {
|
|
40
40
|
scanDir.forEach(dir => {
|
|
41
|
-
const scanPath = SerializationPathUtil.pathResolve(this.moduleContext.getModulePath(), dir)
|
|
42
|
-
this.scanFiles.push(...SerializationPathUtil.scanEtsFiles(scanPath))
|
|
43
|
-
})
|
|
41
|
+
const scanPath = SerializationPathUtil.pathResolve(this.moduleContext.getModulePath(), dir);
|
|
42
|
+
this.scanFiles.push(...SerializationPathUtil.scanEtsFiles(scanPath));
|
|
43
|
+
});
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -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
|
}
|