@hadss/hmrouter-plugin 1.0.0-rc.1 → 1.0.0-rc.11

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 (59) hide show
  1. package/README.md +240 -17
  2. package/dist/HMRouterAnalyzer.d.ts +31 -0
  3. package/dist/HMRouterAnalyzer.js +296 -0
  4. package/dist/HMRouterHvigorPlugin.d.ts +15 -0
  5. package/dist/HMRouterHvigorPlugin.js +143 -0
  6. package/dist/HMRouterPluginConfig.d.ts +39 -0
  7. package/dist/HMRouterPluginConfig.js +74 -0
  8. package/dist/HMRouterPluginHandle.d.ts +23 -0
  9. package/dist/HMRouterPluginHandle.js +222 -0
  10. package/dist/Index.d.ts +4 -0
  11. package/dist/Index.js +128 -0
  12. package/dist/common/Constant.d.ts +27 -0
  13. package/{lib → dist}/common/Constant.js +0 -15
  14. package/dist/common/Logger.d.ts +13 -0
  15. package/{lib → dist}/common/Logger.js +17 -24
  16. package/dist/common/PluginModel.d.ts +50 -0
  17. package/{lib → dist}/common/PluginModel.js +2 -16
  18. package/dist/constants/CommonConstants.d.ts +38 -0
  19. package/dist/constants/CommonConstants.js +45 -0
  20. package/dist/constants/ConfigConstants.d.ts +12 -0
  21. package/dist/constants/ConfigConstants.js +16 -0
  22. package/dist/constants/TaskConstants.d.ts +9 -0
  23. package/dist/constants/TaskConstants.js +13 -0
  24. package/dist/store/PluginStore.d.ts +14 -0
  25. package/dist/store/PluginStore.js +20 -0
  26. package/dist/utils/ConfusionUtil.d.ts +4 -0
  27. package/dist/utils/ConfusionUtil.js +27 -0
  28. package/dist/utils/FileUtil.d.ts +11 -0
  29. package/dist/utils/FileUtil.js +20 -0
  30. package/dist/utils/ObfuscationUtil.d.ts +4 -0
  31. package/dist/utils/ObfuscationUtil.js +34 -0
  32. package/dist/utils/StringUtil.d.ts +3 -0
  33. package/dist/utils/StringUtil.js +18 -0
  34. package/dist/utils/TsAstUtil.d.ts +9 -0
  35. package/dist/utils/TsAstUtil.js +89 -0
  36. package/package.json +26 -12
  37. package/{viewBuilder.tpl → viewBuilder.ejs} +18 -11
  38. package/lib/HMRouterAnalyzer.js +0 -351
  39. package/lib/HMRouterAnalyzer.js.map +0 -1
  40. package/lib/HMRouterHvigorPlugin.js +0 -177
  41. package/lib/HMRouterHvigorPlugin.js.map +0 -1
  42. package/lib/HMRouterPluginConfig.js +0 -31
  43. package/lib/HMRouterPluginConfig.js.map +0 -1
  44. package/lib/HMRouterPluginHandle.js +0 -148
  45. package/lib/HMRouterPluginHandle.js.map +0 -1
  46. package/lib/Index.js +0 -143
  47. package/lib/Index.js.map +0 -1
  48. package/lib/common/Constant.js.map +0 -1
  49. package/lib/common/Logger.js.map +0 -1
  50. package/lib/common/PluginModel.js.map +0 -1
  51. package/src/HMRouterAnalyzer.ts +0 -375
  52. package/src/HMRouterHvigorPlugin.ts +0 -199
  53. package/src/HMRouterPluginConfig.ts +0 -44
  54. package/src/HMRouterPluginHandle.ts +0 -188
  55. package/src/Index.ts +0 -151
  56. package/src/common/Constant.ts +0 -49
  57. package/src/common/Logger.ts +0 -73
  58. package/src/common/PluginModel.ts +0 -83
  59. package/tsconfig.json +0 -14
@@ -1,375 +0,0 @@
1
- /*
2
- * Copyright (c) 2024 Huawei Device Co., Ltd.
3
- * Licensed under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License.
5
- * You may obtain a copy of the License at
6
- *
7
- * http://www.apache.org/licenses/LICENSE-2.0
8
- *
9
- * Unless required by applicable law or agreed to in writing, software
10
- * distributed under the License is distributed on an "AS IS" BASIS,
11
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- * See the License for the specific language governing permissions and
13
- * limitations under the License.
14
- */
15
-
16
- import ts from 'typescript'
17
- import {HMRouterPluginConfig} from './HMRouterPluginConfig'
18
- import {AnalyzerResultLike, HMRouterResult, HMServiceResult} from './common/PluginModel'
19
- import {FileUtil} from '@ohos/hvigor'
20
- import {Logger, PluginError} from './common/Logger'
21
- import { HMRouterPluginConstant } from './common/Constant'
22
-
23
- class NodeInfo {
24
- value?: any
25
- }
26
-
27
- export class Analyzer {
28
- analyzeResultSet: Set<AnalyzerResultLike> = new Set()
29
- private readonly sourcePath: string
30
- private readonly pluginConfig: HMRouterPluginConfig
31
- private analyzeResult: AnalyzerResultLike = {}
32
- private classMethodAnalyzeResult: Set<AnalyzerResultLike> = new Set()
33
- private keywordPos: number = 0
34
- private importMap: Map<string, string[]> = new Map()
35
-
36
- constructor(sourcePath: string, pluginConfig: HMRouterPluginConfig) {
37
- this.sourcePath = sourcePath
38
- this.pluginConfig = pluginConfig
39
- }
40
-
41
- start() {
42
- const sourceCode = FileUtil.readFileSync(this.sourcePath).toString()
43
- const sourceFile = ts.createSourceFile(this.sourcePath, sourceCode, ts.ScriptTarget.ES2021, false)
44
-
45
- ts.forEachChild(sourceFile, node => {
46
- this.resolveNode(node)
47
- if (this.analyzeResult.annotation) {
48
- this.analyzeResultSet.add(this.analyzeResult)
49
- }
50
- if (this.classMethodAnalyzeResult.size > 0) {
51
- this.analyzeResultSet = new Set([...this.analyzeResultSet, ...this.classMethodAnalyzeResult])
52
- }
53
- })
54
-
55
- // 遍历map查看是否还有常量类型的属性值
56
- this.analyzeResultSet.forEach(value => {
57
- if (value.annotation === 'HMRouter') {
58
- let hmRouterResult = value as HMRouterResult
59
- if (hmRouterResult.pageUrl.type === 'constant') {
60
- hmRouterResult.pageUrl = this.resolveConstantValue(hmRouterResult.pageUrl.value)
61
- } else if (hmRouterResult.pageUrl.type === 'object') {
62
- hmRouterResult.pageUrl = this.resolveObjectValue(hmRouterResult.pageUrl.className, hmRouterResult.pageUrl.propertyName)
63
- }
64
- }
65
- })
66
- }
67
-
68
- private resolveNode(node: ts.Node) {
69
- if (ts.isImportDeclaration(node)) {
70
- this.resolveImportDeclaration(node)
71
- } else if (ts.isMissingDeclaration(node)) {
72
- this.resolveMissingDeclaration(node)
73
- } else if (ts.isClassDeclaration(node)) {
74
- this.isDecoratedClass(node) ? this.resolveClass(node) : this.resolveClassMethod(node)
75
- } else if (ts.isDecorator(node)) {
76
- this.resolveDecorator(node)
77
- } else if (ts.isCallExpression(node)) {
78
- this.resolveCallExpression(node)
79
- } else if (ts.isExpressionStatement(node)) {
80
- this.resolveExpression(node)
81
- } else if (ts.isBlock(node)) {
82
- this.resolveBlock(node)
83
- } else if (ts.isPropertyAssignment(node)) {
84
- return this.resolvePropertyAccess(node)
85
- } else if (ts.isIdentifier(node)) {
86
- return this.resolveIdentifier(node)
87
- } else if (ts.isStringLiteral(node)) {
88
- return this.resolveStringLiteral(node)
89
- } else if (ts.isNumericLiteral(node)) {
90
- return this.resolveNumericLiteral(node)
91
- } else if (ts.isArrayLiteralExpression(node)) {
92
- return this.resolveArrayLiteral(node)
93
- } else if (node.kind === ts.SyntaxKind.TrueKeyword) {
94
- return this.resolveTrueKeyword()
95
- } else if (node.kind === ts.SyntaxKind.FalseKeyword) {
96
- return this.resolveFalseKeyword()
97
- }
98
- }
99
-
100
- private resolveImportDeclaration(node: ts.ImportDeclaration) {
101
- let variableArr: string[] = []
102
- node.importClause?.namedBindings?.forEachChild(child => {
103
- if (ts.isImportSpecifier(child)) {
104
- variableArr.push(child.name.escapedText!)
105
- }
106
- })
107
- let key = node.moduleSpecifier
108
- if (ts.isModuleName(key)) {
109
- this.importMap.set(key.text, variableArr)
110
- }
111
- }
112
-
113
- private resolveMissingDeclaration(node: ts.MissingDeclaration) {
114
- this.analyzeResult = {}
115
- node.forEachChild(child => this.resolveNode(child))
116
- }
117
-
118
- private isDecoratedClass(node: ts.ClassDeclaration) {
119
- // @ts-ignore
120
- return node.modifiers?.some((item) => HMRouterPluginConstant.CLASS_ANNOTATION_ARR.includes(item.expression?.expression?.text))
121
- }
122
-
123
- private resolveClass(node: ts.ClassDeclaration) {
124
- // 解析到类声明,先清空一次返回结果
125
- this.analyzeResult = {}
126
- node.modifiers?.forEach(modifier => {
127
- // 遍历分析装饰器
128
- this.resolveNode(modifier)
129
- })
130
-
131
- if (this.analyzeResult.annotation) {
132
- this.analyzeResult.name = node.name?.text
133
- }
134
- }
135
-
136
- private resolveClassMethod(node: ts.ClassDeclaration) {
137
- this.classMethodAnalyzeResult = new Set([])
138
- node.members?.forEach((member) => {
139
- this.analyzeResult = {};
140
- if (ts.isMethodDeclaration(member) && member.modifiers) {
141
- member.modifiers?.forEach((modifier) => {
142
- this.resolveNode(modifier)
143
- })
144
-
145
- // @ts-ignore
146
- this.analyzeResult.functionName = member.name?.text
147
- this.analyzeResult.name = node.name?.text
148
-
149
- if (this.analyzeResult.annotation) {
150
- this.classMethodAnalyzeResult.add(this.analyzeResult)
151
- }
152
- this.analyzeResult = {};
153
- }
154
- })
155
- }
156
-
157
- private resolveDecorator(node: ts.Decorator) {
158
- if (ts.isCallExpression(node.expression)) {
159
- const callExpression = node.expression as ts.CallExpression
160
- if (ts.isIdentifier(callExpression.expression)) {
161
- this.switchIdentifier(callExpression)
162
- }
163
- }
164
- }
165
-
166
- private switchIdentifier(callExpression: ts.CallExpression) {
167
- const identifier = callExpression.expression as ts.Identifier
168
- if (this.pluginConfig.annotation.some(item => item === identifier.text)) {
169
- this.analyzeResult.annotation = identifier.text
170
- this.resolveNode(callExpression)
171
- }
172
- }
173
-
174
- private resolveCallExpression(node: ts.CallExpression) {
175
- let identifier = this.resolveNode(node.expression)
176
- this.parseAnnotation(node.arguments, identifier)
177
- }
178
-
179
- private resolveExpression(node: ts.ExpressionStatement) {
180
- let identifier = this.resolveNode(node.expression)
181
- if (identifier?.value === 'struct') {
182
- this.keywordPos = node.end
183
- }
184
- if (this.analyzeResult.annotation === 'HMRouter' && this.keywordPos === node.pos) {
185
- this.analyzeResult.name = identifier?.value
186
- }
187
- }
188
-
189
- private resolveBlock(node: ts.Block) {
190
- node.statements.forEach(statement => {
191
- this.resolveNode(statement)
192
- })
193
- }
194
-
195
- private parseAnnotation(args: ts.NodeArray<ts.Expression>, nodeInfo?: NodeInfo) {
196
- if (this.pluginConfig.annotation.some(item => nodeInfo?.value === item)) {
197
- args
198
- .flatMap((e: ts.Expression) => (e as ts.ObjectLiteralExpression).properties)
199
- .forEach((e: ts.ObjectLiteralElementLike) => {
200
- this.parseConfig(e, this.analyzeResult)
201
- })
202
- }
203
- }
204
-
205
- private parseConfig(node: ts.ObjectLiteralElementLike, result: AnalyzerResultLike) {
206
- let info = this.resolveNode(node)
207
- Reflect.set(result, info?.value['key'], info?.value['value'])
208
- }
209
-
210
- private resolvePropertyAccess(node: any) {
211
- let propertyName = this.resolveNode(node.name)?.value
212
- let propertyValue
213
- if (propertyName === 'pageUrl') {
214
- if (node.initializer.kind === ts.SyntaxKind.Identifier) {
215
- propertyValue = {
216
- type: 'constant', // 常量
217
- value: this.resolveNode(node.initializer)?.value
218
- }
219
- } else if (node.initializer.kind === ts.SyntaxKind.PropertyAccessExpression) {
220
- propertyValue = {
221
- type: 'object', // 对象
222
- className: this.resolveNode(node.initializer.expression)?.value,
223
- propertyName: this.resolveNode(node.initializer.name)?.value
224
- }
225
- } else {
226
- propertyValue = this.resolveNode(node.initializer)?.value
227
- }
228
- } else {
229
- propertyValue = this.resolveNode(node.initializer)?.value
230
- }
231
- let info = new NodeInfo()
232
- info.value = { key: propertyName, value: propertyValue }
233
- return info
234
- }
235
-
236
- private resolveIdentifier(node: ts.Identifier) {
237
- if (node.escapedText === 'NavDestination' && this.analyzeResult.annotation === 'HMRouter') {
238
- Logger.e(PluginError.ERR_WRONG_DECORATION)
239
- throw new Error('NavDestination is not allowed in HMRouter' + this.sourcePath)
240
- }
241
- let info = new NodeInfo()
242
- info.value = node.escapedText.toString()
243
- return info
244
- }
245
-
246
- private resolveArrayLiteral(node: ts.ArrayLiteralExpression) {
247
- let arrValue = node.elements.map(e => this.resolveNode(e)?.value as string)
248
- let info = new NodeInfo()
249
- info.value = arrValue
250
- return info
251
- }
252
-
253
- private resolveNumericLiteral(node: ts.NumericLiteral) {
254
- let info = new NodeInfo()
255
- info.value = Number(node.text)
256
- return info
257
- }
258
-
259
- private resolveStringLiteral(node: ts.StringLiteral) {
260
- let info = new NodeInfo()
261
- info.value = node.text
262
- return info
263
- }
264
-
265
- private resolveTrueKeyword() {
266
- let info = new NodeInfo()
267
- info.value = true
268
- return info
269
- }
270
-
271
- private resolveFalseKeyword() {
272
- let info = new NodeInfo()
273
- info.value = false
274
- return info
275
- }
276
-
277
- private getSourceFile(filePath: string): ts.SourceFile | null {
278
- if (!FileUtil.exist(filePath)) {
279
- return null;
280
- }
281
- const sourceCode = FileUtil.readFileSync(filePath).toString();
282
- return ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.ES2021, false);
283
- }
284
-
285
- private findConstantValueInSourceFile(sourceFile: ts.SourceFile, constantName: string): NodeInfo | null {
286
- let nodeInfo = new NodeInfo();
287
- ts.forEachChild(sourceFile, node => {
288
- if (!ts.isVariableStatement(node)) {
289
- return;
290
- }
291
- node.declarationList.declarations.forEach(declaration => {
292
- let info = this.parseVariableDeclaration(declaration);
293
- if (constantName === info?.value['key']) {
294
- nodeInfo = info;
295
- }
296
- });
297
- });
298
- return nodeInfo.value['value'] !== '' ? nodeInfo : null;
299
- }
300
-
301
- private findObjectValueInSourceFile(sourceFile: ts.SourceFile, className: string,
302
- propertyName: string): NodeInfo | null {
303
- let info = new NodeInfo();
304
- ts.forEachChild(sourceFile, node => {
305
- if (!ts.isClassDeclaration(node) || node.name?.escapedText.toString() !== className) {
306
- return;
307
- }
308
- node.members.forEach(member => {
309
- // @ts-ignore
310
- if (member.name?.escapedText.toString() === propertyName) {
311
- info = this.parseVariableDeclaration(member);
312
- }
313
- });
314
- });
315
- return info.value['value'] !== '' ? info : null;
316
- }
317
-
318
- private resolveConstantValue(constantName: string) {
319
- const sourceFile = this.getSourceFile(this.resolvePath(constantName));
320
- if (!sourceFile) {
321
- return null;
322
- }
323
-
324
- const nodeInfo = this.findConstantValueInSourceFile(sourceFile, constantName);
325
- if (!nodeInfo) {
326
- Logger.e(PluginError.ERR_NOT_EMPTY_STRING, constantName);
327
- throw new Error('constant value cannot be an empty string');
328
- }
329
- return nodeInfo.value['value'];
330
- }
331
-
332
- private resolveObjectValue(className: string, propertyName: string) {
333
- const sourceFile = this.getSourceFile(this.resolvePath(className));
334
- if (!sourceFile) {
335
- return null;
336
- }
337
-
338
- const info = this.findObjectValueInSourceFile(sourceFile, className, propertyName);
339
- if (!info) {
340
- Logger.e(PluginError.ERR_NOT_EMPTY_STRING, propertyName);
341
- throw new Error('constant value cannot be an empty string');
342
- }
343
- return info.value['value'];
344
- }
345
-
346
-
347
- private resolvePath(variableName: any) {
348
- let filePath: string = ''
349
- this.importMap.forEach((value, key) => {
350
- if (value.includes(variableName)) {
351
- filePath = key
352
- }
353
- })
354
- if (filePath) {
355
- filePath =
356
- FileUtil.pathResolve(
357
- this.sourcePath.split(HMRouterPluginConstant.FILE_SEPARATOR).slice(0, -1)
358
- .join(HMRouterPluginConstant.FILE_SEPARATOR),
359
- filePath
360
- ) + '.ets'
361
- } else {
362
- filePath = this.sourcePath
363
- }
364
-
365
- return filePath
366
- }
367
-
368
- private parseVariableDeclaration(node: any) {
369
- let variableName = this.resolveNode(node.name)?.value
370
- let variableValue = this.resolveNode(node.initializer!)?.value
371
- let info = new NodeInfo()
372
- info.value = { key: variableName, value: variableValue }
373
- return info
374
- }
375
- }
@@ -1,199 +0,0 @@
1
- /*
2
- * Copyright (c) 2024 Huawei Device Co., Ltd.
3
- * Licensed under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License.
5
- * You may obtain a copy of the License at
6
- *
7
- * http://www.apache.org/licenses/LICENSE-2.0
8
- *
9
- * Unless required by applicable law or agreed to in writing, software
10
- * distributed under the License is distributed on an "AS IS" BASIS,
11
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- * See the License for the specific language governing permissions and
13
- * limitations under the License.
14
- */
15
-
16
- import { FileUtil } from '@ohos/hvigor'
17
- import { HMRouterPluginConfig } from './HMRouterPluginConfig'
18
- import {
19
- AnalyzerResultLike,
20
- HMAnimatorResult,
21
- HMInterceptorResult,
22
- HMLifecycleResult,
23
- HMServiceResult,
24
- HMRouterResult,
25
- RouterInfo,
26
- TemplateModel
27
- } from './common/PluginModel'
28
- import path from 'path'
29
- import fs from 'fs'
30
- import { Analyzer } from './HMRouterAnalyzer'
31
- import Handlebars from 'handlebars'
32
- import { Logger, PluginError } from './common/Logger'
33
- import { HMRouterPluginConstant } from './common/Constant'
34
-
35
- // 定义HMRouterHvigorPlugin类
36
- export class HMRouterHvigorPlugin {
37
- config: HMRouterPluginConfig
38
- routerMap: RouterInfo[] = []
39
- private scanFiles: string[] = []
40
- private HMRouterNum: number = 0
41
-
42
- constructor(config: HMRouterPluginConfig) {
43
- this.config = config
44
- }
45
-
46
- analyzeAnnotation() {
47
- this.config.scanDir.forEach(scanDir => {
48
- const scanPath = FileUtil.pathResolve(this.config.modulePath, scanDir)
49
- this.deepScan(scanPath, '')
50
- })
51
- Logger.i(`扫描到${this.scanFiles.length}个文件`, this.scanFiles)
52
- this.scanFiles.forEach(filePath => {
53
- if (filePath.endsWith(HMRouterPluginConstant.VIEW_NAME_SUFFIX)) {
54
- // 创建Analyzer对象
55
- const analyzer = new Analyzer(filePath, this.config)
56
- // 开始分析
57
- analyzer.start()
58
- // 遍历分析结果
59
- for (let analyzeResult of analyzer.analyzeResultSet) {
60
- analyzeResult.module = this.config.moduleName
61
- let pageSourceFile = path.relative(this.config.modulePath, filePath)
62
- this.pushRouterInfo(analyzeResult, pageSourceFile.replaceAll(HMRouterPluginConstant.FILE_SEPARATOR, HMRouterPluginConstant.DELIMITER))
63
- }
64
- this.HMRouterNum = 0
65
- }
66
- })
67
- }
68
-
69
- // 推送路由信息
70
- private pushRouterInfo(analyzeResult: AnalyzerResultLike, pageSourceFile: string) {
71
- // 判断注解类型
72
- switch (analyzeResult.annotation) {
73
- case HMRouterPluginConstant.ROUTER_ANNOTATION:
74
- this.HMRouterNum++
75
- // 判断是否存在多个HMRouter注解
76
- if (this.HMRouterNum > 1) {
77
- Logger.e(PluginError.ERR_REPEAT_ANNOTATION, pageSourceFile)
78
- throw new Error(`文件${pageSourceFile}中存在多个HMRouter注解`)
79
- }
80
- let [generatorFilePath, componentName] = this.generateBuilder(analyzeResult, pageSourceFile)
81
- // window环境下需要替换路径中的反斜杠
82
- generatorFilePath = generatorFilePath.replaceAll(HMRouterPluginConstant.FILE_SEPARATOR, HMRouterPluginConstant.DELIMITER)
83
- this.routerMap.push(
84
- new RouterInfo((analyzeResult as HMRouterResult).pageUrl as string, generatorFilePath, `${componentName}Builder`, analyzeResult)
85
- )
86
- break
87
- case HMRouterPluginConstant.ANIMATOR_ANNOTATION:
88
- let animatorName = HMRouterPluginConstant.ANIMATOR_PREFIX + (analyzeResult as HMAnimatorResult).animatorName
89
- this.routerMap.push(new RouterInfo(animatorName, pageSourceFile, '', analyzeResult))
90
- break
91
- case HMRouterPluginConstant.INTERCEPTOR_ANNOTATION:
92
- let interceptorName = HMRouterPluginConstant.INTERCEPTOR_PREFIX + (analyzeResult as HMInterceptorResult).interceptorName
93
- this.routerMap.push(new RouterInfo(interceptorName, pageSourceFile, '', analyzeResult))
94
- break
95
- case HMRouterPluginConstant.LIFECYCLE_ANNOTATION:
96
- let lifecycleName = HMRouterPluginConstant.LIFECYCLE_PREFIX + (analyzeResult as HMLifecycleResult).lifecycleName
97
- this.routerMap.push(new RouterInfo(lifecycleName, pageSourceFile, '', analyzeResult))
98
- break
99
- case HMRouterPluginConstant.SERVICE_ANNOTATION:
100
- let serviceName = HMRouterPluginConstant.SERVICE_PREFIX + (analyzeResult as HMServiceResult).serviceName
101
- this.routerMap.push(new RouterInfo(serviceName, pageSourceFile, '', analyzeResult))
102
- break
103
- }
104
- }
105
-
106
- // 生成Builder
107
- private generateBuilder(analyzeResult: HMRouterResult, pageSourceFile: string) {
108
- // 获取导入路径
109
- let importPath = path
110
- .relative(this.config.builderDir, pageSourceFile)
111
- .replaceAll(HMRouterPluginConstant.FILE_SEPARATOR, HMRouterPluginConstant.DELIMITER)
112
- .replaceAll(HMRouterPluginConstant.VIEW_NAME_SUFFIX, '')
113
- // 生成视图名称
114
- let generatorViewName = HMRouterPluginConstant.VIEW_NAME_PREFIX + analyzeResult.name + this.stringToHashCode(analyzeResult.pageUrl!)
115
- // 创建模板模型
116
- const templateModel: TemplateModel = new TemplateModel(
117
- analyzeResult.pageUrl,
118
- importPath,
119
- analyzeResult.name!,
120
- !!analyzeResult.dialog,
121
- generatorViewName
122
- )
123
- // 获取模板文件路径
124
- const templateFilePath = FileUtil.pathResolve(__dirname, HMRouterPluginConstant.PARENT_DELIMITER + this.config.builderTpl)
125
- // 读取模板文件
126
- const tpl = FileUtil.readFileSync(templateFilePath).toString()
127
- // 编译模板
128
- const template = Handlebars.compile(tpl)
129
- // 渲染模板
130
- const output = template(templateModel)
131
- // 获取生成文件路径
132
- const generatorFilePath = FileUtil.pathResolve(
133
- this.config.modulePath,
134
- this.config.builderDir,
135
- templateModel.generatorViewName + HMRouterPluginConstant.VIEW_NAME_SUFFIX
136
- )
137
- FileUtil.ensureFileSync(generatorFilePath)
138
- FileUtil.writeFileSync(generatorFilePath, output)
139
- Logger.i(`Builder ${templateModel.generatorViewName}.ets has been generated in ${generatorFilePath}`)
140
- // 返回生成文件路径和组件名称
141
- return [path.join(this.config.builderDir, templateModel.generatorViewName + HMRouterPluginConstant.VIEW_NAME_SUFFIX), templateModel.componentName]
142
- }
143
-
144
- // 生成路由表文件
145
- generateRouterMap() {
146
- let set = new Set<string>()
147
- this.routerMap.forEach(item => {
148
- // 判断路由名称是否重复
149
- if (set.has(item.name)) {
150
- Logger.e(PluginError.ERR_DUPLICATE_NAME, item.name)
151
- throw new Error(`路由${item.name}重复`)
152
- } else {
153
- set.add(item.name)
154
- }
155
- })
156
- let routerMap = {
157
- routerMap: this.routerMap.map(item => {
158
- // 删除注解
159
- if (item.customData && item.customData.annotation) {
160
- delete item.customData.annotation
161
- }
162
- return item
163
- })
164
- }
165
-
166
- // 获取路由映射文件路径
167
- const routerMapJsonStr = JSON.stringify(routerMap, null, 2)
168
- const routerMapFilePath = FileUtil.pathResolve(this.config.modulePath, this.config.routerMapDir, HMRouterPluginConstant.ROUTER_MAP_NAME)
169
- // 确保文件存在
170
- FileUtil.ensureFileSync(routerMapFilePath)
171
- FileUtil.writeFileSync(routerMapFilePath, routerMapJsonStr)
172
- Logger.i(`hm_router_map.json has been generated in ${routerMapFilePath}`)
173
- }
174
-
175
- // 深度扫描文件夹获取需要扫描的文件列表
176
- private deepScan(scanPath: string, filePath: string) {
177
- let resolvePath = FileUtil.pathResolve(scanPath, filePath)
178
- if (FileUtil.isDictionary(resolvePath)) {
179
- const files: string[] = fs.readdirSync(resolvePath)
180
- files.forEach(file => {
181
- this.deepScan(resolvePath, file)
182
- })
183
- } else {
184
- this.scanFiles.push(resolvePath)
185
- }
186
- }
187
-
188
- // 字符串转哈希码
189
- private stringToHashCode(str: string) {
190
- let hash = 0
191
- if (str.length === 0) return hash
192
- for (let i = 0; i < str.length; i++) {
193
- const char = str.charCodeAt(i)
194
- hash = (hash << 5) - hash + char
195
- hash |= 0 // 转换为32位整数
196
- }
197
- return hash
198
- }
199
- }
@@ -1,44 +0,0 @@
1
- /*
2
- * Copyright (c) 2024 Huawei Device Co., Ltd.
3
- * Licensed under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License.
5
- * You may obtain a copy of the License at
6
- *
7
- * http://www.apache.org/licenses/LICENSE-2.0
8
- *
9
- * Unless required by applicable law or agreed to in writing, software
10
- * distributed under the License is distributed on an "AS IS" BASIS,
11
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- * See the License for the specific language governing permissions and
13
- * limitations under the License.
14
- */
15
-
16
- export class HMRouterPluginConfig {
17
- moduleName: string
18
- modulePath: string
19
- scanDir: string[]
20
- routerMapDir: string
21
- builderDir: string
22
- annotation: string[]
23
- builderTpl: string
24
- saveGeneratedFile: boolean
25
-
26
- constructor(moduleName: string, modulePath: string, param: HMRouterPluginConfigParam) {
27
- this.moduleName = moduleName
28
- this.modulePath = modulePath
29
- this.scanDir = param.scanDir ? [...new Set(...param.scanDir)] : ['src/main/ets']
30
- this.routerMapDir = param.routerMapDir ? param.routerMapDir : 'src/main/resources/base/profile'
31
- this.builderDir = param.builderDir ? param.builderDir : 'src/main/ets/generated'
32
- this.annotation = ['HMRouter', 'HMAnimator', 'HMInterceptor', 'HMLifecycle', 'HMService']
33
- this.builderTpl = param.builderTpl ? param.builderTpl : 'viewBuilder.tpl'
34
- this.saveGeneratedFile = !!param.saveGeneratedFile
35
- }
36
- }
37
-
38
- export interface HMRouterPluginConfigParam {
39
- scanDir?: string[]
40
- routerMapDir?: string
41
- builderDir?: string
42
- saveGeneratedFile?: boolean // 隐藏字段仅用于调试
43
- builderTpl?: string // 隐藏字段仅用于调试
44
- }