!49 check validity of extend component

Merge pull request !49 from houhaoyu/test
This commit is contained in:
openharmony_ci
2021-10-18 06:41:42 +00:00
committed by Gitee
9 changed files with 288 additions and 26 deletions
+19
View File
@@ -17,6 +17,8 @@ import("//foundation/ace/ace_engine/ace_config.gni")
ets_loader_lib_dir =
get_label_info(":build_ets_loader_library", "target_out_dir") + "/lib"
ets_loader_syntax_dir = get_label_info(":build_ets_loader_library",
"target_out_dir") + "/syntax_parser/dist"
ets_loader_declarations_dir = get_label_info(":build_ets_loader_library",
"target_out_dir") + "/declarations"
ets_loader_component_config_file =
@@ -30,6 +32,7 @@ action("build_ets_loader_library") {
depfile = "$target_gen_dir/$target_name.d"
outputs = [
ets_loader_lib_dir,
ets_loader_syntax_dir,
ets_loader_declarations_dir,
ets_loader_component_config_file,
]
@@ -45,12 +48,14 @@ action("build_ets_loader_library") {
_babel_js = _ace_config_dir + "/node_modules/@babel/cli/bin/babel.js"
_babel_config_js = _ace_config_dir + "/babel.config.js"
_uglify_source_js = _ace_config_dir + "/uglify-source.js"
_build_parser_js = _ace_config_dir + "/build_parser.js"
_build_declarations_file_js = _ace_config_dir + "/build_declarations_file.js"
inputs = [
_babel_config_js,
_babel_js,
_uglify_source_js,
_build_parser_js,
_build_declarations_file_js,
]
@@ -82,12 +87,18 @@ action("build_ets_loader_library") {
rebase_path(_babel_js, root_build_dir),
"--ets-loader-src-dir",
rebase_path(_ets_loader_dir + "/src", root_build_dir),
"--ets-loader-syntax-src-dir",
rebase_path(_ets_loader_dir + "/syntax_parser/src", root_build_dir),
"--babel-config-js",
rebase_path(_babel_config_js, root_build_dir),
"--uglify-source-js",
rebase_path(_uglify_source_js, root_build_dir),
"--build-parser-js",
rebase_path(_build_parser_js, root_build_dir),
"--output-dir",
rebase_path(ets_loader_lib_dir, root_build_dir),
"--output-syntax-dir",
rebase_path(ets_loader_syntax_dir, root_build_dir),
"--declarations-file-dir",
rebase_path(_declarations_file_dir, root_build_dir),
"--build-declarations-file-js",
@@ -143,6 +154,14 @@ ohos_copy("ets_loader_library") {
module_install_name = ""
}
ohos_copy("ets_loader_syntax") {
deps = [ ":build_ets_loader_library" ]
sources = [ ets_loader_syntax_dir ]
outputs = [ target_out_dir + "/$target_name" ]
module_source_dir = target_out_dir + "/$target_name"
module_install_name = ""
}
ohos_copy("ets_loader_declaration") {
deps = [ ":build_ets_loader_library" ]
sources = [ ets_loader_declarations_dir ]
+17 -3
View File
@@ -39,9 +39,14 @@ def parse_args():
parser.add_argument('--node', help='path to nodejs exetuable')
parser.add_argument('--babel-js', help='path to babel.js')
parser.add_argument('--ets-loader-src-dir', help='path to compiler/src')
parser.add_argument('--ets-loader-syntax-src-dir',
help='path to compiler/syntax_parser/src')
parser.add_argument('--babel-config-js', help='path babel.config.js')
parser.add_argument('--uglify-source-js', help='path uglify-source.js')
parser.add_argument('--build-parser-js', help='path build_parser.js')
parser.add_argument('--output-dir', help='path to output')
parser.add_argument('--output-syntax-dir',
help='path syntax file to output')
parser.add_argument('--declarations-file-dir',
help='path declarations file')
parser.add_argument('--build-declarations-file-js',
@@ -55,8 +60,9 @@ def parse_args():
return options
def do_build(build_cmd, uglify_cmd, build_declarations_file_cmd):
for cmd in [build_cmd, uglify_cmd, build_declarations_file_cmd]:
def do_build(build_cmd, uglify_cmd, syntax_cmd, build_declarations_file_cmd):
for cmd in [build_cmd, uglify_cmd, syntax_cmd,
build_declarations_file_cmd]:
build_utils.check_output(cmd)
@@ -70,10 +76,16 @@ def main():
build_cmd.extend(['--config-file', options.babel_config_js])
depfile_deps = [options.node, options.babel_js, options.babel_config_js]
depfile_deps.extend(build_utils.get_all_files(options.ets_loader_src_dir))
depfile_deps.extend(
build_utils.get_all_files(options.ets_loader_syntax_src_dir))
uglify_cmd = [options.node, options.uglify_source_js, options.output_dir]
depfile_deps.append(options.uglify_source_js)
syntax_cmd = [options.node, options.build_parser_js,
options.output_syntax_dir]
depfile_deps.append(options.build_parser_js)
build_declarations_file_cmd = [options.node,
options.build_declarations_file_js,
options.declarations_file_dir,
@@ -82,12 +94,14 @@ def main():
depfile_deps.append(options.build_declarations_file_js)
build_utils.call_and_write_depfile_if_stale(
lambda: do_build(build_cmd, uglify_cmd, build_declarations_file_cmd),
lambda: do_build(build_cmd, uglify_cmd,
syntax_cmd, build_declarations_file_cmd),
options,
depfile_deps=depfile_deps,
input_paths=depfile_deps,
output_paths=([
options.output_dir,
options.output_syntax_dir,
options.output_declarations_dir,
options.output_component_config_file]))
+48
View File
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const util = require('util');
const childProcess = require('child_process');
const exec = util.promisify(childProcess.exec);
const fs = require('fs');
const path = require('path');
function generateSyntaxParser(inputFile, nodePath) {
const readDirPath = path.resolve(__dirname, './syntax_parser/src');
const readDirSubFiles = fs.readdirSync(readDirPath);
const catalogPath = path.resolve(inputFile, '..');
const catalogSubFiles = fs.readdirSync(catalogPath)
const parserPath = path.resolve(__dirname, './node_modules/pegjs/bin/pegjs');
if (catalogSubFiles.includes('dist')) {
exec('rm -rf ' + catalogPath + '/dist/*.js');
} else {
exec('mkdir ' + catalogPath + '/dist');
}
;(async function transJs () {
if (readDirSubFiles.length) {
for (let item of readDirSubFiles) {
let name = path.basename(item, '.peg');
if (name){
await exec(nodePath + ' ' + parserPath + ' -o ' +
catalogPath + '/dist/' + name + '.js ' + readDirPath + '/' + item);
}
}
}
})()
}
generateSyntaxParser(process.argv[2], process.argv[0]);
+5
View File
@@ -4295,6 +4295,11 @@
"integrity": "sha1-hTTnenfOesWiUS6iHg/bj89sPY0=",
"dev": true
},
"pegjs": {
"version": "0.10.0",
"resolved": "https://registry.npm.taobao.org/pegjs/download/pegjs-0.10.0.tgz",
"integrity": "sha1-z4uvrm7d/0tafvsYUmnqr0YQ3b0="
},
"picomatch": {
"version": "2.3.0",
"resolved": "https://registry.nlark.com/picomatch/download/picomatch-2.3.0.tgz",
+3 -1
View File
@@ -10,11 +10,12 @@
],
"scripts": {
"lint": "eslint --fix ./src --ext .ts",
"build": "npm run generateDeclarations && ./node_modules/.bin/babel ./src --out-dir lib --extensions .ts",
"build": "npm run generateSyntaxParser && npm run generateDeclarations && ./node_modules/.bin/babel ./src --out-dir lib --extensions .ts",
"create": "node ./lib/create.js --env projectName",
"compile": "webpack --config webpack.config.js --env buildMode=debug projectName",
"test": "npm run build && mocha -r ts-node/register test/test.ts",
"generateDeclarations": "node ./build_declarations_file.js ../../../interface/sdk-js/api/@internal/component/ets ./declarations ./lib",
"generateSyntaxParser": "node build_parser.js ./syntax_parser/dist",
"postinstall": "node npm-install.js"
},
"devDependencies": {
@@ -36,6 +37,7 @@
"copy-webpack-plugin": "^8.1.0",
"deccjsunit": "1.0.3",
"log4js": "^6.3.0",
"pegjs": "^0.10.0",
"ts-loader": "^8.0.12",
"typescript": "^4.1.3",
"webpack": "^5.48.0",
+5 -3
View File
@@ -14,6 +14,7 @@
*/
import {
ReplaceResult,
sourceReplace,
validateUISyntax,
processSystemApi
@@ -27,9 +28,10 @@ import { BUILD_ON } from './pre_define';
function preProcess(source: string): string {
process.env.compiler = BUILD_ON;
if (/\.ets$/.test(this.resourcePath)) {
const newContent: string = sourceReplace(source);
const log: LogInfo[] =
validateUISyntax(source, newContent, this.resourcePath, this.resourceQuery);
const result: ReplaceResult = sourceReplace(source, this.resourcePath);
const newContent: string = result.content;
const log: LogInfo[] = result.log;
log.concat(validateUISyntax(source, newContent, this.resourcePath, this.resourceQuery));
if (log.length) {
emitLogInfo(this, log);
}
+49 -19
View File
@@ -59,6 +59,7 @@ import {
addLog,
hasDecorator
} from './utils';
const parser = require('../syntax_parser/dist/syntax_parser.js');
export interface ComponentCollection {
entryComponent: string;
@@ -683,9 +684,14 @@ function collectionStates(decorator: string, name: string, states: Set<string>,
}
}
export function sourceReplace(source: string): string {
let content: string = source;
export interface ReplaceResult {
content: string,
log: LogInfo[]
}
export function sourceReplace(source: string, sourcePath: string): ReplaceResult {
let content: string = source;
const log: LogInfo[] = [];
// replace struct->class
content = content.replace(
new RegExp('\\b' + STRUCT + '\\b.+\\{', 'g'), item => {
@@ -693,28 +699,52 @@ export function sourceReplace(source: string): string {
return `${item} constructor(${COMPONENT_CONSTRUCTOR_ID}?, ${COMPONENT_CONSTRUCTOR_PARENT}?, ${COMPONENT_CONSTRUCTOR_PARAMS}?) {}`;
});
content = preprocessExtend(content);
content = preprocessNewExtend(content);
content = preprocessExtend(content, sourcePath, log);
// process @system.
content = processSystemApi(content);
return content;
return {
content: content,
log: log
}
}
export function preprocessExtend(content: string): string {
const REG_EXTEND: RegExp = /(?<![\*|\/]\s*)^(\s*)@Extend(\s+)(\S+)\.(\S+)(\s*\()(.*)(\)\s*{)/gm;
return content.replace(REG_EXTEND, (_, item1, item2, item3, item4, item5, item6, item7) => {
collectExtend(item3, item4, item6);
return `${item1}${COMPONENT_EXTEND_DECORATOR} function${item2}__${item3}__${item4}${item5}${item6}${item7}${item3}`;
});
}
export function preprocessNewExtend(content: string): string {
const REG_EXTEND: RegExp = /(?<![\*|\/]\s*)^(\s*)@Extend\s*\((.+)\)(\s+)function(\s+)(\S+)(\s*\()(.*)(\)\s*{)/gm;
return content.replace(REG_EXTEND, (_, item1, item2, item3, item4, item5, item6, item7, item8) => {
collectExtend(item2, item5, item7);
return `${item1}${COMPONENT_EXTEND_DECORATOR}${item3}function${item4}__${item2}__${item5}${item6}${item7}${item8}${item2}`;
});
export function preprocessExtend(content: string, sourcePath: string, log: LogInfo[]): string {
let syntaxCheckContent: string;
let result: any;
try {
result = parser.parse(content);
syntaxCheckContent = result.content;
for (let i = 0; i < result.collect_extend.component.length; i++) {
collectExtend(
result.collect_extend.component[i],
result.collect_extend.functionName[i],
result.collect_extend.parameters[i]
);
}
} catch (err) {
result = err;
log.push({
type: LogType.ERROR,
message: parser.SyntaxError.buildMessage(err.expected, err.found),
line: err.location.start.line,
column: err.location.start.column,
fileName: sourcePath
});
syntaxCheckContent = content;
}
if (result.error_otherParsers) {
for(let i = 0; i < result.error_otherParsers.length; i++) {
log.push({
type: LogType.ERROR,
message: result.error_otherParsers[i].errMessage,
line: result.error_otherParsers[i].errPosition.line,
column: result.error_otherParsers[i].errPosition.column,
fileName: sourcePath
});
}
}
return syntaxCheckContent;
}
function collectExtend(component: string, attribute: string, parameter: string): void {
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
start = extendAttributes:extendAttribute+
{
return {location: location()};
}
extendAttribute = whiteSpace '.' whiteSpace attribute item
attribute = attr_head attr_tail
attr_head = $ [a-zA-Z_$]+
attr_tail = $ [a-zA-Z0-9_$]*
item = whiteSpace '(' [^()]* item* [^()]* ')' whiteSpace
whiteSpace = [ \t\r\n]*
@@ -0,0 +1,116 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
{
const parse_extend = require('./parse_extend.js');
const error_otherParsers = [];
let singleError = function(errMessage, line, column) {
this.errMessage = errMessage;
this.errPosition = {
line: line,
column: column
};
};
const collect_extend = {
component: [],
functionName: [],
parameters: []
};
}
start = blocks: block+
{
return {
content: blocks.join(''),
location: location(),
collect_extend: collect_extend,
error_otherParsers: error_otherParsers
};
}
block = extend/(prefix extend?)
prefix = $((!prefix_extend .)+)
extend =
whiteSpace1:whiteSpace prefix_extend:prefix_extend funcBody_extend:funcBody_extend
whiteSpace2: whiteSpace right:'}' whiteSpace3:whiteSpace
{
return whiteSpace1 + prefix_extend + funcBody_extend + whiteSpace2 + right + whiteSpace3;
}
prefix_extend = prefix_extend_one/prefix_extend_another
//match a kind of extend component
prefix_extend_one =
'@Extend' whiteSpace1:whiteSpace '(' component:component ')' whiteSpace2:whiteSpace 'function'
whiteSpace3:whiteSpace function_name:function_name whiteSpace4:whiteSpace '(' parameters:parameters
')' whiteSpace5:whiteSpace left:'{'
{
collect_extend.component.push(component);
collect_extend.functionName.push(function_name);
collect_extend.parameters.push(parameters);
return '@Extend' + whiteSpace1 + whiteSpace2 + 'function' + whiteSpace3 + '__' + component +
'__' + function_name + whiteSpace4 + '(' + parameters + ')' + whiteSpace5 + left + component;
}
//match another kind of extend component
prefix_extend_another =
'@Extend' whiteSpace1:whiteSpace component:component '.' function_name:function_name
whiteSpace2:whiteSpace '(' parameters:parameters ')' whiteSpace3:whiteSpace left:'{'
{
collect_extend.component.push(component);
collect_extend.functionName.push(function_name);
collect_extend.parameters.push(parameters);
return '@Extend' + ' function' + whiteSpace1 + '__' + component + '__' + function_name +
whiteSpace2 + '(' + parameters + ')' + whiteSpace3 + left + component;
}
component = $ [a-zA-Z_]+
function_name = $ (function_name_head function_name_tail)
function_name_head = $ [a-zA-Z_$]+
function_name_tail = $ [a-zA-Z0-9_$]*
parameters = $ ([^()]* item* [^()]*)
//extract Extend internal attribute SyntaxError
funcBody_extend = body:($[^{}]* item* [^{}]*)
{
try {
let functionBody = body.join('');
parse_extend.parse(functionBody);
return functionBody;
} catch (err) {
let countLines = location().end.line - location().start.line;
if (err.location.start.line === 1) {
err.location.start.column += location().start.column;
}
let supportMessage = " Our rule is .attribute(value) , for example: .width(50) . And you'd better have at least one attribute in Extend Component";
error_otherParsers.push(
new singleError(
parse_extend.SyntaxError.buildMessage(err.expected, err.found) + supportMessage,
err.location.start.line + location().start.line - 1,
err.location.start.column
)
);
let placeHolders = '';
while (countLines>0) {
placeHolders += '\r\n';
countLines -= 1;
}
return '()' + placeHolders;
}
}
item = $ (whiteSpace '{' [^{}]* item* [^{}]* '}' whiteSpace)
whiteSpace = $ [ \t\r\n]*