@aiot-toolkit/parser 2.0.6-beta.1 → 2.0.6-beta.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.
@@ -1,6 +1,6 @@
1
1
  import { Dictionary, Loglevel } from '@aiot-toolkit/shared-utils';
2
2
  import { StyleMessage } from '@aiot-toolkit/shared-utils';
3
- import { BlockItem, StyleItem } from '../../interface/IStyleAst';
3
+ import { BlockItem, StyleItem } from '../interface/IStyleAst';
4
4
  type ValidateInfo = {
5
5
  level: Loglevel;
6
6
  message: StyleMessage[];
@@ -5,8 +5,8 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.STYLE_ATTRIBUTE_LIST = exports.STYLE_ATTRIBUTE_CONFIG = void 0;
7
7
  var _sharedUtils = require("@aiot-toolkit/shared-utils");
8
- var _ExtendedBoxStyle = _interopRequireDefault(require("../../translate/vela/utils/ExtendedBoxStyle"));
9
- var _UxUtil = _interopRequireDefault(require("../../utils/UxUtil"));
8
+ var _ExtendedBoxStyle = _interopRequireDefault(require("../translate/vela/utils/ExtendedBoxStyle"));
9
+ var _UxUtil = _interopRequireDefault(require("../utils/UxUtil"));
10
10
  var _cssTree = _interopRequireDefault(require("css-tree"));
11
11
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
12
  const REGEXP_NAME = /^([a-zA-Z_]+[a-zA-Z0-9]*\s*,\s*)*[a-zA-Z_]+[a-zA-Z0-9]*$/;
@@ -1345,9 +1345,9 @@ function validateLengthNode(sourceNode) {
1345
1345
  value[0] = value[0];
1346
1346
  const validResult = validLength(value[0]);
1347
1347
  if (validResult.message.length > 0) {
1348
- validateInfo.message = [`The value verification of attribute`, {
1349
- word: attributeName
1350
- }, `failed.`, ...validResult.message];
1348
+ validateInfo.message = [`The value of attribute`, {
1349
+ word: `${attributeName}:`
1350
+ }, ...validResult.message];
1351
1351
  }
1352
1352
  }
1353
1353
  return validateInfo;
@@ -1363,11 +1363,9 @@ function validLength(value) {
1363
1363
  message: []
1364
1364
  };
1365
1365
  if (_cssTree.default.lexer.matchType('length', value.value + value.unit).error !== null) {
1366
- validateInfo.message = [`The length value is`, {
1367
- word: value.value || 'null'
1368
- }, `, unit is`, {
1369
- word: value.unit || 'null'
1370
- }, `, which does not meet the length standard.`];
1366
+ validateInfo.message = [{
1367
+ word: `${value.value}${value.unit}`
1368
+ }, `is invalid.`];
1371
1369
  }
1372
1370
  return validateInfo;
1373
1371
  }
@@ -1549,30 +1547,24 @@ function validPosition(sourceNode) {
1549
1547
  name: attributeName
1550
1548
  } = sourceNode;
1551
1549
  if (value.length <= 0) {
1552
- validateInfo.message = [`Error parsing the value of attribute`, {
1550
+ validateInfo.message = [`The value of attribute`, {
1553
1551
  word: `${attributeName}`
1554
- }];
1552
+ }, 'is invalid.'];
1555
1553
  } else if (value.length > 3) {
1556
- validateInfo.message = [`Error parsing the value length`, `of`, {
1557
- word: `'${attributeName}'`
1558
- }, `is`, {
1559
- word: value.length
1560
- }, `, which does not meet the requirement.`];
1554
+ validateInfo.message = [`The value length`, `of attribute`, {
1555
+ word: `${attributeName}: ${value.length}`
1556
+ }, `is invalid.`];
1561
1557
  } else {
1562
1558
  value.forEach(v => {
1563
1559
  v = v;
1564
1560
  const validResult = validLength(v);
1565
1561
  // 有报错
1566
1562
  if (validResult.message.length > 0) {
1567
- validateInfo.message.push(...validResult.message);
1563
+ validateInfo.message = [`The value of attribute`, {
1564
+ word: `${attributeName}:`
1565
+ }, ...validResult.message];
1568
1566
  }
1569
1567
  });
1570
- // 如果有报错,添加一下属性名
1571
- if (validateInfo.message.length > 0) {
1572
- validateInfo.message.unshift(`The value verification of attribute `, {
1573
- word: attributeName
1574
- }, `failed.`);
1575
- }
1576
1568
  }
1577
1569
  return validateInfo;
1578
1570
  }
@@ -93,6 +93,12 @@ const elementConfig = {
93
93
  }
94
94
  }
95
95
  },
96
+ markdown: {
97
+ allowTextChildren: true,
98
+ attributes: {
99
+ value: {}
100
+ }
101
+ },
96
102
  'arc-text': {
97
103
  allowTextChildren: true,
98
104
  attributes: {
@@ -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";
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * IStyleError
3
3
  */
4
+ import { StyleMessage } from '@aiot-toolkit/shared-utils';
4
5
  export interface IStyleError {
5
- message: string;
6
+ messages: StyleMessage[];
6
7
  details: string;
7
8
  startLine: number;
8
9
  startCol: number;
@@ -14,7 +14,8 @@ class ScriptParser {
14
14
  parser(content) {
15
15
  // const { onLog } = this.options
16
16
  const ast = {
17
- content
17
+ // 判断content是否包含有效js内容,若只包含\n\r\t空白符,则content为''
18
+ content: content.trim() ? content : ''
18
19
  };
19
20
  return {
20
21
  ast
@@ -3,7 +3,7 @@ import IOptions from '../config/IOptions';
3
3
  import { IStyleAst } from '../interface/IStyleAst';
4
4
  import ITranslateOption from '../interface/ITranslateOption';
5
5
  import { IImageFunction } from '../interface/IImageResource';
6
- import { RawSourceMap, SourceMapConsumer } from 'source-map';
6
+ import { SourceMapConsumer } from 'source-map';
7
7
  /**
8
8
  * StyleParser
9
9
  * 1. 根据语言类型分别转为CSS样式
@@ -15,9 +15,10 @@ declare class StyleParser implements IParser<IStyleAst> {
15
15
  readonly compilerOption: ITranslateOption;
16
16
  collectImageResource: IImageFunction;
17
17
  readonly styleLineOffset: number;
18
- nodeMap: RawSourceMap | string;
18
+ nodeMap: string;
19
19
  sourceMapConsumer: SourceMapConsumer;
20
20
  private styleMapUtil;
21
+ private isCss;
21
22
  readonly QUICKAPP_CONFIG = "quickapp.config.js";
22
23
  constructor(options: IOptions, compilerOption: ITranslateOption, collectImageResource: IImageFunction, styleLineOffset: number);
23
24
  parser(content: string, fileName: string): Promise<ParserResult<IStyleAst>>;
@@ -32,19 +32,21 @@ const {
32
32
  * 3. 把解析结果转换为目标格式
33
33
  */
34
34
  class StyleParser {
35
+ // 是否是css样式代码
36
+ isCss = true;
35
37
  QUICKAPP_CONFIG = 'quickapp.config.js';
36
38
  constructor(options, compilerOption, collectImageResource, styleLineOffset) {
37
39
  this.options = options;
38
40
  this.compilerOption = compilerOption;
39
41
  this.collectImageResource = collectImageResource;
40
42
  this.styleLineOffset = styleLineOffset;
41
- this.nodeMap = {
43
+ this.nodeMap = JSON.stringify({
42
44
  version: 3,
43
45
  sources: [],
44
46
  names: [],
45
47
  mappings: '',
46
48
  file: ''
47
- };
49
+ });
48
50
  }
49
51
  async parser(content, fileName) {
50
52
  const {
@@ -147,7 +149,8 @@ class StyleParser {
147
149
  relativeUrls: true,
148
150
  sourceMap: {
149
151
  sourceMapURL: `${baseName}.map`,
150
- outputSourceFiles: true
152
+ outputSourceFiles: true,
153
+ sourceMapRootpath: 'file:///'
151
154
  }
152
155
  }, (error, output) => {
153
156
  if (error) {
@@ -161,6 +164,7 @@ class StyleParser {
161
164
  CSSCode = output?.css ? output.css : '';
162
165
  if (output?.map) {
163
166
  this.nodeMap = output.map;
167
+ this.isCss && (this.isCss = false);
164
168
  }
165
169
  resolve(CSSCode);
166
170
  }
@@ -177,7 +181,7 @@ class StyleParser {
177
181
  onLog,
178
182
  filePath
179
183
  } = this.options;
180
- const url = `file://${filePath}`;
184
+ const url = `file:///${filePath}`;
181
185
  const alias = this.getAlias();
182
186
 
183
187
  // sass 的 alias 处理依赖当前文件路径
@@ -196,6 +200,7 @@ class StyleParser {
196
200
  });
197
201
  if (Result.sourceMap) {
198
202
  this.nodeMap = JSON.stringify(Result.sourceMap);
203
+ this.isCss && (this.isCss = false);
199
204
  }
200
205
  return Result.css;
201
206
  } catch (error) {
@@ -217,23 +222,29 @@ class StyleParser {
217
222
  onLog,
218
223
  filePath
219
224
  } = this.options;
225
+ const newFilePath = this.isCss ? filePath : `file:///${filePath}`;
220
226
  const alias = this.getAlias();
221
227
  try {
222
228
  const result = await (0, _postcss.default)([(0, _postcssImport.default)({
223
- resolve: id => {
229
+ resolve: (id, basedir) => {
230
+ // 处理所有路径中的 file:/// 前缀
231
+ const cleanId = id.replace(/^file:\/\/\//, '');
232
+ const cleanBase = basedir.replace(/^file:\/\/\//, '');
233
+ const filePath = _path.default.resolve(cleanBase, cleanId);
224
234
  for (const [key, value] of Object.entries(alias)) {
225
- if (id.startsWith(key)) {
226
- return id.replace(key, value);
235
+ if (filePath.startsWith(key)) {
236
+ return filePath.replace(key, value);
227
237
  }
228
238
  }
229
- return id;
239
+ return filePath;
230
240
  }
231
241
  }), _postcssUrl.default]).process(sourceContent, {
232
- from: filePath,
242
+ from: newFilePath,
233
243
  map: {
234
244
  prev: this.nodeMap,
235
245
  inline: false,
236
- annotation: true
246
+ sourcesContent: true,
247
+ absolute: this.isCss
237
248
  }
238
249
  });
239
250
  this.nodeMap = result.map.toString();
@@ -307,7 +318,7 @@ class StyleParser {
307
318
  type: '',
308
319
  prelude: [],
309
320
  block: [],
310
- position: sourceNode.loc ? this.styleMapUtil.transfromLocToPosition(sourceNode.loc) : undefined
321
+ position: sourceNode.loc ? this.styleMapUtil.transfromLocToPosition(sourceNode.loc, false) : undefined
311
322
  };
312
323
  const {
313
324
  type,
@@ -330,7 +341,7 @@ class StyleParser {
330
341
  name: '',
331
342
  prelude: [],
332
343
  rules: [],
333
- position: sourceNode.loc ? this.styleMapUtil.transfromLocToPosition(sourceNode.loc) : undefined
344
+ position: sourceNode.loc ? this.styleMapUtil.transfromLocToPosition(sourceNode.loc, false) : undefined
334
345
  };
335
346
  const {
336
347
  type,
@@ -376,7 +387,7 @@ class StyleParser {
376
387
  type: '',
377
388
  name: '',
378
389
  block: [],
379
- position: sourceNode.loc ? this.styleMapUtil.transfromLocToPosition(sourceNode.loc) : undefined
390
+ position: sourceNode.loc ? this.styleMapUtil.transfromLocToPosition(sourceNode.loc, false) : undefined
380
391
  };
381
392
  const {
382
393
  type,
@@ -494,7 +505,7 @@ class StyleParser {
494
505
  let value = '';
495
506
  nodeValue.children.map(v => {
496
507
  let tempTargetValue;
497
- const tempPosition = v.loc ? this.styleMapUtil.transfromLocToPosition(v.loc) : undefined;
508
+ const tempPosition = v.loc ? this.styleMapUtil.transfromLocToPosition(v.loc, false) : undefined;
498
509
  switch (v.type) {
499
510
  case 'Operator':
500
511
  value = _cssTree.default.generate(v);
@@ -578,7 +589,7 @@ class StyleParser {
578
589
  targetList.push({
579
590
  name: nodeName,
580
591
  value: valueList,
581
- position: node.loc ? this.styleMapUtil.transfromLocToPosition(node.loc) : undefined
592
+ position: node.loc ? this.styleMapUtil.transfromLocToPosition(node.loc, false) : undefined
582
593
  });
583
594
  }
584
595
  return targetList;
@@ -587,17 +598,10 @@ class StyleParser {
587
598
  let errors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
588
599
  let isParserError = errorType === 'parserError';
589
600
  let sourceCodeStyle = _sharedUtils.Loglevel.WARN;
590
- const {
591
- onLog,
592
- filePath
593
- } = this.options;
594
601
  if (isParserError) {
595
602
  sourceCodeStyle = _sharedUtils.Loglevel.ERROR;
596
603
  }
597
604
  errors.forEach(error => {
598
- const sourceCode = error.source ? [`, source code:`, {
599
- word: `${error.source}`
600
- }] : [];
601
605
  const position = this.styleMapUtil.transfromLocToPosition({
602
606
  start: {
603
607
  line: error.startLine,
@@ -613,14 +617,7 @@ class StyleParser {
613
617
  });
614
618
  position.startColumn++;
615
619
  position.endColumn++;
616
- onLog({
617
- level: sourceCodeStyle,
618
- filePath,
619
- position,
620
- message: [{
621
- word: error.message
622
- }, ...sourceCode]
623
- });
620
+ _StyleUtil.default.handleStyleError(sourceCodeStyle, error.messages, this.options, position);
624
621
  });
625
622
  return [];
626
623
  }
@@ -20,6 +20,7 @@ declare class UxParser implements IParser<IUxAst> {
20
20
  * 1. template:
21
21
  * a. 最多1个
22
22
  * b. 子元素有且仅有1个,不能是 block
23
+ * 2. 必须有闭合标签, 示例: `<script>....</script>`正确, `<script>aaaa`错误
23
24
  */
24
25
  private validateContent;
25
26
  /**
@@ -201,6 +201,7 @@ class UxParser {
201
201
  * 1. template:
202
202
  * a. 最多1个
203
203
  * b. 子元素有且仅有1个,不能是 block
204
+ * 2. 必须有闭合标签, 示例: `<script>....</script>`正确, `<script>aaaa`错误
204
205
  */
205
206
  validateContent(childNodes) {
206
207
  let result = true;
@@ -249,21 +250,22 @@ class UxParser {
249
250
  }
250
251
 
251
252
  // 2
252
- // if (scriptCount !== 1) {
253
- // onLog({
254
- // level: Loglevel.THROW,
255
- // filePath,
256
- // message: [
257
- // { word: '<script>' },
258
- // `There are`,
259
- // { word: scriptCount },
260
- // `, but expect to have`,
261
- // { word: 1 }
262
- // ]
263
- // })
264
- // result = false
265
- // }
266
-
253
+ childNodes.forEach(node => {
254
+ if (_TemplateUtil.default.isElement(node)) {
255
+ const {
256
+ sourceCodeLocation
257
+ } = node;
258
+ if (sourceCodeLocation && !sourceCodeLocation.endTag) {
259
+ onLog({
260
+ level: _sharedUtils.Loglevel.ERROR,
261
+ filePath,
262
+ position: _TemplateUtil.default.parse5LocationToPosition(sourceCodeLocation.startTag),
263
+ message: [`<${node.nodeName}>`, 'must have an end tag']
264
+ });
265
+ result = false;
266
+ }
267
+ }
268
+ });
267
269
  return result;
268
270
  }
269
271
  /**
@@ -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
- const logs = await this.checkCode(sourceTree);
33
- if (logs) {
34
- logs.forEach(log => {
35
- this.options.onLog(log);
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);
@@ -51,7 +55,10 @@ class ScriptToTypescript {
51
55
  * @returns
52
56
  */
53
57
  babelScript(sourceTree) {
54
- const sourceCode = sourceTree.content ? sourceTree.content : `""`;
58
+ if (sourceTree.content === '') {
59
+ return '';
60
+ }
61
+ const sourceCode = sourceTree.content;
55
62
  const relativePath = _path.default.relative(this.options.projectPath, this.options.filePath);
56
63
  const plugins = [
57
64
  // 替换所有的require节点
@@ -94,8 +94,14 @@ class StyleToTypescript {
94
94
  const selector = node[i];
95
95
  const {
96
96
  type,
97
- name
97
+ name: orgName
98
98
  } = selector;
99
+
100
+ // 去除名称中的转义符,例如 源码是 .w-20\% {}, 希望生成 w-20%
101
+ // 注意:此处的反转义不能用 JSON.parse
102
+ // 原因:js中 % 不需要转义,但css选择器中%需要转义,两者规则不一样,所以不能使用 JSON.parse
103
+ // 示例:js可以写'abc%', 但css选择器中必须写'abc\%'
104
+ const name = orgName.replace(/\\(.{1})/g, '$1');
99
105
  // 选择器类型转为数字
100
106
  const selectorIndex = (0, _StyleSelectorType.findSelectorIndex)(type);
101
107
  if (type === _StyleSelectorType.Selector.COMBINATOR) {
@@ -131,10 +137,6 @@ class StyleToTypescript {
131
137
  * @param name
132
138
  */
133
139
  addThorwLog(type, name, position, info) {
134
- const {
135
- onLog,
136
- filePath
137
- } = this.options;
138
140
  const logLevel = name === ' ' || name === '>' ? _sharedUtils.Loglevel.WARN : _sharedUtils.Loglevel.THROW;
139
141
  const message = info ? [`### StyleToTypescript ### Selector type unsupport`, {
140
142
  word: info
@@ -143,12 +145,7 @@ class StyleToTypescript {
143
145
  }, ',name:', {
144
146
  word: name
145
147
  }];
146
- onLog({
147
- filePath,
148
- position,
149
- level: logLevel,
150
- message
151
- });
148
+ _StyleUtil.default.handleStyleError(logLevel, message, this.options, position);
152
149
  }
153
150
  translateAtrule(sourceNode) {
154
151
  let targetNodes = [];