@hadss/hmrouter-plugin 1.0.0-rc.5 → 1.0.0-rc.6
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/.mocharc.js +23 -0
- package/README.md +13 -2
- package/dist/HMRouterAnalyzer.d.ts +4 -36
- package/dist/HMRouterAnalyzer.js +203 -295
- package/dist/HMRouterHvigorPlugin.d.ts +2 -2
- package/dist/HMRouterHvigorPlugin.js +58 -65
- package/dist/HMRouterPluginConfig.d.ts +3 -0
- package/dist/HMRouterPluginConfig.js +26 -15
- package/dist/HMRouterPluginHandle.d.ts +5 -0
- package/dist/HMRouterPluginHandle.js +108 -21
- package/dist/Index.js +52 -34
- package/dist/common/PluginModel.d.ts +1 -0
- package/dist/constants/CommonConstants.d.ts +34 -0
- package/dist/constants/CommonConstants.js +41 -0
- package/dist/constants/ConfigConstants.d.ts +11 -0
- package/dist/constants/ConfigConstants.js +14 -0
- package/dist/constants/TaskConstants.d.ts +9 -0
- package/dist/constants/TaskConstants.js +12 -0
- package/dist/utils/ConfusionUtil.d.ts +4 -0
- package/dist/utils/ConfusionUtil.js +27 -0
- package/dist/utils/FileUtil.d.ts +11 -0
- package/dist/utils/FileUtil.js +19 -0
- package/dist/utils/TsAstUtil.d.ts +8 -0
- package/dist/utils/TsAstUtil.js +57 -0
- package/package.json +7 -7
- package/viewBuilder.tpl +1 -0
package/.mocharc.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
extension: ['ts'],
|
|
20
|
+
require: 'ts-node/register',
|
|
21
|
+
spec: process.env.TEST_ENV === 'unit' ? 'tests/**/Unit.test.ts' : 'tests/**/*.test.ts',
|
|
22
|
+
recursive: true
|
|
23
|
+
}
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
```json5
|
|
5
5
|
{
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@hadss/hmrouter-plugin": "^1.0.0-rc.
|
|
7
|
+
"@hadss/hmrouter-plugin": "^1.0.0-rc.6" // 使用npm仓版本号
|
|
8
8
|
},
|
|
9
9
|
// ...其他配置
|
|
10
10
|
}
|
|
@@ -28,13 +28,24 @@ export default {
|
|
|
28
28
|
{
|
|
29
29
|
// 如果不配置则扫描src/main/ets目录,对代码进行全量扫描,如果配置则数组不能为空,建议配置指定目录可缩短编译耗时
|
|
30
30
|
"scanDir": ["src/main/ets/components","src/main/ets/interceptors"],
|
|
31
|
-
"saveGeneratedFile": false, // 默认为false,调试排除错误时可以改成true
|
|
31
|
+
"saveGeneratedFile": false, // 默认为false,调试排除错误时可以改成true,不删除编译产物,
|
|
32
|
+
"autoObfuscation": true // 默认为false,不自动配置混淆规则,只会生成hmrouter_obfuscation_rules.txt文件帮助开发者配置混淆规则;如果设置为true,会自动配置混淆规则,并在编译完成后删除hmrouter_obfuscation_rules.txt文件
|
|
32
33
|
}
|
|
33
34
|
```
|
|
34
35
|
|
|
36
|
+
### hmrouter_config.json配置
|
|
37
|
+
|
|
38
|
+
`hmrouter_config.json`文件用于配置编译插件`@hadss/hmrouter-plugin`在编译期的行为
|
|
39
|
+
|
|
35
40
|
> 配置文件读取规则为 模块 > 工程 > 默认
|
|
36
41
|
> 优先使用本模块内的配置,如果没有配置,则找模块目录的上级目录(最多找三层目录,找到则停止),若找不到则使用默认配置
|
|
37
42
|
|
|
43
|
+
| 配置项 | 类型 | 是否必填 | 说明 |
|
|
44
|
+
|-------------------|---------|------|--------------------------------------------------------------------------------------------------------------------------------------|
|
|
45
|
+
| scanDir | array | 否 | 扫描当前模块使用HMRouter装饰器的路径,缺省值为`"src/main/ets"` |
|
|
46
|
+
| saveGeneratedFile | boolean | 否 | 默认为false,不保留插件自动生成的代码,如果需要保留,需要设置为true |
|
|
47
|
+
| autoObfuscation | boolean | 否 | 默认为false,不自动配置混淆规则,只会生成`hmrouter_obfuscation_rules.txt`文件帮助开发者配置混淆规则;如果设置为true,会自动配置混淆规则,并在编译完成后删除`hmrouter_obfuscation_rules.txt`文件 |
|
|
48
|
+
|
|
38
49
|
## HMRouter使用
|
|
39
50
|
|
|
40
51
|
详见[@hadss/hmrouter](https://ohpm.openharmony.cn/#/cn/detail/@hadss%2Fhmrouter)
|
|
@@ -1,40 +1,8 @@
|
|
|
1
1
|
import { HMRouterPluginConfig } from './HMRouterPluginConfig';
|
|
2
2
|
import { AnalyzerResultLike } from './common/PluginModel';
|
|
3
|
-
export declare class
|
|
4
|
-
analyzeResultSet: Set<AnalyzerResultLike>;
|
|
5
|
-
private readonly sourcePath;
|
|
6
|
-
private readonly pluginConfig;
|
|
3
|
+
export declare class AnalyzerController {
|
|
7
4
|
private analyzeResult;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
constructor(sourcePath: string, pluginConfig: HMRouterPluginConfig);
|
|
12
|
-
start(): void;
|
|
13
|
-
private resolveNode;
|
|
14
|
-
private resolveImportDeclaration;
|
|
15
|
-
private resolveMissingDeclaration;
|
|
16
|
-
private isDecoratedClass;
|
|
17
|
-
private resolveClass;
|
|
18
|
-
private resolveClassMethod;
|
|
19
|
-
private resolveDecorator;
|
|
20
|
-
private switchIdentifier;
|
|
21
|
-
private resolveCallExpression;
|
|
22
|
-
private resolveExpression;
|
|
23
|
-
private resolveBlock;
|
|
24
|
-
private parseAnnotation;
|
|
25
|
-
private parseConfig;
|
|
26
|
-
private resolvePropertyAccess;
|
|
27
|
-
private resolveIdentifier;
|
|
28
|
-
private resolveArrayLiteral;
|
|
29
|
-
private resolveNumericLiteral;
|
|
30
|
-
private resolveStringLiteral;
|
|
31
|
-
private resolveTrueKeyword;
|
|
32
|
-
private resolveFalseKeyword;
|
|
33
|
-
private getSourceFile;
|
|
34
|
-
private findConstantValueInSourceFile;
|
|
35
|
-
private findObjectValueInSourceFile;
|
|
36
|
-
private resolveConstantValue;
|
|
37
|
-
private resolveObjectValue;
|
|
38
|
-
private resolvePath;
|
|
39
|
-
private parseVariableDeclaration;
|
|
5
|
+
analyzeFile(sourceFilePath: string, config: HMRouterPluginConfig): void;
|
|
6
|
+
parsePageUrl(): void;
|
|
7
|
+
getAnalyzeResultSet(): Set<AnalyzerResultLike>;
|
|
40
8
|
}
|
package/dist/HMRouterAnalyzer.js
CHANGED
|
@@ -3,334 +3,242 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
7
|
-
const
|
|
8
|
-
const hvigor_1 = require("@ohos/hvigor");
|
|
6
|
+
exports.AnalyzerController = void 0;
|
|
7
|
+
const ts_morph_1 = require("ts-morph");
|
|
9
8
|
const Logger_1 = require("./common/Logger");
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class
|
|
14
|
-
constructor(
|
|
15
|
-
this.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
9
|
+
const TsAstUtil_1 = require("./utils/TsAstUtil");
|
|
10
|
+
const CommonConstants_1 = __importDefault(require("./constants/CommonConstants"));
|
|
11
|
+
const FileUtil_1 = __importDefault(require("./utils/FileUtil"));
|
|
12
|
+
class AnalyzerController {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.analyzeResult = new Set();
|
|
15
|
+
}
|
|
16
|
+
analyzeFile(sourceFilePath, config) {
|
|
17
|
+
let analyzerService = new AnalyzerService(sourceFilePath, config);
|
|
18
|
+
analyzerService.start();
|
|
19
|
+
analyzerService.getResult().forEach(item => {
|
|
20
|
+
item.pageSourceFile = sourceFilePath;
|
|
21
|
+
this.analyzeResult.add(item);
|
|
22
|
+
});
|
|
23
|
+
this.parsePageUrl();
|
|
22
24
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
this.resolveNode(node);
|
|
28
|
-
if (this.analyzeResult.annotation) {
|
|
29
|
-
this.analyzeResultSet.add(this.analyzeResult);
|
|
25
|
+
parsePageUrl() {
|
|
26
|
+
this.analyzeResult.forEach((item) => {
|
|
27
|
+
if (item.annotation !== 'HMRouter') {
|
|
28
|
+
return;
|
|
30
29
|
}
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
let pageUrl = item.pageUrl;
|
|
31
|
+
if (pageUrl.type === 'constant') {
|
|
32
|
+
pageUrl =
|
|
33
|
+
TsAstUtil_1.TsAstUtil.parseConstantValue(TsAstUtil_1.project.addSourceFileAtPath(pageUrl.variableFilePath), pageUrl.variableName);
|
|
33
34
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (value.annotation === 'HMRouter') {
|
|
37
|
-
let hmRouterResult = value;
|
|
38
|
-
if (hmRouterResult.pageUrl.type === 'constant') {
|
|
39
|
-
hmRouterResult.pageUrl = this.resolveConstantValue(hmRouterResult.pageUrl.value);
|
|
40
|
-
}
|
|
41
|
-
else if (hmRouterResult.pageUrl.type === 'object') {
|
|
42
|
-
hmRouterResult.pageUrl =
|
|
43
|
-
this.resolveObjectValue(hmRouterResult.pageUrl.className, hmRouterResult.pageUrl.propertyName);
|
|
44
|
-
}
|
|
35
|
+
else if (pageUrl.type === 'object') {
|
|
36
|
+
pageUrl = TsAstUtil_1.TsAstUtil.parseConstantValue(TsAstUtil_1.project.addSourceFileAtPath(pageUrl.variableFilePath), pageUrl.variableName, pageUrl.propertyName);
|
|
45
37
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (typescript_1.default.isImportDeclaration(node)) {
|
|
50
|
-
this.resolveImportDeclaration(node);
|
|
51
|
-
}
|
|
52
|
-
else if (typescript_1.default.isMissingDeclaration(node)) {
|
|
53
|
-
this.resolveMissingDeclaration(node);
|
|
54
|
-
}
|
|
55
|
-
else if (typescript_1.default.isClassDeclaration(node)) {
|
|
56
|
-
this.isDecoratedClass(node) ? this.resolveClass(node) : this.resolveClassMethod(node);
|
|
57
|
-
}
|
|
58
|
-
else if (typescript_1.default.isDecorator(node)) {
|
|
59
|
-
this.resolveDecorator(node);
|
|
60
|
-
}
|
|
61
|
-
else if (typescript_1.default.isCallExpression(node)) {
|
|
62
|
-
this.resolveCallExpression(node);
|
|
63
|
-
}
|
|
64
|
-
else if (typescript_1.default.isExpressionStatement(node)) {
|
|
65
|
-
this.resolveExpression(node);
|
|
66
|
-
}
|
|
67
|
-
else if (typescript_1.default.isBlock(node)) {
|
|
68
|
-
this.resolveBlock(node);
|
|
69
|
-
}
|
|
70
|
-
else if (typescript_1.default.isPropertyAssignment(node)) {
|
|
71
|
-
return this.resolvePropertyAccess(node);
|
|
72
|
-
}
|
|
73
|
-
else if (typescript_1.default.isIdentifier(node)) {
|
|
74
|
-
return this.resolveIdentifier(node);
|
|
75
|
-
}
|
|
76
|
-
else if (typescript_1.default.isStringLiteral(node)) {
|
|
77
|
-
return this.resolveStringLiteral(node);
|
|
78
|
-
}
|
|
79
|
-
else if (typescript_1.default.isNumericLiteral(node)) {
|
|
80
|
-
return this.resolveNumericLiteral(node);
|
|
81
|
-
}
|
|
82
|
-
else if (typescript_1.default.isArrayLiteralExpression(node)) {
|
|
83
|
-
return this.resolveArrayLiteral(node);
|
|
84
|
-
}
|
|
85
|
-
else if (node.kind === typescript_1.default.SyntaxKind.TrueKeyword) {
|
|
86
|
-
return this.resolveTrueKeyword();
|
|
87
|
-
}
|
|
88
|
-
else if (node.kind === typescript_1.default.SyntaxKind.FalseKeyword) {
|
|
89
|
-
return this.resolveFalseKeyword();
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
resolveImportDeclaration(node) {
|
|
93
|
-
let variableArr = [];
|
|
94
|
-
node.importClause?.namedBindings?.forEachChild(child => {
|
|
95
|
-
if (typescript_1.default.isImportSpecifier(child)) {
|
|
96
|
-
variableArr.push(child.name.escapedText);
|
|
38
|
+
if (pageUrl === '') {
|
|
39
|
+
Logger_1.Logger.error(Logger_1.PluginError.ERR_NOT_EMPTY_STRING);
|
|
40
|
+
throw new Error('constant value cannot be an empty string');
|
|
97
41
|
}
|
|
42
|
+
item.pageUrl = pageUrl;
|
|
98
43
|
});
|
|
99
|
-
variableArr.push(node.importClause?.name?.text);
|
|
100
|
-
let key = node.moduleSpecifier;
|
|
101
|
-
if (typescript_1.default.isModuleName(key)) {
|
|
102
|
-
this.importMap.set(key.text, variableArr);
|
|
103
|
-
}
|
|
104
44
|
}
|
|
105
|
-
|
|
106
|
-
this.analyzeResult
|
|
107
|
-
node.forEachChild(child => this.resolveNode(child));
|
|
45
|
+
getAnalyzeResultSet() {
|
|
46
|
+
return this.analyzeResult;
|
|
108
47
|
}
|
|
109
|
-
|
|
110
|
-
|
|
48
|
+
}
|
|
49
|
+
exports.AnalyzerController = AnalyzerController;
|
|
50
|
+
class AnalyzerService {
|
|
51
|
+
constructor(sourceFilePath, config) {
|
|
52
|
+
this.analyzerResultSet = new Set();
|
|
53
|
+
this.importMap = new Map();
|
|
54
|
+
this.sourceFilePath = sourceFilePath;
|
|
55
|
+
this.sourceFile = TsAstUtil_1.TsAstUtil.getSourceFile(sourceFilePath);
|
|
56
|
+
this.config = config;
|
|
111
57
|
}
|
|
112
|
-
|
|
113
|
-
this.
|
|
114
|
-
|
|
115
|
-
|
|
58
|
+
start() {
|
|
59
|
+
this.analyzeImport();
|
|
60
|
+
this.analyzeRouter();
|
|
61
|
+
this.analyzeComponent();
|
|
62
|
+
this.parseFileByLineOrder();
|
|
63
|
+
}
|
|
64
|
+
getResult() {
|
|
65
|
+
let HMRouterNum = 0;
|
|
66
|
+
this.analyzerResultSet.forEach((analyzerResult) => {
|
|
67
|
+
if (analyzerResult.annotation === CommonConstants_1.default.ROUTER_ANNOTATION) {
|
|
68
|
+
HMRouterNum++;
|
|
69
|
+
}
|
|
116
70
|
});
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
71
|
+
if (HMRouterNum > 1) {
|
|
72
|
+
Logger_1.Logger.error(Logger_1.PluginError.ERR_REPEAT_ANNOTATION, this.sourceFilePath);
|
|
73
|
+
throw new Error(`文件${this.sourceFilePath}中存在多个HMRouter注解`);
|
|
74
|
+
}
|
|
75
|
+
return this.analyzerResultSet;
|
|
76
|
+
}
|
|
77
|
+
analyzeImport() {
|
|
78
|
+
this.sourceFile.getImportDeclarations().forEach(importDeclaration => {
|
|
79
|
+
const moduleSpecifier = importDeclaration.getModuleSpecifierValue();
|
|
80
|
+
const namedImports = importDeclaration.getNamedImports().map(namedImport => namedImport.getName());
|
|
81
|
+
const defaultImport = importDeclaration.getDefaultImport()?.getText();
|
|
82
|
+
const namespaceImport = importDeclaration.getNamespaceImport()?.getText();
|
|
83
|
+
const importNames = [];
|
|
84
|
+
if (namedImports.length > 0) {
|
|
85
|
+
importNames.push(...namedImports);
|
|
86
|
+
}
|
|
87
|
+
if (defaultImport) {
|
|
88
|
+
importNames.push(defaultImport);
|
|
89
|
+
}
|
|
90
|
+
if (namespaceImport) {
|
|
91
|
+
importNames.push(namespaceImport);
|
|
92
|
+
}
|
|
93
|
+
if (importNames.length > 0) {
|
|
94
|
+
let variableFilePath = FileUtil_1.default.pathResolve(this.config.modulePath, moduleSpecifier);
|
|
95
|
+
importNames.forEach((item) => {
|
|
96
|
+
if (FileUtil_1.default.exist(variableFilePath)) {
|
|
97
|
+
TsAstUtil_1.importVariableCache.set(variableFilePath + CommonConstants_1.default.VARIABLE_SEPARATOR + item, '');
|
|
98
|
+
}
|
|
128
99
|
});
|
|
129
|
-
this.
|
|
130
|
-
this.analyzeResult.name = node.name?.text;
|
|
131
|
-
if (this.analyzeResult.annotation) {
|
|
132
|
-
this.classMethodAnalyzeResult.add(this.analyzeResult);
|
|
133
|
-
}
|
|
134
|
-
this.analyzeResult = {};
|
|
100
|
+
this.importMap.set(moduleSpecifier, importNames);
|
|
135
101
|
}
|
|
136
102
|
});
|
|
137
103
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
switchIdentifier(callExpression) {
|
|
147
|
-
const identifier = callExpression.expression;
|
|
148
|
-
if (this.pluginConfig.annotation.some(item => item === identifier.text)) {
|
|
149
|
-
this.analyzeResult.annotation = identifier.text;
|
|
150
|
-
this.resolveNode(callExpression);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
resolveCallExpression(node) {
|
|
154
|
-
let identifier = this.resolveNode(node.expression);
|
|
155
|
-
this.parseAnnotation(node.arguments, identifier);
|
|
156
|
-
}
|
|
157
|
-
resolveExpression(node) {
|
|
158
|
-
let identifier = this.resolveNode(node.expression);
|
|
159
|
-
if (identifier?.value === 'struct') {
|
|
160
|
-
this.keywordPos = node.end;
|
|
161
|
-
}
|
|
162
|
-
if (this.analyzeResult.annotation === 'HMRouter' && this.keywordPos === node.pos) {
|
|
163
|
-
this.analyzeResult.name = identifier?.value;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
resolveBlock(node) {
|
|
167
|
-
node.statements.forEach(statement => {
|
|
168
|
-
this.resolveNode(statement);
|
|
104
|
+
analyzeRouter() {
|
|
105
|
+
let viewNameArr = this.sourceFile.getChildrenOfKind(ts_morph_1.SyntaxKind.ExpressionStatement).map((node) => {
|
|
106
|
+
return node.getText();
|
|
107
|
+
}).filter((text) => {
|
|
108
|
+
return text != 'struct';
|
|
169
109
|
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
args
|
|
174
|
-
.flatMap((e) => e.properties)
|
|
175
|
-
.forEach((e) => {
|
|
176
|
-
this.parseConfig(e, this.analyzeResult);
|
|
110
|
+
this.sourceFile.getChildrenOfKind(ts_morph_1.SyntaxKind.MissingDeclaration).forEach((node, index) => {
|
|
111
|
+
node.getChildrenOfKind(ts_morph_1.SyntaxKind.Decorator).forEach((decorator) => {
|
|
112
|
+
this.addToResultSet(decorator, viewNameArr[index]);
|
|
177
113
|
});
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
parseConfig(node, result) {
|
|
181
|
-
let info = this.resolveNode(node);
|
|
182
|
-
Reflect.set(result, info?.value['key'], info?.value['value']);
|
|
114
|
+
});
|
|
183
115
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
value: this.resolveNode(node.initializer)?.value
|
|
192
|
-
};
|
|
116
|
+
parseFileByLineOrder() {
|
|
117
|
+
const statements = this.sourceFile.getStatements();
|
|
118
|
+
const sortedStatements = statements.sort((a, b) => a.getStart() - b.getStart());
|
|
119
|
+
let HMRouterExists = false;
|
|
120
|
+
sortedStatements.forEach(statement => {
|
|
121
|
+
if (statement.getKind() === ts_morph_1.SyntaxKind.MissingDeclaration && statement.getText().includes('HMRouter')) {
|
|
122
|
+
HMRouterExists = true;
|
|
193
123
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
propertyValue = this.resolveNode(node.initializer)?.value;
|
|
124
|
+
if (statement.getKind() === ts_morph_1.SyntaxKind.Block && HMRouterExists) {
|
|
125
|
+
HMRouterExists = false;
|
|
126
|
+
statement.getDescendantsOfKind(ts_morph_1.SyntaxKind.Identifier).forEach((node) => {
|
|
127
|
+
if (node.getText() === 'NavDestination') {
|
|
128
|
+
Logger_1.Logger.error(Logger_1.PluginError.ERR_WRONG_DECORATION);
|
|
129
|
+
throw new Error('NavDestination is not allowed in HMRouter, filePath:' + this.sourceFilePath);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
203
132
|
}
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
propertyValue = this.resolveNode(node.initializer)?.value;
|
|
207
|
-
}
|
|
208
|
-
let info = new NodeInfo();
|
|
209
|
-
info.value = { key: propertyName, value: propertyValue };
|
|
210
|
-
return info;
|
|
211
|
-
}
|
|
212
|
-
resolveIdentifier(node) {
|
|
213
|
-
if (node.escapedText === 'NavDestination' && this.analyzeResult.annotation === 'HMRouter') {
|
|
214
|
-
Logger_1.Logger.error(Logger_1.PluginError.ERR_WRONG_DECORATION);
|
|
215
|
-
throw new Error('NavDestination is not allowed in HMRouter' + this.sourcePath);
|
|
216
|
-
}
|
|
217
|
-
let info = new NodeInfo();
|
|
218
|
-
info.value = node.escapedText.toString();
|
|
219
|
-
return info;
|
|
220
|
-
}
|
|
221
|
-
resolveArrayLiteral(node) {
|
|
222
|
-
let arrValue = node.elements.map(e => this.resolveNode(e)?.value);
|
|
223
|
-
let info = new NodeInfo();
|
|
224
|
-
info.value = arrValue;
|
|
225
|
-
return info;
|
|
226
|
-
}
|
|
227
|
-
resolveNumericLiteral(node) {
|
|
228
|
-
let info = new NodeInfo();
|
|
229
|
-
info.value = Number(node.text);
|
|
230
|
-
return info;
|
|
231
|
-
}
|
|
232
|
-
resolveStringLiteral(node) {
|
|
233
|
-
let info = new NodeInfo();
|
|
234
|
-
info.value = node.text;
|
|
235
|
-
return info;
|
|
236
|
-
}
|
|
237
|
-
resolveTrueKeyword() {
|
|
238
|
-
let info = new NodeInfo();
|
|
239
|
-
info.value = true;
|
|
240
|
-
return info;
|
|
241
|
-
}
|
|
242
|
-
resolveFalseKeyword() {
|
|
243
|
-
let info = new NodeInfo();
|
|
244
|
-
info.value = false;
|
|
245
|
-
return info;
|
|
246
|
-
}
|
|
247
|
-
getSourceFile(filePath) {
|
|
248
|
-
if (!hvigor_1.FileUtil.exist(filePath)) {
|
|
249
|
-
return null;
|
|
250
|
-
}
|
|
251
|
-
const sourceCode = hvigor_1.FileUtil.readFileSync(filePath).toString();
|
|
252
|
-
return typescript_1.default.createSourceFile(filePath, sourceCode, typescript_1.default.ScriptTarget.ES2021, false);
|
|
133
|
+
});
|
|
253
134
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
node.declarationList.declarations.forEach(declaration => {
|
|
261
|
-
let info = this.parseVariableDeclaration(declaration);
|
|
262
|
-
if (constantName === info?.value['key']) {
|
|
263
|
-
nodeInfo = info;
|
|
135
|
+
analyzeComponent() {
|
|
136
|
+
this.sourceFile.getClasses().forEach((cls) => {
|
|
137
|
+
cls.getDecorators().forEach((decorator) => {
|
|
138
|
+
if (this.config.annotation.includes(decorator.getName())) {
|
|
139
|
+
this.addToResultSet(decorator, cls.getName());
|
|
264
140
|
}
|
|
265
141
|
});
|
|
142
|
+
cls.getMethods().forEach((method) => {
|
|
143
|
+
method.getDecorators().forEach((decorator) => {
|
|
144
|
+
let serviceResult = this.addToResultSet(decorator, cls.getName());
|
|
145
|
+
serviceResult.functionName = method.getName();
|
|
146
|
+
});
|
|
147
|
+
});
|
|
266
148
|
});
|
|
267
|
-
return nodeInfo;
|
|
268
149
|
}
|
|
269
|
-
|
|
270
|
-
let
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
150
|
+
addToResultSet(decorator, componentName) {
|
|
151
|
+
let decoratorResult = this.parseDecorator(decorator);
|
|
152
|
+
decoratorResult.name = componentName;
|
|
153
|
+
if (decoratorResult.annotation) {
|
|
154
|
+
this.analyzerResultSet.add(decoratorResult);
|
|
155
|
+
}
|
|
156
|
+
return decoratorResult;
|
|
157
|
+
}
|
|
158
|
+
parseDecorator(decorator) {
|
|
159
|
+
let decoratorResult = {};
|
|
160
|
+
let decoratorName = decorator.getName();
|
|
161
|
+
if (this.config.annotation.includes(decoratorName)) {
|
|
162
|
+
decoratorResult.annotation = decoratorName;
|
|
163
|
+
let args = this.parseDecoratorArguments(decorator);
|
|
164
|
+
Object.assign(decoratorResult, args);
|
|
165
|
+
}
|
|
166
|
+
return decoratorResult;
|
|
167
|
+
}
|
|
168
|
+
parseDecoratorArguments(decorator) {
|
|
169
|
+
let argResult = {};
|
|
170
|
+
decorator.getArguments().map(arg => {
|
|
171
|
+
const objLiteral = arg.asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
172
|
+
if (objLiteral) {
|
|
173
|
+
objLiteral.getProperties().forEach((prop) => {
|
|
174
|
+
let propertyName = prop.getName();
|
|
175
|
+
let propertyValue = propertyName === CommonConstants_1.default.PAGE_URL ?
|
|
176
|
+
this.parsePageUrlValue(prop.getInitializer()) :
|
|
177
|
+
this.parsePropertyValue(prop.getInitializer());
|
|
178
|
+
Reflect.set(argResult, propertyName, propertyValue);
|
|
179
|
+
});
|
|
274
180
|
}
|
|
275
|
-
node.members.forEach(member => {
|
|
276
|
-
if (member.name?.escapedText.toString() === propertyName) {
|
|
277
|
-
info = this.parseVariableDeclaration(member);
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
181
|
});
|
|
281
|
-
return
|
|
282
|
-
}
|
|
283
|
-
resolveConstantValue(constantName) {
|
|
284
|
-
const sourceFile = this.getSourceFile(this.resolvePath(constantName));
|
|
285
|
-
if (!sourceFile) {
|
|
286
|
-
return null;
|
|
287
|
-
}
|
|
288
|
-
const constantValueStr = this.findConstantValueInSourceFile(sourceFile, constantName).value['value'];
|
|
289
|
-
if (!constantValueStr) {
|
|
290
|
-
Logger_1.Logger.error(Logger_1.PluginError.ERR_NOT_EMPTY_STRING, constantName);
|
|
291
|
-
throw new Error('constant value cannot be an empty string');
|
|
292
|
-
}
|
|
293
|
-
return constantValueStr;
|
|
182
|
+
return argResult;
|
|
294
183
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
184
|
+
parsePageUrlValue(value) {
|
|
185
|
+
switch (value.getKind()) {
|
|
186
|
+
case ts_morph_1.SyntaxKind.Identifier:
|
|
187
|
+
return {
|
|
188
|
+
type: 'constant',
|
|
189
|
+
variableName: value.getText(),
|
|
190
|
+
variableFilePath: this.getVariableFilePath(value.getText())
|
|
191
|
+
};
|
|
192
|
+
case ts_morph_1.SyntaxKind.PropertyAccessExpression:
|
|
193
|
+
return {
|
|
194
|
+
type: 'object',
|
|
195
|
+
variableName: value.getExpression().getText(),
|
|
196
|
+
propertyName: value?.getName(),
|
|
197
|
+
variableFilePath: this.getVariableFilePath(value?.getExpression().getText())
|
|
198
|
+
};
|
|
199
|
+
default:
|
|
200
|
+
return this.parsePropertyValue(value);
|
|
304
201
|
}
|
|
305
|
-
return objectValueStr;
|
|
306
202
|
}
|
|
307
|
-
|
|
308
|
-
let
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
203
|
+
parsePropertyValue(value) {
|
|
204
|
+
let propertyValue;
|
|
205
|
+
switch (value.getKind()) {
|
|
206
|
+
case ts_morph_1.SyntaxKind.StringLiteral:
|
|
207
|
+
propertyValue = value.asKind(ts_morph_1.SyntaxKind.StringLiteral)?.getLiteralValue();
|
|
208
|
+
break;
|
|
209
|
+
case ts_morph_1.SyntaxKind.TrueKeyword:
|
|
210
|
+
propertyValue = true;
|
|
211
|
+
break;
|
|
212
|
+
case ts_morph_1.SyntaxKind.FalseKeyword:
|
|
213
|
+
propertyValue = false;
|
|
214
|
+
break;
|
|
215
|
+
case ts_morph_1.SyntaxKind.ArrayLiteralExpression:
|
|
216
|
+
propertyValue = value.asKind(ts_morph_1.SyntaxKind.ArrayLiteralExpression)?.getElements()
|
|
217
|
+
.map(item => item.asKind(ts_morph_1.SyntaxKind.StringLiteral)?.getLiteralValue());
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
return propertyValue;
|
|
221
|
+
}
|
|
222
|
+
getVariableFilePath(variableName) {
|
|
223
|
+
let classesNames = this.sourceFile.getClasses().map((classes) => {
|
|
224
|
+
return classes.getName();
|
|
313
225
|
});
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
226
|
+
let variableNames = this.sourceFile.getVariableDeclarations().map((variableDeclaration) => {
|
|
227
|
+
return variableDeclaration.getName();
|
|
228
|
+
});
|
|
229
|
+
if (classesNames.includes(variableName) || variableNames.includes(variableName)) {
|
|
230
|
+
return this.sourceFilePath;
|
|
318
231
|
}
|
|
319
232
|
else {
|
|
320
|
-
filePath =
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
throw new Error('Invalid constant value');
|
|
233
|
+
let filePath = '';
|
|
234
|
+
this.importMap.forEach((value, key) => {
|
|
235
|
+
if (value.includes(variableName)) {
|
|
236
|
+
filePath =
|
|
237
|
+
FileUtil_1.default.pathResolve(this.sourceFilePath.split(CommonConstants_1.default.FILE_SEPARATOR).slice(0, -1)
|
|
238
|
+
.join(CommonConstants_1.default.FILE_SEPARATOR), key) + CommonConstants_1.default.VIEW_NAME_SUFFIX;
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
return filePath;
|
|
330
242
|
}
|
|
331
|
-
let info = new NodeInfo();
|
|
332
|
-
info.value = { key: variableName, value: variableValue };
|
|
333
|
-
return info;
|
|
334
243
|
}
|
|
335
244
|
}
|
|
336
|
-
exports.Analyzer = Analyzer;
|
|
@@ -4,12 +4,12 @@ export declare class HMRouterHvigorPlugin {
|
|
|
4
4
|
config: HMRouterPluginConfig;
|
|
5
5
|
routerMap: RouterInfo[];
|
|
6
6
|
private scanFiles;
|
|
7
|
-
private
|
|
7
|
+
private analyzerController;
|
|
8
8
|
constructor(config: HMRouterPluginConfig);
|
|
9
9
|
analyzeAnnotation(): void;
|
|
10
|
+
generateRouterMap(): void;
|
|
10
11
|
private pushRouterInfo;
|
|
11
12
|
private generateBuilder;
|
|
12
|
-
generateRouterMap(): void;
|
|
13
13
|
private deepScan;
|
|
14
14
|
private stringToHashCode;
|
|
15
15
|
}
|