@aiot-toolkit/parser 2.0.6-beta.9 → 2.1.0-prender.1
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/lib/ux/config/IElement.d.ts +14 -0
- package/lib/ux/config/StyleBaseConfig.js +6 -0
- package/lib/ux/config/vela/ElementConfig.js +19 -0
- package/lib/ux/interface/IE2eConfig.d.ts +49 -0
- package/lib/ux/interface/IE2eConfig.js +1 -0
- package/lib/ux/parser/UxParser.js +40 -2
- package/lib/ux/translate/vela/ScriptToTypescript.d.ts +2 -1
- package/lib/ux/translate/vela/ScriptToTypescript.js +15 -8
- package/lib/ux/translate/vela/plugins/e2e.js +34 -142
- package/lib/ux/translate/vela/plugins/e2e1.d.ts +8 -0
- package/lib/ux/translate/vela/plugins/e2e1.js +307 -0
- package/lib/ux/translate/vela/utils/SourceMapUtil.d.ts +4 -0
- package/lib/ux/translate/vela/utils/SourceMapUtil.js +6 -0
- package/lib/ux/translate/vela/utils/TemplateUtil.js +2 -1
- package/lib/ux/utils/StyleUtil.js +1 -1
- package/lib/ux/utils/UxUtil.d.ts +14 -0
- package/lib/ux/utils/UxUtil.js +42 -1
- package/package.json +4 -4
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Dictionary, Logger } from '@aiot-toolkit/shared-utils';
|
|
2
|
+
import { IAttributeNode } from '../interface/IIdentifierNode';
|
|
2
3
|
interface IElement {
|
|
3
4
|
/**
|
|
4
5
|
* 别名
|
|
@@ -8,6 +9,19 @@ interface IElement {
|
|
|
8
9
|
* @example <img /> 生成为 image
|
|
9
10
|
*/
|
|
10
11
|
aliasName?: string;
|
|
12
|
+
/**
|
|
13
|
+
* 别名属性
|
|
14
|
+
*
|
|
15
|
+
* aliasName 生效时,会将别名属性合并到属性列表中
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```
|
|
19
|
+
* // <button /> 生成为 <input type="button" />
|
|
20
|
+
* aliasName='input'
|
|
21
|
+
* aliasAttributes=[{name:'type',value:'button'}]
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
aliasAttributes?: IAttributeNode[];
|
|
11
25
|
/**
|
|
12
26
|
* 允许文字子节点
|
|
13
27
|
*
|
|
@@ -1321,6 +1321,12 @@ const STYLE_ATTRIBUTE_CONFIG = exports.STYLE_ATTRIBUTE_CONFIG = {
|
|
|
1321
1321
|
scrollSnapAlign: {
|
|
1322
1322
|
// csstree-validator可校验
|
|
1323
1323
|
// 按照一般转换即可,无需额外转换
|
|
1324
|
+
},
|
|
1325
|
+
selectedFontSize: {
|
|
1326
|
+
validate: validateLengthNode
|
|
1327
|
+
},
|
|
1328
|
+
selectedBackgroundColor: {
|
|
1329
|
+
validate: validColorNode
|
|
1324
1330
|
}
|
|
1325
1331
|
};
|
|
1326
1332
|
/**
|
|
@@ -217,6 +217,17 @@ const elementConfig = {
|
|
|
217
217
|
name: {}
|
|
218
218
|
}
|
|
219
219
|
},
|
|
220
|
+
button: {
|
|
221
|
+
aliasName: 'input',
|
|
222
|
+
aliasAttributes: [{
|
|
223
|
+
name: 'type',
|
|
224
|
+
value: 'button'
|
|
225
|
+
}],
|
|
226
|
+
attributes: {
|
|
227
|
+
name: {},
|
|
228
|
+
value: {}
|
|
229
|
+
}
|
|
230
|
+
},
|
|
220
231
|
input: {
|
|
221
232
|
events: ['change', 'enterkeyclick', 'selectionchange'],
|
|
222
233
|
attributes: {
|
|
@@ -804,6 +815,14 @@ const elementConfig = {
|
|
|
804
815
|
enums: ['none', 'forwards']
|
|
805
816
|
}
|
|
806
817
|
}
|
|
818
|
+
},
|
|
819
|
+
'widget-container': {
|
|
820
|
+
events: ['load'],
|
|
821
|
+
attributes: {
|
|
822
|
+
uri: {},
|
|
823
|
+
size: {},
|
|
824
|
+
uidata: {}
|
|
825
|
+
}
|
|
807
826
|
}
|
|
808
827
|
}
|
|
809
828
|
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IE2eConfig
|
|
3
|
+
*/
|
|
4
|
+
export default interface IE2eConfig {
|
|
5
|
+
/**
|
|
6
|
+
* 测试文件的目录
|
|
7
|
+
*
|
|
8
|
+
* 绝对路径 或 相对config文件的路径
|
|
9
|
+
*
|
|
10
|
+
* @default "test"
|
|
11
|
+
*/
|
|
12
|
+
dir: string;
|
|
13
|
+
/**
|
|
14
|
+
* 测试模式打包,入口文件的在manifest中的名称
|
|
15
|
+
*/
|
|
16
|
+
entry: {
|
|
17
|
+
/**
|
|
18
|
+
* 自动化测试文件路径:相对config文件的路径 或 绝对路径
|
|
19
|
+
*
|
|
20
|
+
* @example "pages/index"
|
|
21
|
+
*/
|
|
22
|
+
path: string;
|
|
23
|
+
launchMode?: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* 待测试的页面配置
|
|
27
|
+
*/
|
|
28
|
+
testcases?: Array<ITestCase>;
|
|
29
|
+
}
|
|
30
|
+
export interface ITestCase {
|
|
31
|
+
/**
|
|
32
|
+
* 页面名称, 对应manifest中的路由名称
|
|
33
|
+
*
|
|
34
|
+
* @example "pages/index"
|
|
35
|
+
*/
|
|
36
|
+
name: string;
|
|
37
|
+
/**
|
|
38
|
+
* 测试完成后,等待多久回退到上一个页面,单位ms
|
|
39
|
+
*
|
|
40
|
+
* @default 0
|
|
41
|
+
*/
|
|
42
|
+
sleep?: number;
|
|
43
|
+
/**
|
|
44
|
+
* 测试完成后,是否回退到上一个页面
|
|
45
|
+
*
|
|
46
|
+
* @default true
|
|
47
|
+
*/
|
|
48
|
+
back?: boolean;
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -11,6 +11,7 @@ var _TemplateUtil = _interopRequireDefault(require("../translate/vela/utils/Temp
|
|
|
11
11
|
var _UxUtil = _interopRequireDefault(require("../utils/UxUtil"));
|
|
12
12
|
var _ScriptParser = _interopRequireDefault(require("./ScriptParser"));
|
|
13
13
|
var _StyleParser = _interopRequireDefault(require("./StyleParser"));
|
|
14
|
+
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
14
15
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
16
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
16
17
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
@@ -72,14 +73,51 @@ class UxParser {
|
|
|
72
73
|
};
|
|
73
74
|
break;
|
|
74
75
|
case 'style':
|
|
75
|
-
|
|
76
|
+
// 如果 style 标签有 src 属性,则读取对应的文件内容,否则直接使用 style 标签的内容
|
|
77
|
+
const src = _UxUtil.default.getStyleSrc(childNode, this.options.filePath);
|
|
78
|
+
let cssContent = '';
|
|
79
|
+
const filePath = this.options.filePath;
|
|
80
|
+
if (src) {
|
|
81
|
+
// 如果有 src 属性,且 style 标签内有内容,则提示用户 style 标签内的内容会被 src 文件覆盖
|
|
82
|
+
if (childNode.childNodes && childNode.childNodes.length > 0) {
|
|
83
|
+
this.options.onLog({
|
|
84
|
+
level: _sharedUtils.Loglevel.WARN,
|
|
85
|
+
filePath: this.options.filePath,
|
|
86
|
+
position: {
|
|
87
|
+
startLine: childNode.sourceCodeLocation?.startLine || 0,
|
|
88
|
+
startColumn: 0
|
|
89
|
+
},
|
|
90
|
+
message: [`style tag with src should not have inline content, src file will be used directly`]
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// 读取 src 文件内容,如果文件不存在,则提示用户
|
|
94
|
+
if (!_fsExtra.default.existsSync(src)) {
|
|
95
|
+
this.options.onLog({
|
|
96
|
+
level: _sharedUtils.Loglevel.WARN,
|
|
97
|
+
filePath: this.options.filePath,
|
|
98
|
+
position: {
|
|
99
|
+
startLine: childNode.sourceCodeLocation?.startLine || 0,
|
|
100
|
+
startColumn: 0
|
|
101
|
+
},
|
|
102
|
+
message: [`style src file does not exist: ${src}`]
|
|
103
|
+
});
|
|
104
|
+
} else {
|
|
105
|
+
cssContent = _fsExtra.default.readFileSync(src).toString();
|
|
106
|
+
// 解析 css 时需要用到文件路径,所以将options.filePath暂时替换为src,解析完成后再还原
|
|
107
|
+
this.options.filePath = src;
|
|
108
|
+
}
|
|
109
|
+
} else cssContent = parse5.serialize(childNode);
|
|
110
|
+
|
|
76
111
|
// 获取lang值,组合成文件名
|
|
77
112
|
const langType = _UxUtil.default.getLangType(childNode);
|
|
78
|
-
|
|
113
|
+
// 使用 src 时,cssFileName 以 src 的文件名为准,否则以当前解析的文件名为准
|
|
114
|
+
const cssFileName = src ? _path.default.basename(src) : _UxUtil.default.spliceFileName(fileName, langType);
|
|
79
115
|
// 转换全局变量为符合lang类型的字符串
|
|
80
116
|
const globalStyle = _UxUtil.default.convertGlobalJson(this.globalVar, langType);
|
|
81
117
|
// 解析CSS 转为 js格式的内容
|
|
82
118
|
const cssParserResult = await new _StyleParser.default(this.options, this.compilerOption, this.collectImageResource, childNode.sourceCodeLocation?.startLine || 0).parser(`${cssContent}\n${globalStyle}`, cssFileName);
|
|
119
|
+
// 还原 this.options.filePath
|
|
120
|
+
this.options.filePath = filePath;
|
|
83
121
|
// 多Style标签(TODO: 应该不支持多style标签)
|
|
84
122
|
ast.style.styleContent.push(...cssParserResult.ast.styleContent);
|
|
85
123
|
ast.style.content = parse5.serialize(childNode);
|
|
@@ -12,8 +12,9 @@ declare class ScriptToTypescript implements ITranslate<IScriptAst, SourceFile> {
|
|
|
12
12
|
options: IOptions;
|
|
13
13
|
readonly compilerOption: ITranslateOption;
|
|
14
14
|
readonly context: IFileLaneContext;
|
|
15
|
+
readonly disableCheckCode: boolean;
|
|
15
16
|
private _systemFeatures;
|
|
16
|
-
constructor(options: IOptions, compilerOption: ITranslateOption, context: IFileLaneContext);
|
|
17
|
+
constructor(options: IOptions, compilerOption: ITranslateOption, context: IFileLaneContext, disableCheckCode?: boolean);
|
|
17
18
|
translate(sourceTree: IScriptAst, offsetList: IOffset[]): Promise<{
|
|
18
19
|
targetTree: SourceFile;
|
|
19
20
|
mapList: never[];
|
|
@@ -21,19 +21,23 @@ const BabelPreset = require('@babel/preset-env');
|
|
|
21
21
|
class ScriptToTypescript {
|
|
22
22
|
_systemFeatures = (() => new Set())();
|
|
23
23
|
constructor(options, compilerOption, context) {
|
|
24
|
+
let disableCheckCode = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
24
25
|
this.options = options;
|
|
25
26
|
this.compilerOption = compilerOption;
|
|
26
27
|
this.context = context;
|
|
28
|
+
this.disableCheckCode = disableCheckCode;
|
|
27
29
|
}
|
|
28
30
|
async translate(sourceTree,
|
|
29
31
|
// eslint-disable-next-line
|
|
30
32
|
offsetList) {
|
|
31
33
|
// 检查代码错误
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
logs
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
if (!this.disableCheckCode) {
|
|
35
|
+
const logs = await this.checkCode(sourceTree);
|
|
36
|
+
if (logs) {
|
|
37
|
+
logs.forEach(log => {
|
|
38
|
+
this.options.onLog(log);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
37
41
|
}
|
|
38
42
|
// 使用babel实现替换,由此实现自动更新source map
|
|
39
43
|
const content = this.babelScript(sourceTree);
|
|
@@ -64,8 +68,11 @@ class ScriptToTypescript {
|
|
|
64
68
|
compilerOption: this.compilerOption
|
|
65
69
|
}]];
|
|
66
70
|
const pluginList = [{
|
|
67
|
-
enable: this.compilerOption.enableE2e,
|
|
71
|
+
enable: this.compilerOption.enableE2e && this.compilerOption.e2eConfigPath,
|
|
68
72
|
path: _path.default.resolve(__dirname, './plugins/e2e.js')
|
|
73
|
+
}, {
|
|
74
|
+
enable: this.compilerOption.enableE2e && !this.compilerOption.e2eConfigPath,
|
|
75
|
+
path: _path.default.resolve(__dirname, './plugins/e2e1.js')
|
|
69
76
|
}, {
|
|
70
77
|
enable: this.compilerOption.startPage && this.options.fileType === 'app',
|
|
71
78
|
path: _path.default.resolve(__dirname, './plugins/startPage.js')
|
|
@@ -88,7 +95,7 @@ class ScriptToTypescript {
|
|
|
88
95
|
targets: {
|
|
89
96
|
node: 8
|
|
90
97
|
},
|
|
91
|
-
modules:
|
|
98
|
+
modules: false
|
|
92
99
|
}]],
|
|
93
100
|
plugins
|
|
94
101
|
});
|
|
@@ -99,7 +106,7 @@ class ScriptToTypescript {
|
|
|
99
106
|
let position = undefined;
|
|
100
107
|
let message = babelError.message;
|
|
101
108
|
if (loc) {
|
|
102
|
-
const offsetLine = (sourceTree.sourceCodeLocation?.startLine ||
|
|
109
|
+
const offsetLine = (sourceTree.sourceCodeLocation?.startLine || 1) - 1;
|
|
103
110
|
const startLine = loc.line + offsetLine;
|
|
104
111
|
const startColumn = loc.column;
|
|
105
112
|
// babel 错误信息中包含行列信息,需要替换
|
|
@@ -8,7 +8,7 @@ var t = _interopRequireWildcard(require("@babel/types"));
|
|
|
8
8
|
var parser = _interopRequireWildcard(require("@babel/parser"));
|
|
9
9
|
var _path = _interopRequireDefault(require("path"));
|
|
10
10
|
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
11
|
-
var
|
|
11
|
+
var _UxUtil = _interopRequireDefault(require("../../../utils/UxUtil"));
|
|
12
12
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
13
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
14
14
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
@@ -62,10 +62,6 @@ function addAppTestCode(path) {
|
|
|
62
62
|
* b. 设置测试函数: 如果 onTestStart 方法已存在,则在其内部添加测试代码;否则,添加 onTestStart方法
|
|
63
63
|
*
|
|
64
64
|
*
|
|
65
|
-
* 2. 如果启用自动路由,且当前页面是首页
|
|
66
|
-
* a. 从routerList 中过滤出有测试文件的路由
|
|
67
|
-
* b. 在末尾添加 $generateAutoRunTest
|
|
68
|
-
* c. 在onShow 方法中调用 $generateAutoRunTest
|
|
69
65
|
*
|
|
70
66
|
*
|
|
71
67
|
* @description 示例
|
|
@@ -91,12 +87,20 @@ function addAppTestCode(path) {
|
|
|
91
87
|
* @param opts
|
|
92
88
|
*/
|
|
93
89
|
function addPageTestCode(path, opts) {
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
if (!opts.compilerOption.e2eConfigPath) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const e2eConfig = _UxUtil.default.getE2eConfig({
|
|
94
|
+
projectPath: opts.options.projectPath,
|
|
95
|
+
e2eConfigPath: opts.compilerOption.e2eConfigPath
|
|
96
|
+
});
|
|
97
|
+
const filePath = opts.options.filePath;
|
|
98
|
+
const testFilePath = getTestFilePath(filePath, opts, e2eConfig);
|
|
99
|
+
const testCaseConfig = getTestcaseConfig(filePath, opts, e2eConfig);
|
|
96
100
|
// 1
|
|
97
101
|
if (_fsExtra.default.existsSync(testFilePath)) {
|
|
98
102
|
// 1.a
|
|
99
|
-
const relativePath = _path.default.relative(_path.default.dirname(
|
|
103
|
+
const relativePath = _path.default.relative(_path.default.dirname(filePath), testFilePath);
|
|
100
104
|
const vmImport = t.importDeclaration([t.importDefaultSpecifier(t.identifier('fnTestCase'))], t.stringLiteral(relativePath));
|
|
101
105
|
if (path.parent.type === 'Program') {
|
|
102
106
|
path.parent.body.unshift(vmImport);
|
|
@@ -105,36 +109,21 @@ function addPageTestCode(path, opts) {
|
|
|
105
109
|
// 1.b
|
|
106
110
|
if (path.node.declaration.type === 'ObjectExpression') {
|
|
107
111
|
const properties = path.node.declaration.properties;
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// 2
|
|
113
|
-
if (isIndexPage(opts) && e2eConfig.autoRoute) {
|
|
114
|
-
let {
|
|
115
|
-
routerList,
|
|
116
|
-
pageSleep
|
|
117
|
-
} = e2eConfig.autoRoute;
|
|
118
|
-
routerList = routerList?.filter(item => hasTestFile(item, opts, e2eConfig));
|
|
119
|
-
if (!routerList?.length) {
|
|
120
|
-
opts.options.onLog({
|
|
121
|
-
level: _sharedUtils.Loglevel.WARN,
|
|
122
|
-
message: 'missing autoRoute.routerList'
|
|
123
|
-
});
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
// 2.a
|
|
127
|
-
|
|
128
|
-
if (path.node.declaration.type === 'ObjectExpression') {
|
|
129
|
-
const properties = path.node.declaration.properties;
|
|
130
|
-
|
|
131
|
-
// 2.b
|
|
132
|
-
insertFun('$generateAutoRunTest', generateAutoRouterFn(pageSleep, routerList), properties);
|
|
133
|
-
// 2.c
|
|
134
|
-
insertFun('onShow', generateAutoRouterInOnShow(), properties);
|
|
112
|
+
insertFn('onTestStart', generateTestFn(testCaseConfig), properties);
|
|
135
113
|
}
|
|
136
114
|
}
|
|
137
115
|
}
|
|
116
|
+
function getTestcaseConfig(filePath, opts, e2eConfig) {
|
|
117
|
+
const {
|
|
118
|
+
projectPath
|
|
119
|
+
} = opts.options;
|
|
120
|
+
const {
|
|
121
|
+
sourceRoot
|
|
122
|
+
} = opts.compilerOption;
|
|
123
|
+
const relativeSrc = _path.default.relative(_path.default.join(projectPath, sourceRoot || ''), filePath);
|
|
124
|
+
const pageName = _path.default.dirname(relativeSrc).replace(/\\/g, _path.default.posix.sep);
|
|
125
|
+
return e2eConfig.testcases?.find(item => item.name === pageName);
|
|
126
|
+
}
|
|
138
127
|
|
|
139
128
|
/**
|
|
140
129
|
* 插入函数
|
|
@@ -144,7 +133,7 @@ function addPageTestCode(path, opts) {
|
|
|
144
133
|
* @param name 函数名
|
|
145
134
|
* @param body 函数体
|
|
146
135
|
*/
|
|
147
|
-
function
|
|
136
|
+
function insertFn(name, body, properties) {
|
|
148
137
|
const fun = properties.find(p => p.type === 'ObjectMethod' && p.key.name === name);
|
|
149
138
|
if (fun) {
|
|
150
139
|
fun.body.body.push(...body.body);
|
|
@@ -155,77 +144,6 @@ function insertFun(name, body, properties) {
|
|
|
155
144
|
}, [], body));
|
|
156
145
|
}
|
|
157
146
|
}
|
|
158
|
-
function hasTestFile(router, opts, e2eConfig) {
|
|
159
|
-
const manifest = getManifest(opts);
|
|
160
|
-
if (manifest) {
|
|
161
|
-
const {
|
|
162
|
-
pages
|
|
163
|
-
} = manifest.router;
|
|
164
|
-
const pageRouter = pages[router];
|
|
165
|
-
if (!pageRouter) {
|
|
166
|
-
opts.options.onLog({
|
|
167
|
-
level: _sharedUtils.Loglevel.WARN,
|
|
168
|
-
message: [{
|
|
169
|
-
word: router
|
|
170
|
-
}, `missing router in manifest.json`]
|
|
171
|
-
});
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
const pagePath = `${opts.compilerOption.sourceRoot}/${router}/${pageRouter.component}`;
|
|
175
|
-
const testFilePath = getTestFilePath(pagePath, opts, e2eConfig);
|
|
176
|
-
return _fsExtra.default.existsSync(testFilePath);
|
|
177
|
-
}
|
|
178
|
-
return false;
|
|
179
|
-
}
|
|
180
|
-
function isIndexPage(opts) {
|
|
181
|
-
const manifest = getManifest(opts);
|
|
182
|
-
if (manifest) {
|
|
183
|
-
const {
|
|
184
|
-
entry,
|
|
185
|
-
pages
|
|
186
|
-
} = manifest.router;
|
|
187
|
-
const entryItem = pages[entry];
|
|
188
|
-
const entryPath = `${entry}/${entryItem.component}`;
|
|
189
|
-
const sourcePath = _path.default.join(opts.options.projectPath, opts.compilerOption.sourceRoot);
|
|
190
|
-
const filePath = _path.default.relative(sourcePath, opts.options.filePath);
|
|
191
|
-
const filePathParsed = _path.default.parse(filePath);
|
|
192
|
-
return entryPath === `${filePathParsed.dir}/${filePathParsed.name}`;
|
|
193
|
-
}
|
|
194
|
-
return false;
|
|
195
|
-
}
|
|
196
|
-
function getManifest(opts) {
|
|
197
|
-
const manifestPath = _path.default.resolve(opts.options.projectPath, opts.compilerOption.sourceRoot, 'manifest.json');
|
|
198
|
-
if (manifestPath) {
|
|
199
|
-
return _fsExtra.default.readJSONSync(manifestPath);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
function getE2eConfig(opts) {
|
|
203
|
-
const defaultTestDir = 'test';
|
|
204
|
-
let result = {
|
|
205
|
-
testDir: _path.default.join(opts.options.projectPath, defaultTestDir)
|
|
206
|
-
};
|
|
207
|
-
const {
|
|
208
|
-
projectPath
|
|
209
|
-
} = opts.options;
|
|
210
|
-
const {
|
|
211
|
-
e2eConfigPath
|
|
212
|
-
} = opts.compilerOption;
|
|
213
|
-
if (e2eConfigPath) {
|
|
214
|
-
const configFilePath = _path.default.resolve(projectPath, e2eConfigPath);
|
|
215
|
-
const configFileDir = _path.default.dirname(configFilePath);
|
|
216
|
-
if (_fsExtra.default.existsSync(configFilePath)) {
|
|
217
|
-
result = _fsExtra.default.readJSONSync(configFilePath, 'utf-8');
|
|
218
|
-
|
|
219
|
-
// 目录转换为绝对路径
|
|
220
|
-
if (result) {
|
|
221
|
-
result.testDir = _path.default.resolve(configFileDir, result.testDir || defaultTestDir);
|
|
222
|
-
}
|
|
223
|
-
} else {
|
|
224
|
-
throw new Error(`e2e Configuration file does not exist: ${configFilePath}`);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
return result;
|
|
228
|
-
}
|
|
229
147
|
|
|
230
148
|
/**
|
|
231
149
|
* 获取源文件对应的测试文件地址
|
|
@@ -243,14 +161,18 @@ function getTestFilePath(sourceFile, opts, e2eConfig) {
|
|
|
243
161
|
} = opts.compilerOption;
|
|
244
162
|
const relativeSrc = _path.default.relative(_path.default.join(projectPath, sourceRoot || ''), sourceFile);
|
|
245
163
|
const parsed = _path.default.parse(relativeSrc);
|
|
246
|
-
return _path.default.join(e2eConfig.
|
|
164
|
+
return _path.default.join(e2eConfig.dir, parsed.dir, `${parsed.name}.js`);
|
|
247
165
|
}
|
|
248
166
|
|
|
249
167
|
/**
|
|
250
168
|
* 获取测试函数的函数体
|
|
251
169
|
* @returns
|
|
252
170
|
*/
|
|
253
|
-
function generateTestFn() {
|
|
171
|
+
function generateTestFn(config) {
|
|
172
|
+
const {
|
|
173
|
+
sleep,
|
|
174
|
+
back = true
|
|
175
|
+
} = config || {};
|
|
254
176
|
const fn = `function(){
|
|
255
177
|
this.$options = this._options || this.$options;
|
|
256
178
|
if (this.$options._descriptor) {
|
|
@@ -262,46 +184,16 @@ function generateTestFn() {
|
|
|
262
184
|
global.qat = new VelaQuickappTest();
|
|
263
185
|
setTimeout(() => {
|
|
264
186
|
typeof fnTestCase === 'function' && fnTestCase(this)
|
|
265
|
-
qat.run(() => {
|
|
187
|
+
qat.run(async () => {
|
|
266
188
|
if (this.back !== "false") {
|
|
267
189
|
console.info("拥有关联测试用例,测试完毕,返回到之前的页面");
|
|
268
190
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
269
191
|
var _system = _interopRequireDefault($app_require$('@app-module/system.router'));
|
|
270
|
-
|
|
192
|
+
${sleep ? `await new Promise(resolve => setTimeout(resolve, ${sleep}));` : ''}
|
|
193
|
+
${back ? `_system.default.back();` : ''}
|
|
271
194
|
}
|
|
272
195
|
});
|
|
273
196
|
}, global.CASE_TEST_START);
|
|
274
197
|
}`;
|
|
275
198
|
return parser.parseExpression(fn).body;
|
|
276
|
-
}
|
|
277
|
-
function generateAutoRouterFn() {
|
|
278
|
-
let sleep = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 3000;
|
|
279
|
-
let routerList = arguments.length > 1 ? arguments[1] : undefined;
|
|
280
|
-
const fn = `function(){
|
|
281
|
-
const routerList = ${JSON.stringify(routerList)}
|
|
282
|
-
if (!routerList) {
|
|
283
|
-
console.log('missing routerList');
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
if (this.autoTestPageIndex === undefined) {
|
|
287
|
-
this.autoTestPageIndex = -1;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
setTimeout(() => {
|
|
291
|
-
if (++this.autoTestPageIndex < routerList.length) {
|
|
292
|
-
const uri = routerList[this.autoTestPageIndex];
|
|
293
|
-
console.log(\`auto test page=\${uri}, index=\${this.autoTestPageIndex}\`);
|
|
294
|
-
router.push({ uri });
|
|
295
|
-
} else {
|
|
296
|
-
console.log('auto test finish');
|
|
297
|
-
}
|
|
298
|
-
}, ${sleep});
|
|
299
|
-
}`;
|
|
300
|
-
return parser.parseExpression(fn).body;
|
|
301
|
-
}
|
|
302
|
-
function generateAutoRouterInOnShow() {
|
|
303
|
-
const fn = `function(){
|
|
304
|
-
this.$generateAutoRunTest();
|
|
305
|
-
}`;
|
|
306
|
-
return parser.parseExpression(fn).body;
|
|
307
199
|
}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = e2e;
|
|
7
|
+
var t = _interopRequireWildcard(require("@babel/types"));
|
|
8
|
+
var parser = _interopRequireWildcard(require("@babel/parser"));
|
|
9
|
+
var _path = _interopRequireDefault(require("path"));
|
|
10
|
+
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
11
|
+
var _sharedUtils = require("@aiot-toolkit/shared-utils");
|
|
12
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
14
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
15
|
+
/**
|
|
16
|
+
* 用于添加应用自动化测试代码
|
|
17
|
+
* 分为两种情况
|
|
18
|
+
* 1. app文件
|
|
19
|
+
* 2. page 文件
|
|
20
|
+
*/
|
|
21
|
+
function e2e() {
|
|
22
|
+
return {
|
|
23
|
+
visitor: {
|
|
24
|
+
ExportDefaultDeclaration(path, _ref) {
|
|
25
|
+
let {
|
|
26
|
+
opts
|
|
27
|
+
} = _ref;
|
|
28
|
+
const opts2 = opts;
|
|
29
|
+
const options = opts2.options;
|
|
30
|
+
switch (options.fileType) {
|
|
31
|
+
case 'page':
|
|
32
|
+
addPageTestCode(path, opts2);
|
|
33
|
+
break;
|
|
34
|
+
case 'app':
|
|
35
|
+
addAppTestCode(path);
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 添加 app 的测试代码
|
|
45
|
+
*
|
|
46
|
+
* 引入测试框架文件
|
|
47
|
+
* @param path
|
|
48
|
+
* @param opts
|
|
49
|
+
*/
|
|
50
|
+
function addAppTestCode(path) {
|
|
51
|
+
const runtimePath = _path.default.join(__dirname, '../runtime/velaTestLibrary.js');
|
|
52
|
+
const appImport = t.importDeclaration([], t.stringLiteral(runtimePath));
|
|
53
|
+
if (path.parent.type === 'Program') {
|
|
54
|
+
path.parent.body.unshift(appImport);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 添加页面的测试代码
|
|
60
|
+
* 1. 如果测试文件存在,则
|
|
61
|
+
* a. import 测试文件
|
|
62
|
+
* b. 设置测试函数: 如果 onTestStart 方法已存在,则在其内部添加测试代码;否则,添加 onTestStart方法
|
|
63
|
+
*
|
|
64
|
+
*
|
|
65
|
+
* 2. 如果启用自动路由,且当前页面是首页
|
|
66
|
+
* a. 从routerList 中过滤出有测试文件的路由
|
|
67
|
+
* b. 在末尾添加 $generateAutoRunTest
|
|
68
|
+
* c. 在onShow 方法中调用 $generateAutoRunTest
|
|
69
|
+
*
|
|
70
|
+
*
|
|
71
|
+
* @description 示例
|
|
72
|
+
*
|
|
73
|
+
* 源码 `src/home/myHome.ux`
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* export default {}
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* 产物
|
|
80
|
+
* ```
|
|
81
|
+
* import fnTestCase from 'test/home/myHome.js'
|
|
82
|
+
*
|
|
83
|
+
* export default {
|
|
84
|
+
* onTestStart: (){
|
|
85
|
+
* // code
|
|
86
|
+
* }
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* @param path
|
|
91
|
+
* @param opts
|
|
92
|
+
*/
|
|
93
|
+
function addPageTestCode(path, opts) {
|
|
94
|
+
const e2eConfig = getE2eConfig(opts);
|
|
95
|
+
const testFilePath = getTestFilePath(opts.options.filePath, opts, e2eConfig);
|
|
96
|
+
// 1
|
|
97
|
+
if (_fsExtra.default.existsSync(testFilePath)) {
|
|
98
|
+
// 1.a
|
|
99
|
+
const relativePath = _path.default.relative(_path.default.dirname(opts.options.filePath), testFilePath);
|
|
100
|
+
const vmImport = t.importDeclaration([t.importDefaultSpecifier(t.identifier('fnTestCase'))], t.stringLiteral(relativePath));
|
|
101
|
+
if (path.parent.type === 'Program') {
|
|
102
|
+
path.parent.body.unshift(vmImport);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 1.b
|
|
106
|
+
if (path.node.declaration.type === 'ObjectExpression') {
|
|
107
|
+
const properties = path.node.declaration.properties;
|
|
108
|
+
insertFun('onTestStart', generateTestFn(), properties);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 2
|
|
113
|
+
if (isIndexPage(opts) && e2eConfig.autoRoute) {
|
|
114
|
+
let {
|
|
115
|
+
routerList,
|
|
116
|
+
pageSleep
|
|
117
|
+
} = e2eConfig.autoRoute;
|
|
118
|
+
routerList = routerList?.filter(item => hasTestFile(item, opts, e2eConfig));
|
|
119
|
+
if (!routerList?.length) {
|
|
120
|
+
opts.options.onLog({
|
|
121
|
+
level: _sharedUtils.Loglevel.WARN,
|
|
122
|
+
message: 'missing autoRoute.routerList'
|
|
123
|
+
});
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
// 2.a
|
|
127
|
+
|
|
128
|
+
if (path.node.declaration.type === 'ObjectExpression') {
|
|
129
|
+
const properties = path.node.declaration.properties;
|
|
130
|
+
|
|
131
|
+
// 2.b
|
|
132
|
+
insertFun('$generateAutoRunTest', generateAutoRouterFn(pageSleep, routerList), properties);
|
|
133
|
+
// 2.c
|
|
134
|
+
insertFun('onShow', generateAutoRouterInOnShow(), properties);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* 插入函数
|
|
141
|
+
*
|
|
142
|
+
* 如果已存在,把函数体插入到指定函数末尾;不存在,则添加
|
|
143
|
+
*
|
|
144
|
+
* @param name 函数名
|
|
145
|
+
* @param body 函数体
|
|
146
|
+
*/
|
|
147
|
+
function insertFun(name, body, properties) {
|
|
148
|
+
const fun = properties.find(p => p.type === 'ObjectMethod' && p.key.name === name);
|
|
149
|
+
if (fun) {
|
|
150
|
+
fun.body.body.push(...body.body);
|
|
151
|
+
} else {
|
|
152
|
+
properties.push(t.objectMethod('method', {
|
|
153
|
+
name: name,
|
|
154
|
+
type: 'Identifier'
|
|
155
|
+
}, [], body));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function hasTestFile(router, opts, e2eConfig) {
|
|
159
|
+
const manifest = getManifest(opts);
|
|
160
|
+
if (manifest) {
|
|
161
|
+
const {
|
|
162
|
+
pages
|
|
163
|
+
} = manifest.router;
|
|
164
|
+
const pageRouter = pages[router];
|
|
165
|
+
if (!pageRouter) {
|
|
166
|
+
opts.options.onLog({
|
|
167
|
+
level: _sharedUtils.Loglevel.WARN,
|
|
168
|
+
message: [{
|
|
169
|
+
word: router
|
|
170
|
+
}, `missing router in manifest.json`]
|
|
171
|
+
});
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
const pagePath = `${opts.compilerOption.sourceRoot}/${router}/${pageRouter.component}`;
|
|
175
|
+
const testFilePath = getTestFilePath(pagePath, opts, e2eConfig);
|
|
176
|
+
return _fsExtra.default.existsSync(testFilePath);
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
function isIndexPage(opts) {
|
|
181
|
+
const manifest = getManifest(opts);
|
|
182
|
+
if (manifest) {
|
|
183
|
+
const {
|
|
184
|
+
entry,
|
|
185
|
+
pages
|
|
186
|
+
} = manifest.router;
|
|
187
|
+
const entryItem = pages[entry];
|
|
188
|
+
const entryPath = `${entry}/${entryItem.component}`;
|
|
189
|
+
const sourcePath = _path.default.join(opts.options.projectPath, opts.compilerOption.sourceRoot);
|
|
190
|
+
const filePath = _path.default.relative(sourcePath, opts.options.filePath);
|
|
191
|
+
const filePathParsed = _path.default.parse(filePath);
|
|
192
|
+
return entryPath === `${filePathParsed.dir}/${filePathParsed.name}`;
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
function getManifest(opts) {
|
|
197
|
+
const manifestPath = _path.default.resolve(opts.options.projectPath, opts.compilerOption.sourceRoot, 'manifest.json');
|
|
198
|
+
if (manifestPath) {
|
|
199
|
+
return _fsExtra.default.readJSONSync(manifestPath);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function getE2eConfig(opts) {
|
|
203
|
+
const defaultTestDir = 'test';
|
|
204
|
+
let result = {
|
|
205
|
+
testDir: _path.default.join(opts.options.projectPath, defaultTestDir)
|
|
206
|
+
};
|
|
207
|
+
const {
|
|
208
|
+
projectPath
|
|
209
|
+
} = opts.options;
|
|
210
|
+
const {
|
|
211
|
+
e2eConfigPath
|
|
212
|
+
} = opts.compilerOption;
|
|
213
|
+
if (e2eConfigPath) {
|
|
214
|
+
const configFilePath = _path.default.resolve(projectPath, e2eConfigPath);
|
|
215
|
+
const configFileDir = _path.default.dirname(configFilePath);
|
|
216
|
+
if (_fsExtra.default.existsSync(configFilePath)) {
|
|
217
|
+
result = _fsExtra.default.readJSONSync(configFilePath, 'utf-8');
|
|
218
|
+
|
|
219
|
+
// 目录转换为绝对路径
|
|
220
|
+
if (result) {
|
|
221
|
+
result.testDir = _path.default.resolve(configFileDir, result.testDir || defaultTestDir);
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
throw new Error(`e2e Configuration file does not exist: ${configFilePath}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* 获取源文件对应的测试文件地址
|
|
232
|
+
* @param sourceFile 源文件
|
|
233
|
+
* @param opts
|
|
234
|
+
* @param e2eConfig
|
|
235
|
+
* @returns
|
|
236
|
+
*/
|
|
237
|
+
function getTestFilePath(sourceFile, opts, e2eConfig) {
|
|
238
|
+
const {
|
|
239
|
+
projectPath
|
|
240
|
+
} = opts.options;
|
|
241
|
+
const {
|
|
242
|
+
sourceRoot
|
|
243
|
+
} = opts.compilerOption;
|
|
244
|
+
const relativeSrc = _path.default.relative(_path.default.join(projectPath, sourceRoot || ''), sourceFile);
|
|
245
|
+
const parsed = _path.default.parse(relativeSrc);
|
|
246
|
+
return _path.default.join(e2eConfig.testDir, parsed.dir, `${parsed.name}.js`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* 获取测试函数的函数体
|
|
251
|
+
* @returns
|
|
252
|
+
*/
|
|
253
|
+
function generateTestFn() {
|
|
254
|
+
const fn = `function(){
|
|
255
|
+
this.$options = this._options || this.$options;
|
|
256
|
+
if (this.$options._descriptor) {
|
|
257
|
+
this.$options._descriptor["back"] = {
|
|
258
|
+
access: "public",
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
global.CASE_TEST_START = global.CASE_TEST_START || 1000;
|
|
262
|
+
global.qat = new VelaQuickappTest();
|
|
263
|
+
setTimeout(() => {
|
|
264
|
+
typeof fnTestCase === 'function' && fnTestCase(this)
|
|
265
|
+
qat.run(() => {
|
|
266
|
+
if (this.back !== "false") {
|
|
267
|
+
console.info("拥有关联测试用例,测试完毕,返回到之前的页面");
|
|
268
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
269
|
+
var _system = _interopRequireDefault($app_require$('@app-module/system.router'));
|
|
270
|
+
_system.default.back();
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
}, global.CASE_TEST_START);
|
|
274
|
+
}`;
|
|
275
|
+
return parser.parseExpression(fn).body;
|
|
276
|
+
}
|
|
277
|
+
function generateAutoRouterFn() {
|
|
278
|
+
let sleep = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 3000;
|
|
279
|
+
let routerList = arguments.length > 1 ? arguments[1] : undefined;
|
|
280
|
+
const fn = `function(){
|
|
281
|
+
const routerList = ${JSON.stringify(routerList)}
|
|
282
|
+
if (!routerList) {
|
|
283
|
+
console.log('missing routerList');
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
if (this.autoTestPageIndex === undefined) {
|
|
287
|
+
this.autoTestPageIndex = -1;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
setTimeout(() => {
|
|
291
|
+
if (++this.autoTestPageIndex < routerList.length) {
|
|
292
|
+
const uri = routerList[this.autoTestPageIndex];
|
|
293
|
+
console.log(\`auto test page=\${uri}, index=\${this.autoTestPageIndex}\`);
|
|
294
|
+
router.push({ uri });
|
|
295
|
+
} else {
|
|
296
|
+
console.log('auto test finish');
|
|
297
|
+
}
|
|
298
|
+
}, ${sleep});
|
|
299
|
+
}`;
|
|
300
|
+
return parser.parseExpression(fn).body;
|
|
301
|
+
}
|
|
302
|
+
function generateAutoRouterInOnShow() {
|
|
303
|
+
const fn = `function(){
|
|
304
|
+
this.$generateAutoRunTest();
|
|
305
|
+
}`;
|
|
306
|
+
return parser.parseExpression(fn).body;
|
|
307
|
+
}
|
|
@@ -114,5 +114,11 @@ class SourceMapUtil {
|
|
|
114
114
|
let lineCount = (originStr.match(/\n/g) || []).length + 1;
|
|
115
115
|
return lineCount;
|
|
116
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* 拼接正文和source map
|
|
119
|
+
*/
|
|
120
|
+
static concatSourceMap(content, sourceMap) {
|
|
121
|
+
return `${content}\n//# sourceMappingURL=data:application/json;base64,${Buffer.from(sourceMap).toString('base64')}`;
|
|
122
|
+
}
|
|
117
123
|
}
|
|
118
124
|
var _default = exports.default = SourceMapUtil;
|
|
@@ -367,6 +367,7 @@ class TemplateUtil {
|
|
|
367
367
|
}
|
|
368
368
|
const elementConfig = getElementConfig(tag.name);
|
|
369
369
|
const effectTag = elementConfig?.aliasName || tag.name;
|
|
370
|
+
const aliasAttributes = elementConfig?.aliasAttributes;
|
|
370
371
|
const {
|
|
371
372
|
globalInstance,
|
|
372
373
|
dataInstance,
|
|
@@ -374,7 +375,7 @@ class TemplateUtil {
|
|
|
374
375
|
} = this.context;
|
|
375
376
|
const result = `${globalInstance}.${callerName}("${effectTag}", ${_sharedUtils.StringUtil.objectToString({
|
|
376
377
|
[dataInstance]: dataInstanceValue,
|
|
377
|
-
__opts__: await this.attributesToObject(attributes, identifiers, {
|
|
378
|
+
__opts__: await this.attributesToObject(aliasAttributes ? [...aliasAttributes, ...attributes] : attributes, identifiers, {
|
|
378
379
|
nameToCamel: true
|
|
379
380
|
})
|
|
380
381
|
})}, ${children})`;
|
|
@@ -537,7 +537,7 @@ class StyleUtil {
|
|
|
537
537
|
if (!(0, _StyleSelectorType.isSupportMediaType)(mediaTypeName, projectType)) {
|
|
538
538
|
// 报错
|
|
539
539
|
onLog({
|
|
540
|
-
level: _sharedUtils.Loglevel.
|
|
540
|
+
level: _sharedUtils.Loglevel.WARN,
|
|
541
541
|
filePath: filePath,
|
|
542
542
|
position: node.loc ? styleMapUil.transfromLocToPosition(node.loc) : undefined,
|
|
543
543
|
message: [`Unsupported media type `, {
|
package/lib/ux/utils/UxUtil.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Dictionary } from '@aiot-toolkit/shared-utils';
|
|
|
2
2
|
import { Element } from 'aiot-parse5/dist/tree-adapters/default';
|
|
3
3
|
import IImportAst from '../interface/IImportAst';
|
|
4
4
|
import ITranslateOption from '../interface/ITranslateOption';
|
|
5
|
+
import IE2eConfig from '../interface/IE2eConfig';
|
|
5
6
|
/**
|
|
6
7
|
* UxParserUtil
|
|
7
8
|
*/
|
|
@@ -47,5 +48,18 @@ declare class UxUtil {
|
|
|
47
48
|
*/
|
|
48
49
|
static isAbsoluteResource(path?: string): boolean;
|
|
49
50
|
static importToTypescript(importList: IImportAst[], compilerOption: ITranslateOption): string[];
|
|
51
|
+
static getE2eConfig(option: {
|
|
52
|
+
projectPath: string;
|
|
53
|
+
e2eConfigPath: string;
|
|
54
|
+
}): IE2eConfig;
|
|
55
|
+
/**
|
|
56
|
+
* 获取 style 标签的 src 属性值
|
|
57
|
+
* 如果 src 是相对路径,则需要拼接路径
|
|
58
|
+
*
|
|
59
|
+
* @param node
|
|
60
|
+
* @param filePath
|
|
61
|
+
* @returns
|
|
62
|
+
*/
|
|
63
|
+
static getStyleSrc(node: Element, filePath: string): string;
|
|
50
64
|
}
|
|
51
65
|
export default UxUtil;
|
package/lib/ux/utils/UxUtil.js
CHANGED
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
var _path = _interopRequireDefault(require("path"));
|
|
8
|
+
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
8
9
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
10
|
/**
|
|
10
11
|
* UxParserUtil
|
|
@@ -97,7 +98,7 @@ class UxUtil {
|
|
|
97
98
|
name,
|
|
98
99
|
src
|
|
99
100
|
} = item;
|
|
100
|
-
const pushList = [
|
|
101
|
+
const pushList = [`import ${name.toLowerCase().replace(/-/g, '_')}_comp from '${src}'`];
|
|
101
102
|
|
|
102
103
|
// 如果开启统计,添加引用组件耗时日志
|
|
103
104
|
if (compilerOption.enableStats) {
|
|
@@ -108,5 +109,45 @@ class UxUtil {
|
|
|
108
109
|
}
|
|
109
110
|
return appImport;
|
|
110
111
|
}
|
|
112
|
+
static getE2eConfig(option) {
|
|
113
|
+
const defaultTestDir = 'test';
|
|
114
|
+
const {
|
|
115
|
+
projectPath,
|
|
116
|
+
e2eConfigPath
|
|
117
|
+
} = option;
|
|
118
|
+
const configFilePath = _path.default.resolve(projectPath, e2eConfigPath);
|
|
119
|
+
const configFileDir = _path.default.dirname(configFilePath);
|
|
120
|
+
if (_fsExtra.default.existsSync(configFilePath)) {
|
|
121
|
+
const obj = _fsExtra.default.readJSONSync(configFilePath, 'utf-8');
|
|
122
|
+
const dir = _path.default.resolve(configFileDir, obj.dir || defaultTestDir);
|
|
123
|
+
if (!obj.entry) {
|
|
124
|
+
throw new Error(`e2e Configuration file error: missing entry field`);
|
|
125
|
+
}
|
|
126
|
+
const result = {
|
|
127
|
+
...obj,
|
|
128
|
+
dir
|
|
129
|
+
};
|
|
130
|
+
return result;
|
|
131
|
+
} else {
|
|
132
|
+
throw new Error(`e2e Configuration file does not exist: ${configFilePath}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 获取 style 标签的 src 属性值
|
|
138
|
+
* 如果 src 是相对路径,则需要拼接路径
|
|
139
|
+
*
|
|
140
|
+
* @param node
|
|
141
|
+
* @param filePath
|
|
142
|
+
* @returns
|
|
143
|
+
*/
|
|
144
|
+
static getStyleSrc(node, filePath) {
|
|
145
|
+
for (let attr of node.attrs) {
|
|
146
|
+
if (attr.name === 'src') {
|
|
147
|
+
return UxUtil.isAbsoluteResource(attr.value) ? attr.value : _path.default.join(_path.default.dirname(filePath), attr.value);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return '';
|
|
151
|
+
}
|
|
111
152
|
}
|
|
112
153
|
var _default = exports.default = UxUtil;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiot-toolkit/parser",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0-prender.1",
|
|
4
4
|
"description": "Parse the source code of aiot and convert it to the AST (Abstract Syntax Tree) of the target code.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"aiot",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"test": "node ./__tests__/parser.test.js"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@aiot-toolkit/shared-utils": "2.0
|
|
23
|
+
"@aiot-toolkit/shared-utils": "2.1.0-prender.1",
|
|
24
24
|
"@babel/core": "^7.23.6",
|
|
25
25
|
"@babel/generator": "^7.24.10",
|
|
26
26
|
"@babel/parser": "^7.24.8",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"css-tree": "npm:aiot-css-tree@^2.3.1",
|
|
32
32
|
"csstree-validator": "^3.0.0",
|
|
33
33
|
"eslint": "^8.46.0",
|
|
34
|
-
"file-lane": "2.0
|
|
34
|
+
"file-lane": "2.1.0-prender.1",
|
|
35
35
|
"fs-extra": "^11.2.0",
|
|
36
36
|
"google-protobuf": "^3.21.2",
|
|
37
37
|
"less": "^4.2.0",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"@types/tinycolor2": "^1.4.6",
|
|
61
61
|
"babel-plugin-tester": "^11.0.4"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "8bb39a59fbe7a7c22c1167e69d44c78024330cec"
|
|
64
64
|
}
|