Signed-off-by: zhongjianfei <zhongjianfei@huawei.com>
This commit is contained in:
zhongjianfei 2021-08-28 16:45:47 +08:00
parent c075db5164
commit 87223c37dd
215 changed files with 23212 additions and 0 deletions

94
BUILD.gn Normal file
View File

@ -0,0 +1,94 @@
# Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
import("//build/ohos.gni")
import("//build/ohos/ace/ace.gni")
import("//foundation/ace/ace_engine/ace_config.gni")
ace_loader_lib_dir =
get_label_info(":build_ace_loader_library", "target_out_dir") + "/lib"
action("build_ace_loader_library") {
script = "//foundation/ace/huawei_proprietary/tools/ace-loader/build_ace_loader_library.py"
depfile = "$target_gen_dir/$target_name.d"
outputs = [ ace_loader_lib_dir ]
_ace_loader_dir =
"//foundation/ace/huawei_proprietary/tools/ace-loader/ace-loader"
_ace_toolkit_dir = "//prebuilts/ace-toolkit/ace-loader/linux-x64"
_module_source_js = _ace_loader_dir + "/module-source.js"
_babel_js = _ace_toolkit_dir + "/node_modules/@babel/cli/bin/babel.js"
_babel_config_js = _ace_toolkit_dir + "/babel.config.js"
_uglify_source_js = _ace_toolkit_dir + "/uglify-source.js"
inputs = [
_babel_config_js,
_babel_js,
_module_source_js,
_uglify_source_js,
]
# different host platform nodejs tool directory
if (host_os == "linux") {
nodejs_path =
"//prebuilts/ace-toolkit/nodejs/node-v12.18.4-linux-x64/bin/node"
} else if (host_os == "mac") {
nodejs_path =
"//prebuilts/ace-toolkit/nodejs/node-v12.18.4-darwin-x64/bin/node"
} else {
assert(false, "Unsupported host_os: $host_os")
}
args = [
"--depfile",
rebase_path(depfile, root_build_dir),
"--node",
rebase_path(nodejs_path, root_build_dir),
"--babel-js",
rebase_path(_babel_js, root_build_dir),
"--weex-loader-src-dir",
rebase_path(_ace_loader_dir + "/third_party/weex-loader/src",
root_build_dir),
"--ace-loader-src-dir",
rebase_path(_ace_loader_dir + "/src", root_build_dir),
"--babel-config-js",
rebase_path(_babel_config_js, root_build_dir),
"--module-source-js",
rebase_path(_module_source_js, root_build_dir),
"--uglify-source-js",
rebase_path(_uglify_source_js, root_build_dir),
"--output-dir",
rebase_path(ace_loader_lib_dir, root_build_dir),
]
}
ohos_copy("ace_loader") {
sources = [
"ace-loader/.npmignore",
"ace-loader/babel.config.js",
"ace-loader/index.js",
"ace-loader/main.product.js",
"ace-loader/npm-install.js",
"ace-loader/package-lock.json",
"ace-loader/package.json",
"ace-loader/router",
"ace-loader/sample",
"ace-loader/webpack.lite.config.js",
"ace-loader/webpack.rich.config.js",
"ace-loader/webpack.router.config.js",
]
outputs = [ target_out_dir + "/$target_name/{{source_file_part}}" ]
module_source_dir = target_out_dir + "/$target_name/"
module_install_name = ""
license_file = "//third_party/parse5/LICENSE"
}
ohos_copy("ace_loader_library") {
deps = [ ":build_ace_loader_library" ]
sources = [ ace_loader_lib_dir ]
outputs = [ target_out_dir + "/$target_name" ]
module_source_dir = target_out_dir + "/$target_name"
module_install_name = ""
license_file = "//third_party/weex-loader/NOTICE"
}

177
LICENSE Normal file
View File

@ -0,0 +1,177 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

36
ace-loader/.eslintrc.js Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2020 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.
*/
module.exports = {
env: {
browser: true,
es6: true,
node: true,
},
extends: ['google'],
globals: {
profiler: 'readonly',
initStyleSheet: 'readonly',
},
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
rules: {
'comma-dangle': ['error', 'always-multiline'],
'object-curly-spacing': ['error', 'always'],
'max-len': ['error', { 'code': 120 }],
},
};

3
ace-loader/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
node_modules
lib
build

3
ace-loader/.npmignore Normal file
View File

@ -0,0 +1,3 @@
node_modules
src
test

27
ace-loader/README.md Normal file
View File

@ -0,0 +1,27 @@
# Ace Loader
A webpack loader for Ace.
## Install Dependencies under the ace-loader dir.
npm install
## Build built-in sample for Rich devices under the ace-loader dir.
npm run rich
## Build built-in sample for Lite devices under the ace-loader dir.
npm run lite
## How to build custom ace project
Windows:
Step 1. set aceModuleRoot=path/to/your/ace/project
Step 2. set aceModuleBuild=path/to/your/jsbundle/build
Step 3. node ./node_modules/webpack/bin/webpack.js --config webpack.rich.config.js
Linux:
Step 1. export aceModuleRoot=path/to/your/ace/project
Step 2. export aceModuleBuild=path/to/your/jsbundle/build
Step 3. node ./node_modules/webpack/bin/webpack.js --config webpack.rich.config.js

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2020 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.
*/
module.exports = function(api) {
api.cache(true);
const presets = ['@babel/preset-env'];
const plugins = [
'@babel/plugin-transform-modules-commonjs',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-transform-runtime',
[
'@babel/plugin-transform-arrow-functions',
{
spec: true,
},
],
];
return {
presets,
plugins,
};
};

16
ace-loader/index.js Normal file
View File

@ -0,0 +1,16 @@
/*
* Copyright (c) 2020 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.
*/
module.exports = require('./lib/loader')

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2020 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.
*/
var path = require('path')
var fs = require('fs')
const red = '\u001b[31m';
const reset = '\u001b[39m';
function deleteFolderRecursive(url) {
let files = [];
if (fs.existsSync(url)) {
files = fs.readdirSync(url);
files.forEach(function(file) {
const curPath = path.join(url, file);
if (fs.statSync(curPath).isDirectory()) {
deleteFolderRecursive(curPath);
} else {
fs.unlinkSync(curPath);
}
});
fs.rmdir(url, function(err) {});
}
}
function readManifest(manifestFilePath) {
let manifest = {};
try {
const jsonString = fs.readFileSync(manifestFilePath).toString()
manifest = JSON.parse(jsonString)
} catch (e) {
throw Error('\u001b[31m' + 'ERROR: the manifest file is lost or format is invalid.' + '\u001b[39m').message
}
return manifest;
}
function loadEntryObj(manifest, projectPath, device_level) {
let entryObj = {}
const appJSPath = path.resolve(projectPath, 'app.js');
if (device_level === 'card') {
entryObj = addPageEntryObj(manifest, projectPath);
} else {
if (!fs.existsSync(appJSPath)) {
throw Error(red + 'ERROR: missing app.js' + reset).message;
}
entryObj['./app'] = projectPath + '/app.js?entry';
}
return entryObj;
}
function addPageEntryObj(manifest, projectPath) {
let entryObj = {};
const pages = manifest.pages;
if (pages === undefined) {
throw Error('ERROR: missing pages').message;
}
pages.forEach((element) => {
entryObj['./' + element] = projectPath + path.sep + element + '.hml?entry'
})
return entryObj;
}
module.exports = {
deleteFolderRecursive: deleteFolderRecursive,
readManifest: readManifest,
loadEntryObj: loadEntryObj
};

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2020 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 fs = require('fs');
const path = require('path');
const exists = function(src, dst, callback) {
if (src.match(/\/test$/)) {
return;
}
fs.exists(dst, function(exists) {
if(exists){
callback(src, dst);
} else{
fs.mkdir(dst, function() {
callback(src, dst);
});
}
});
}
stat = fs.stat;
const copy = function(src, dst){
fs.readdir(src, function(err, paths){
if(err){
throw err;
}
paths.forEach(function(_path){
var _src = src + '/' + _path,
_dst = dst + '/' + _path,
readable, writable;
stat(_src, function(err, st){
if(err){
throw err;
}
if(st.isFile()){
const pathInfo = path.parse(_src);
if (pathInfo.name == 'gulpfile' || pathInfo.ext != '.js') {
return;
}
readable = fs.createReadStream(_src);
writable = fs.createWriteStream(_dst);
readable.pipe(writable);
} else if(st.isDirectory()){
exists(_src, _dst, copy);
}
});
});
});
};
function copyResource(src, dist) {
exists(path.resolve(__dirname, src), dist, copy);
}
copyResource(path.resolve(__dirname, './plugin/templater'), process.argv[2] + '/templater');
copyResource(path.resolve(__dirname, './plugin/theme'), process.argv[2] + '/theme');
copyResource(path.resolve(__dirname, './plugin/codegen'), process.argv[2] + '/codegen');
copyResource(path.resolve(__dirname, './third_party/weex-loader/deps/weex-scripter'), process.argv[2] + '/scripter');
copyResource(path.resolve(__dirname, './third_party/weex-loader/deps/weex-styler'), process.argv[2] + '/styler');
copyResource(path.resolve(__dirname, '../../../../../../third_party/parse5/packages/parse5/lib'), process.argv[2] + '/parse');

37
ace-loader/npm-install.js Normal file
View File

@ -0,0 +1,37 @@
"use strict";
var path = require("path");
var fs = require("fs");
let exec = require('child_process').exec;
if ( !fs.existsSync(path.resolve(path.join(__dirname, 'bin'), "ark"))) return;
var build_linux = path.join(__dirname, "bin", "ark", "build");
var build_win = path.join(__dirname, "bin", "ark", "build-win");
var build_mac = path.join(__dirname, "bin", "ark", "build-mac");
var isWin = !1;
var isMac = !1;
if (fs.existsSync(path.resolve(path.join(__dirname, 'bin'), "ark/build-win"))) {
isWin = !0;
} else if (fs.existsSync(path.resolve(path.join(__dirname, 'bin'), "ark/build-mac"))) {
isMac = !0;
} else if (!fs.existsSync(path.resolve(path.join(__dirname, 'bin'), "ark/build"))) {
throw Error("Error: find build fail").message;
}
let cwd;
if (isWin) {
cwd = build_win
} else if (isMac) {
cwd = build_mac
} else {
cwd = build_linux
}
exec("npm install", { cwd: cwd }, function (err, stdout, stderr) {
console.log("", stdout, "");
if (err != null) {
throw Error(`npm install filed: ${err}`).message;
}
});

6423
ace-loader/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

74
ace-loader/package.json Normal file
View File

@ -0,0 +1,74 @@
{
"name": "ace-loader",
"version": "1.0.11",
"description": "a webpack loader for ace",
"main": "index.js",
"private": true,
"keywords": [
"ace",
"loader",
"webpack",
"Lite",
"Rich"
],
"scripts": {
"build": "",
"rich": "cd sample/rich && webpack --config ../../webpack.rich.config.js",
"lite": "cd sample/lite && webpack --config ../../webpack.lite.config.js",
"card": "cd sample/card && webpack --config ../../webpack.rich.config.js",
"postinstall": "node npm-install.js"
},
"devDependencies": {
"chai": "^3.5.0",
"eslint": "^7.3.1",
"eslint-config-google": "^0.14.0",
"mocha": "^7.1.2",
"sinon": "^1.17.3",
"sinon-chai": "^2.8.0"
},
"dependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.9.0",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.12.10",
"@babel/preset-env": "^7.9.0",
"@babel/runtime": "^7.0.0",
"babel-loader": "^8.0.6",
"babel-plugin-require-context-hook": "^1.0.0",
"copy-webpack-plugin": "^8.1.0",
"css": "^3.0.0",
"css-loader": "^3.4.2",
"deccjsunit": "latest",
"escodegen": "^2.0.0",
"esprima": "^4.0.1",
"hash-sum": "^1.0.2",
"jimp": "^0.12.1",
"less": "^3.11.1",
"less-loader": "^5.0.0",
"loader-utils": "^1.1.0",
"md5": "^2.1.0",
"parse5": "^2.1.5",
"resolve-bin": "^0.4.0",
"sass": "^1.26.8",
"sass-loader": "^7.3.1",
"source-map": "^0.7.3",
"uglify-es": "^3.3.9",
"webpack": "^5.48.0",
"webpack-cli": "^4.6.0"
},
"babel": {
"presets": [
"@babel/preset-env"
],
"plugins": [
"@babel/plugin-transform-modules-commonjs",
"@babel/plugin-proposal-class-properties",
[
"@babel/plugin-transform-arrow-functions",
{
"spec": true
}
]
]
}
}

View File

@ -0,0 +1,736 @@
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ 784:
/***/ ((__unused_webpack_module, exports) => {
/**
* Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
*/
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.errorMap = void 0;
exports.errorMap = new Map([
["fileError", "Visual file is damaged"],
["versionError", "Version number of visual file does not match"],
["modelError", "Visual model in visual file is damaged"],
["codegenError", "Codegen hml and css failed"],
]);
/***/ }),
/***/ 243:
/***/ ((__unused_webpack_module, exports) => {
/*
* @Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
*/
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.Style = exports.Tag = void 0;
class Tag {
/**
* @description: constructor for Tag
* @param tagName is name of component
* @param attributes is attributes of component
* @param content is child elements or innerHtml of component
*/
constructor(tagName, attributes, content) {
this.tagName = tagName;
this.attributes = attributes;
this.content = content;
}
accept(v) {
return v.genTag(this);
}
}
exports.Tag = Tag;
class Style {
/**
* @description: constructor for Style
* @param kind distinguishes id and class
* @param name is name of id or class
* @param content is style name and value of component
*/
constructor(kind, name, content) {
this.kind = kind;
this.name = name;
this.content = content;
}
accept(v) {
return v.genStyle(this);
}
}
exports.Style = Style;
/***/ }),
/***/ 245:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
/*
* @Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
*/
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.StringWriter = void 0;
const ASTNodeVisitor_1 = __webpack_require__(573);
const Cache_1 = __webpack_require__(695);
class StringWriter {
constructor() {
this.generator = ASTNodeVisitor_1.ASTNodeGenerator.getMethodGen(new Cache_1.Cache(""));
}
/**
* @description: generate HML
* @param t is Tag in AST
* @return HML code
*/
genHML(t) {
t.accept(this.generator);
return this.generator.cache.toString();
}
/**
* @description: generate CSS
* @param t is Style in AST
* @return CSS code
*/
genCSS(t) {
t.forEach((value) => {
value.accept(this.generator);
});
return this.generator.cache.toString();
}
}
exports.StringWriter = StringWriter;
/***/ }),
/***/ 573:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
/*
* @Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved.
*/
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.ASTNodeGenerator = void 0;
const Token_1 = __webpack_require__(334);
class ASTNodeGenerator {
/**
* @description: constructor for BridgeVisitor
* @param reference is cache for Harmony FA code
*/
constructor(reference) {
this.cache = reference;
}
/**
* @description: code generator
* @param ref is cache for code
* @return ast node generator
*/
static getMethodGen(ref) {
if (ASTNodeGenerator.instance === undefined) {
ASTNodeGenerator.instance = new ASTNodeGenerator(ref);
}
else {
ASTNodeGenerator.instance.setCache(ref);
}
return ASTNodeGenerator.instance;
}
/**
* @description: cache for code
* @param ref is cache for code
* @return void
*/
setCache(ref) {
this.cache = ref;
}
/**
* @description: parse Tag in AST and generate code for Tag in cache
* @param Tag in AST
* @return void
*/
genTag(t) {
this.cache.concat(Token_1.TokenClass.TAG_START, t.tagName);
this.cache.indentOff();
t.attributes.forEach((value, key) => {
let valueBK = "";
for (const char of value) {
valueBK += (char === "\"" ? "&quot;" : (char === "\n" ? "&#10;" : char));
}
this.cache.concat(Token_1.TokenClass.SPACE, key, Token_1.TokenClass.ASSIGN, Token_1.TokenClass.LQUOTE, valueBK, Token_1.TokenClass.RQUOTE);
});
if (t.content === null) {
this.cache.concat(Token_1.TokenClass.EMPTY_TAG_END);
}
else {
this.cache.concat(Token_1.TokenClass.TAG_END);
if (typeof t.content === "string") {
let contentBK = "";
for (const char of t.content) {
contentBK += (char === "<" ? "&#60;" : (char === "\n" ? "&#10;" : char));
}
this.cache.concat(contentBK);
}
else if (t.content.length !== 0) {
this.cache.concat(Token_1.TokenClass.NEW_LINE);
this.cache.indentOn();
this.cache.incIndent();
t.content.forEach((tag) => {
tag.accept(this);
this.cache.indentOff();
this.cache.concat(Token_1.TokenClass.NEW_LINE);
this.cache.indentOn();
});
this.cache.decIndent();
this.cache.indentOn();
}
this.cache.concat(Token_1.TokenClass.END_TAG_START, t.tagName, Token_1.TokenClass.TAG_END);
}
}
/**
* @description: parse Style in AST and generate code for Style in cache
* @param Style in AST
* @return void
*/
genStyle(s) {
if (s.kind === "IDStyle") {
this.cache.concat(Token_1.TokenClass.ID_STYLE_START);
this.cache.indentOff();
}
this.cache.concat(s.name, Token_1.TokenClass.SPACE, Token_1.TokenClass.LBRA, Token_1.TokenClass.NEW_LINE);
this.cache.indentOn();
this.cache.incIndent();
s.content.forEach((value, key) => {
this.cache.concat(key, Token_1.TokenClass.COLON, Token_1.TokenClass.SPACE, value, Token_1.TokenClass.SEMICOLON, Token_1.TokenClass.NEW_LINE);
});
this.cache.decIndent();
this.cache.concat(Token_1.TokenClass.RBRA, Token_1.TokenClass.NEW_LINE, Token_1.TokenClass.NEW_LINE);
}
}
exports.ASTNodeGenerator = ASTNodeGenerator;
ASTNodeGenerator.instance = undefined;
/***/ }),
/***/ 844:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
/*
* @Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved.
*/
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.CSSBridge = exports.HMLBridge = void 0;
const FATypeChecker_1 = __webpack_require__(335);
const AST_1 = __webpack_require__(243);
class HMLBridge {
constructor() {
this.errors = 0;
}
/**
* @description: generate error message
* @param msg is error message to showup in console
*/
error(msg) {
console.error("Code generating error: " + msg);
this.errors += 1;
}
/**
* @description: get error number
* @return error number
*/
getErrorCount() {
return this.errors;
}
/**
* @description: code generator for Tag, which is HML type in AST in IR
* @param tag is a object with HML type to be generated
* @return a code tree representing Harmony FA HML code
*/
genTag(tag) {
let content = null;
if (FATypeChecker_1.hasTextContent(tag)) {
content = tag.content;
}
else if (FATypeChecker_1.hasArrayContent(tag)) {
const subTags = [];
tag.content.forEach((t) => {
const tree = t.accept(this);
if (tree instanceof AST_1.Tag) {
subTags.push(tree);
}
else {
throw new Error("WTF: what a trrrible failure");
}
});
content = subTags;
}
return new AST_1.Tag(tag.tagName, tag.attributes, content);
}
/**
* @description: visitor gurdance method for contents,
* sort out incoming type and guide to matching code generator
* @param obj is a object with Model or Container or CharUI primitive types to be generated
* @return a code tree representing input object
*/
visit(obj) {
if (FATypeChecker_1.isHmlNode(obj)) {
return this.genTag(obj);
}
throw new Error("no return");
}
}
exports.HMLBridge = HMLBridge;
class CSSBridge {
constructor() {
this.errors = 0;
this.styles = [];
}
/**
* @description: generate error message
* @param msg is error message to showup in console
*/
error(msg) {
console.error("Code generating error: " + msg);
this.errors += 1;
}
/**
* @description: get error number
* @return error number
*/
getErrorCount() {
return this.errors;
}
/**
* @description: code generator for ID Style, which is CSS type in AST in IR
* @param tag is a object with CSS type to be generated
* @return a code tree representing Harmony FA CSS code
*/
genIDStyle(tag) {
if (tag.idStyle.size > 0) {
this.styles.push(new AST_1.Style("IDStyle", tag.id, tag.idStyle));
}
if (FATypeChecker_1.hasArrayContent(tag)) {
for (const child of tag.content) {
child.accept(this);
}
}
}
/**
* @description: code generator for Class Style, which is CSS type in AST in IR
* @param style is a object with CSS type to be generated
* @return a code tree representing Harmony FA CSS code
*/
genClassStyle(style) {
this.styles.push(new AST_1.Style("ClassStyle", style.className, style.content));
}
/**
* @description: visitor gurdance method for contents,
* sort out incoming type and guide to matching code generator
* @param obj is a object with Model or Container or CharUI primitive types to be generated
* @return a code tree representing input object
*/
visit(obj) {
if (FATypeChecker_1.isHmlNode(obj)) {
this.genIDStyle(obj);
return this.styles;
}
else if (FATypeChecker_1.isClassStyle(obj)) {
this.genClassStyle(obj);
return this.styles;
}
throw new Error("no return");
}
}
exports.CSSBridge = CSSBridge;
/***/ }),
/***/ 695:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
/**
* Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
*/
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.Cache = void 0;
const Token_1 = __webpack_require__(334);
// There is no way pass value by reference with JS and TS, but object
class Cache {
/**
* @description: constructor for Cache
* @param value is HML/CSS code with no indents
*/
constructor(value) {
this.value = value;
this.indent = 0;
this.flag = true;
}
/**
* @description: when flag is true, there should be some indents
* @return void
*/
indentOn() {
this.flag = true;
}
/**
* @description: when flag is false, there should be no indents
* @return void
*/
indentOff() {
this.flag = false;
}
/**
* @description: increase indent
* @return void
*/
incIndent() {
this.indent++;
}
/**
* @description: decrease indent
* @return void
*/
decIndent() {
this.indent--;
}
/**
* @description: check whether indent is LT 0
* @return boolean value representing whether indent is LT 0
*/
checkIndent() {
return this.indent < 0;
}
/**
* @description: get indent
* @return indents
*/
getIndents() {
if (this.flag) {
let indents = "";
Array.from(Array(this.indent).keys()).forEach(element => {
indents += Token_1.TokenClass.INDENT;
});
return indents;
}
else {
return "";
}
}
/**
* @description: concat indents and HML/CSS code
* @param strings means HML/CSS code
* @return HML/CSS code after indents are set
*/
concat(...strings) {
this.value += this.getIndents();
this.value = this.value.concat(...strings);
return String(this.value);
}
/**
* @description: concat indents and HML/CSS code
* @return HML/CSS code
*/
toString() {
return this.value;
}
}
exports.Cache = Cache;
/***/ }),
/***/ 334:
/***/ ((__unused_webpack_module, exports) => {
/**
* Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
*/
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.TokenClass = void 0;
var TokenClass;
(function (TokenClass) {
TokenClass[TokenClass["IDENTIFIER"] = 0] = "IDENTIFIER";
// literals
TokenClass[TokenClass["STRING_LITERAL"] = 1] = "STRING_LITERAL";
TokenClass[TokenClass["NUMBER"] = 2] = "NUMBER";
TokenClass[TokenClass["CHARACTER"] = 3] = "CHARACTER";
// special tokens
TokenClass[TokenClass["EOF"] = 4] = "EOF";
TokenClass[TokenClass["INVALID"] = 5] = "INVALID";
TokenClass["EMPTY_DATA"] = "empty";
TokenClass["ASSIGN"] = "=";
// Escape character
TokenClass["NEW_LINE"] = "\n";
TokenClass["CARRIAGE_RETURN"] = "\r";
TokenClass["INDENT"] = " ";
// delimiters
TokenClass["SPACE"] = " ";
TokenClass["LQUOTE"] = "\"";
TokenClass["RQUOTE"] = "\"";
TokenClass["TAG_START"] = "<";
TokenClass["TAG_END"] = ">";
TokenClass["EMPTY_TAG_END"] = "/>";
TokenClass["END_TAG_START"] = "</";
TokenClass["ID_STYLE_START"] = "#";
TokenClass["CLASS_STYLE_START"] = ".";
TokenClass["LBRA"] = "{";
TokenClass["RBRA"] = "}";
TokenClass["SEMICOLON"] = ";";
TokenClass["COLON"] = ":";
})(TokenClass = exports.TokenClass || (exports.TokenClass = {}));
/***/ }),
/***/ 704:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.emit = exports.emitCSS = exports.emitHml = void 0;
/**
* Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
*/
const BridgeVisitor_1 = __webpack_require__(844);
const ASTFileVisitor_1 = __webpack_require__(245);
/**
* @description: output the HML source code of the model
*/
function emitHml(rootModel) {
const visitor = new BridgeVisitor_1.HMLBridge();
const ast = rootModel.accept(visitor);
const stringWriter = new ASTFileVisitor_1.StringWriter();
const res = stringWriter.genHML(ast);
if (visitor.getErrorCount() > 0) {
console.error("Cannot generate code, error found: " + visitor.getErrorCount().toString());
return "error";
}
else {
return res;
}
}
exports.emitHml = emitHml;
/**
* @description: output the CSS source code of the model
*/
function emitCSS(rootModel) {
const visitor = new BridgeVisitor_1.CSSBridge();
const styles = rootModel.accept(visitor);
const stringWriter = new ASTFileVisitor_1.StringWriter();
const res = stringWriter.genCSS(styles);
if (visitor.getErrorCount() > 0) {
console.error("Cannot generate code, error found: " + visitor.getErrorCount().toString());
return "error";
}
else {
return res;
}
}
exports.emitCSS = emitCSS;
/**
* @description: output all source code of the model
*/
function emit(rootModel) {
const obj = {
hml: emitHml(rootModel),
css: emitCSS(rootModel),
};
return obj;
}
exports.emit = emit;
/***/ }),
/***/ 335:
/***/ ((__unused_webpack_module, exports) => {
/**
* Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved.
*/
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.hasJsonTextContent = exports.hasJsonArrayContent = exports.isClassStyle = exports.hasArrayContent = exports.hasTextContent = exports.isText = exports.isHmlNode = exports.isContainer = void 0;
function isContainer(obj) {
return obj.type === "Container";
}
exports.isContainer = isContainer;
function isHmlNode(obj) {
return obj.type === "Container" || obj.type === "TextContent" || obj.type === "Base" || obj.type === "Text";
}
exports.isHmlNode = isHmlNode;
function isText(obj) {
return obj.type === "Text";
}
exports.isText = isText;
function hasTextContent(obj) {
return obj.content !== undefined && typeof obj.content === "string";
}
exports.hasTextContent = hasTextContent;
function hasArrayContent(obj) {
return obj.content !== undefined && obj.content instanceof Array;
}
exports.hasArrayContent = hasArrayContent;
function isClassStyle(obj) {
return obj.kind === "ClassStyle";
}
exports.isClassStyle = isClassStyle;
/**
* @description: judge whether jsonmodel is nested
* @param obj is jsonModel
* @return obj is JsonContainerModel
*/
function hasJsonArrayContent(obj) {
return obj.content !== undefined && obj.content instanceof Array;
}
exports.hasJsonArrayContent = hasJsonArrayContent;
/**
* @description: judge whether type of jsonmodel's content is string
* @param obj is jsonModel
* @return obj is JsonTextContentModel
*/
function hasJsonTextContent(obj) {
return obj.content !== undefined && typeof obj.content === "string";
}
exports.hasJsonTextContent = hasJsonTextContent;
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if(cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
var exports = __webpack_exports__;
/**
* Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
*/
Object.defineProperty(exports, "__esModule", ({ value: true }));
const FATypeChecker_1 = __webpack_require__(335);
const Emit_1 = __webpack_require__(704);
const errorMap_1 = __webpack_require__(784);
const visualVersion = 10;
/**
* @description: codegen hml and css according to code in visual file
* @param source is code in visual file
* @return object of hmlCSS, errorType and errorMessage
*/
function genHmlAndCss(source) {
const retObj = {
hmlCss: {
hml: "",
css: "",
},
errorType: "",
errorMessage: "",
};
try {
// parse source code in visual file
const visualSource = JSON.parse(source);
const destVisualVersion = visualSource.VisualVersion;
const regex = /^([1-9]+[0-9]*)$/;
if (destVisualVersion === undefined) {
retObj.errorType = "versionError";
}
else {
const expression = destVisualVersion.match(regex);
if (expression === null || parseInt(expression[1]) > visualVersion) {
retObj.errorType = "versionError";
}
}
try {
const model = genHmlNode(JSON.parse(visualSource.content));
const hmlCss = Emit_1.emit(model);
if (hmlCss.hml === "error" || hmlCss.css === "error") {
retObj.errorType = "codegenError";
}
retObj.hmlCss = hmlCss;
}
catch (e) {
retObj.errorType = "modelError";
}
}
catch (e) {
retObj.errorType = "fileError";
}
if (retObj.errorType !== "") {
retObj.errorMessage = errorMap_1.errorMap.get(retObj.errorType);
retObj.hmlCss.hml = "";
retObj.hmlCss.css = "";
}
return retObj;
}
/**
* @description: generate HmlNode
* @param model is json format of HmlNode
* @return HmlNode after codegen
*/
function genHmlNode(model) {
const res = {
id: model.id,
tagName: model.tagName,
type: model.type,
idStyle: new Map(model.idStyle),
attributes: new Map(model.attributes),
accept: (v) => {
return v.visit(res);
},
};
if (FATypeChecker_1.hasJsonTextContent(model)) {
res.content = model.content;
}
else if (FATypeChecker_1.hasJsonArrayContent(model)) {
const content = [];
for (const child of model.content) {
content.push(genHmlNode(child));
}
res.content = content;
}
return res;
}
exports.genHmlAndCss = genHmlAndCss;
})();
var __webpack_export_target__ = exports;
for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i];
if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, "__esModule", { value: true });
/******/ })()
;

View File

@ -0,0 +1,239 @@
/*
* Copyright (c) 2020 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 content = require('./content')
const data = require('./data')
const { DEVICE_LEVEL } = require('../lite/lite-enum')
const card = process.env.DEVICE_LEVEL === DEVICE_LEVEL.CARD
const REG_CARD_ARRAY = /(\['.+?'\])|(\[".+?"\])/g
/**
* Check if there is data binding.
* @param {Object} initValue Hml text token information.
* @param {Object} functionFlag Hml text token information.
* @return {String} Compiled data binding
*/
function transExp(initValue, functionFlag, isValue, out, nodeLoc) {
let value = initValue.toString().trim()
const hasExpFlag = isExp(value)
if (hasExpFlag) {
value = parseExp(value, functionFlag, isValue, out, nodeLoc)
}
return value
}
/**
* parse data binding.
* @param {Object} value Hml text token information.
* @param {Object} functionFlag Hml text token information.
* @return {String} Compiled data binding
*/
function parseExp(value, functionFlag, isValue, out, nodeLoc) {
const textArray = data.parseText(value)
const explist = []
for (let i = 0; i < textArray.length; i++) {
const exp = textArray[i]
let transValue
if (exp.tag) {
if (card) {
checkCard(exp.value, out, nodeLoc)
}
transValue = card ? `{{${transCardArray(exp.value)}}}` : content.parseExpression(exp.value)
if (textArray.length !== 1 && !card) {
transValue = `(${transValue})`
}
} else {
transValue = card ? exp.value : `decodeURI('${encodeURI(exp.value).replace(/\'/g, '%27')}')`
}
explist.push(transValue)
}
if (card && checkCardVersionLimit() && isValue) {
if (explist.length > 1) {
out.log.push({
line: nodeLoc.line || 1,
column: nodeLoc.col || 1,
reason: 'ERROR: The variable concatenation is not supported in card (supproted later).',
})
}
}
let func = explist.join(card ? '' : ' + ')
if (functionFlag !== false && !card) {
func = eval('(function () {return ' + func + '})')
}
func = card && textArray.length > 1 ? '$f(' + func + ')' : func
return func
}
/**
* Check if there is data binding in the list.
* @param {String} initValue Hml text token information.
* @return {String} Compiled data binding in list
*/
function transExpForList(initValue) {
let value = initValue.toString().trim()
const hasExpListFlag = containExp(value)
if (hasExpListFlag) {
value = parseExpList(value)
}
return value
}
/**
* parse data binding in list.
* @param {String} value Hml text token information.
* @return {String} Compiled data binding in list
*/
function parseExpList(value) {
const exprMatch = value.match(/{{{([\s\S]+?)}}}|{{([\s\S]+?)}}/g)
const exprArray = value.replace(/{{{([\s\S]+?)}}}|{{([\s\S]+?)}}/g, '&e').split(/\s+/)
let n = 0
const result = []
exprArray.forEach((item)=>{
if (item.indexOf('&e') >= 0) {
while (item.indexOf('&e') >= 0) {
item = item.replace('&e', exprMatch[n++])
}
const textArray = data.parseText(item)
const exprlist = []
if (textArray) {
textArray.forEach(function(text) {
const transValue = text.tag ?
card ? `{{${text.value}}}` : content.parseExpression(text.value) :
card ? text.value : `'${text.value}'`
exprlist.push(transValue)
})
result.push(exprlist.join('+'))
}
} else {
const value = card ? item : `'${item}'`
result.push(value)
}
})
return card ? result : "(function () {return [" + result.join(", ") + "]})"
}
/**
* Regexp determine whether there is data binding.
* @param {String} value expression value.
* @return {Boolean} Test results
*/
function isExp(value) {
const REGEXP_DATABIND = /{{{([\s\S]+?)}}}|{{([\s\S]+?)}}/
return REGEXP_DATABIND.test(value)
}
/**
* Global regexp determine whether there is data binding.
* @param {String} value expression value.
* @return {Boolean} Test results
*/
function containExp(value) {
const REGEXP_DATABIND_ALL = /{{{([\s\S]+?)}}}|{{([\s\S]+?)}}/g
return REGEXP_DATABIND_ALL.test(value)
}
/**
* Replace value on match.
* @param {String} value expression value.
* @return {String} The result after replacement
*/
function removeAllExpFix(value) {
const REGEXP_PRE_DATABIND = /\{\{\{?|\}\}\}?/g
return containExp(value) ? value.replace(REGEXP_PRE_DATABIND, '') : value
}
/**
* Change array format in card
* @param {String} value Array in card
* @return {String} The card array format
*/
function transCardArray(value) {
value = value.replace(REG_CARD_ARRAY, item => {
return `.${item.slice(2, -2)}.`
})
if (value.charAt(value.length - 1) === '.') {
value = value.slice(0, -1)
}
return value
}
function checkCard(value, out, nodeLoc) {
if (!checkApi(value) && !checkIdxAndItem(value)) {
if (checkCardVersionLimit() && !checkVariable(value)){
out.log.push({
line: nodeLoc.line || 1,
column: nodeLoc.col || 1,
reason: `ERROR: The expression '${value}' is not supported in card (only support a single variable in the verion).`
})
} else if (!checkCardVersionLimit() && !checkExpression(value)) {
out.log.push({
line: nodeLoc.line || 1,
column: nodeLoc.col || 1,
reason: `ERROR: The expression '${value}' is not supported in card (only support the binocular expression, ` +
`OR expression, AND expression and NOT expression).`
})
}
}
}
function checkCardVersionLimit() {
return parseInt(process.env.PLATFORM_VERSION.replace('Version', '')) < 6
}
function checkApi(value) {
return /^\$(tc|t|r)/m.test(value)
}
function checkExpression(value) {
return checkVariable(value) || checkOR(value) || checkAND(value) || checkNOT(value) || checkBinocular(value)
}
function checkIdxAndItem(value) {
return value === '$idx' || value === '$item'
}
function checkVariable(value) {
return /^[a-zA-Z\$_][a-zA-Z\d_\.\[\]'"`\s]*$/.test(value)
}
function checkOR(value) {
return /^[a-zA-Z\$_][a-zA-Z\d_\.\[\]'"`\s]*\|\|[a-zA-Z\$_\s][a-zA-Z\d_\.\[\]'"`\s]*$/m.test(value)
}
function checkAND(value) {
return /^[a-zA-Z\$_][a-zA-Z\d_\.\[\]'"`\s]*&&[a-zA-Z\$_\s][a-zA-Z\d_\.\[\]'"`\s]*$/m.test(value)
}
function checkNOT(value) {
return /^![a-zA-Z\$_][a-zA-Z\d_\.\[\]'"`\s]*$/m.test(value)
}
function checkBinocular(value) {
return /^[a-zA-Z\$_][a-zA-Z\d_\.\[\]'"`\s]*\?[a-zA-Z\$_\s][a-zA-Z\d_\.\[\]'"`\s]*:[a-zA-Z\$_\s][a-zA-Z\d_\.\[\]'"`\s]*$/m.test(value)
}
transExp.checkApi = checkApi
transExp.checkExpression = checkExpression
transExp.checkIdxAndItem = checkIdxAndItem
transExp.checkVariable = checkVariable
transExp.checkAND = checkAND
transExp.checkOR = checkOR
transExp.checkNOT = checkNOT
transExp.isExp = isExp
transExp.containExp = containExp
transExp.removeAllExpFix = removeAllExpFix
transExp.transExpForList = transExpForList
transExp.transCardArray = transCardArray
module.exports = transExp

View File

@ -0,0 +1,335 @@
/*
* Copyright (c) 2020 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.
*/
var cardNativeTag = {
'div': {
events: [],
attrs: {}
},
'stack': {
events: [],
attrs: {}
},
'image': {
alias: ['img'],
atomic: true,
selfClosing: true,
events: ['error', 'complete'],
attrs: {
src: {},
alt: {}
}
},
'progress': {
atomic: true,
selfClosing: true,
events: [],
attrs: {
type: {
def: 'horizontal',
enum: ['horizontal', 'circular', 'ring', 'scale-ring', 'arc', 'eclipse']
},
percent: {
def: 0,
checkFunc: 'number'
},
secondarypercent: {
def: 0,
checkFunc: 'number'
},
clockwise: {
def: 'true',
enum: ['true', 'false']
},
},
},
'text': {
textContent: true,
events: [],
children: ['span'],
attrs: {}
},
'span': {
textContent: true,
excludeRoot: true,
parents: ['text', 'span'],
events: [],
children: ['span'],
attrs: {},
},
'chart': {
atomic: true,
selfClosing: true,
events: [],
attrs: {
type: {
def: 'line',
enum: ['line', 'bar', 'gauge', 'progress', 'loading', 'rainbow'],
required: true
},
options: {},
datasets: {},
percent: {
def: 0,
checkFunc: 'number'
},
segments: {},
effects: {
def: 'true',
enum: ['true', 'false']
},
}
},
'button': {
textContent: true,
atomic: true,
selfClosing: true,
attrs: {
type: {
enum: ['capsule', 'circle', 'text', 'arc']
},
value: {},
icon: {},
waiting: {
def: 'false',
enum: ['false', 'true']
},
placement: {
def: 'end',
enum: ['end', 'start', 'top', 'bottom'],
},
}
},
'badge': {
attrs: {
placement: {
def: 'rightTop',
enum: ['rightTop', 'right', 'left']
},
count: {
def: 0,
checkFunc: 'number'
},
visible: {
def: 'false',
enum: ["false", "true"]
},
maxcount: {
def: 99,
checkFunc: 'number',
},
config: {},
},
},
'list': {
children: ['list-item'],
attrs: {
cachedcount: {
def: 0,
checkFunc: 'number',
},
scrollbar: {
def: 'off',
enum: ['off', 'auto', 'on'],
},
scrolleffect: {
def: 'spring',
enum: ['spring', 'fade', 'no'],
},
divider: {
def: 'false',
enum: ['false', 'true'],
},
shapemode: {
def: 'default',
enum: ['default', 'rect', 'round'],
},
updateeffect: {
def: 'false',
enum: ['false', 'true'],
},
initialindex: {
def: 0,
checkFunc: 'number',
},
initialoffset: {
def: 0,
checkFunc: 'length',
},
selected: {}
},
},
'list-item': {
excludeRoot: true,
parents: ['list'],
attrs: {
for: {},
type: {
def: 'default',
},
section: {},
sticky: {
def: 'none',
enum: ['none', 'normal', 'opacity'],
},
},
},
'block': {
excludeRoot: true,
attrs: {},
},
'swiper': {
unSupportedChildren: ['list'],
attrs: {
indicator: {
def: 'true',
enum: ['true', 'false'],
},
index: {
def: 0,
checkFunc: 'number',
},
duration: {
checkFunc: 'number',
},
vertical: {
def: 'false',
enum: ['false', 'true'],
},
digital: {
def: 'false',
enum: ['false', 'true'],
},
loop: {
def: 'true',
enum: ['true', 'false'],
},
animationopacity: {
def: 'true',
enum: ['true', 'false'],
}
},
},
'calendar': {
atomic: true,
events: [
'selectedchange',
'requestdata'
],
attrs: {
date: {},
cardcalendar: {
def: 'false',
enum: ['false', 'true'],
},
startdayofweek: {
def: 6,
},
offdays: {},
calendardata: {},
showholiday: {
def: 'true',
enum: ['true', 'false'],
},
},
},
'clock': {
atomic: true,
attrs: {
clockconfig: {
required: true
},
showdigit: {
def: 'true',
enum: ['true', 'false'],
},
hourswest: {
checkFunc: 'number',
},
},
},
'divider': {
atomic: true,
selfClosing: true,
attrs: {
vertical: {
def: 'false',
enum: ['false', 'true'],
},
},
},
'input': {
atomic: true,
selfClosing: true,
events: ['change'],
attrs: {
checked: {
def: 'false',
enum: ['false', 'true'],
},
type: {
def: 'radio',
enum: ['radio'],
required: true,
},
name: {},
value: {},
},
},
}
var cardCommonTag = {
'events': [
'click'
],
'attrs': {
id: {},
style: {},
class: {},
disabled: {
def: 'false',
enum: ['false', 'true']
},
if: {
excludeRoot: true,
def: 'true'
},
elif: {
def: 'true'
},
else: {
excludeRoot: true
},
show: {
excludeRoot: true,
def: 'true'
},
accessibilitygroup: {
enum: ['false', 'true'],
},
accessibilitytext: {},
accessibilitydescription: {},
accessibilityimportance: {
enum: ['auto', 'yes', 'no', 'no-hide-descendants'],
},
},
'children': ['block', 'slot'],
'parents': ['block']
}
module.exports = {
cardCommonTag: cardCommonTag,
cardNativeTag: cardNativeTag
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2020 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.
*/
var parser = require("@babel/parser")
var traverse = require("@babel/traverse").default
var generate = require("@babel/generator").default
function parseExpression(expression, isEventFunc) {
const keyWordsReg = new RegExp(`^(NaN\\b|isNaN\\b|isFinite\\b|decodeURI\\b|decodeURIComponent\\b|Math\\b|Date\\b|this\\b|true\\b|false\\b|
encodeURI\\b|encodeURIComponent\\b|parseInt\\b|parseFloat\\b|null\\b|undefined\\b|Infinity\\b)`, 'g')
const internalKeyWords = new RegExp(`^(var\\b|while\\b|with\\b|yield\\b|enum\\b|await\\b|implements\\b|package\\b|for\\b|function\\b|if\\b|import\\b|
protected\\b|static\\b|interface\\b|private\\b|public\\b|break\\b|case\\b|class\\b|catch\\b|const\\b|continue\\b|debugger\\b|
default\\b|delete\\b|do\\b|else\\b|export\\b|extends\\b|finally\\b|in\\b|instanceof\\b|let\\b|return\\b|super\\b|switch\\b|throw\\b|try\\b)`, 'g')
const reservedKeyWords = new RegExp(`^(var\\b|while\\b|with\\b|yield\\b|enum\\b|await\\b|implements\\b|package\\b|for\\b|function\\b|if\\b|import\\b|
protected\\b|static\\b|interface\\b|private\\b|public\\b|break\\b|case\\b|class\\b|catch\\b|const\\b|continue\\b|debugger\\b|
default\\b|delete\\b|do\\b|else\\b|export\\b|extends\\b|finally\\b|in\\b|instanceof\\b|let\\b|return\\b|super\\b|switch\\b|throw\\b|try\\b|show\\b|tid\\b)$`, 'g')
try {
if (reservedKeyWords.test(expression)) {
throw Error("A data binding parsing error occurred. Do not use the reserved:" + expression).message
}
let expAst = isEventFunc ? parser.parse('(' + expression + ')') : parser.parse(expression)
traverse(expAst, {
enter(path) {
if (path.parent && path.node.type === "Identifier") {
let flag = false
if (['ConditionalExpression', 'BinaryExpression'].includes(path.parent.type) ||
path.parent.type === 'CallExpression' && path.parent.callee === path.node) {
flag = true
}
else if (path.parent.type === "ObjectProperty" && !path.parent.computed && path.parent.value === path.node) {
flag = true
}
else {
flag = addPrefix(path.node, path.parent)
}
if (flag && !keyWordsReg.test(path.node.name)) {
path.node.name = 'this.' + path.node.name
}
}
}
})
return generate(expAst, { compact: true }).code.replace(';', '').replace(/\"/g, '\'').replace(/\n/g, '')
} catch (e) {
if (isEventFunc) {
throw internalKeyWords.test(expression) ? Error("An event parsing error occurred. Do not use the reserved:" + expression).message :
Error("An event parsing error occurred:" + expression).message
} else {
throw internalKeyWords.test(expression) ? Error("A data binding parsing error occurred. Do not use the reserved:" + expression).message :
Error("A data binding parsing error occurred:" + expression).message
}
}
}
function addPrefix(node, parent) {
const attrArr1 = ['expression', 'argument', 'expressions', 'elements', 'left', 'right']
const attrArr2 = ['object', 'property', 'id', 'key']
let keyArr = Object.keys(parent)
for (let i = 0; i < attrArr1.length; i++) {
if (keyArr.includes(attrArr1[i])) {
if (parent[attrArr1[i]] === node || ['expressions', 'elements'].includes(attrArr1[i]) &&
parent[attrArr1[i]].includes(node)) {
return true
}
}
}
for (let i = 0; i < attrArr2.length; i++) {
if (keyArr.includes(attrArr2[i])) {
if (parent.computed && parent[attrArr2[i]] === node) {
return true
} else {
if (parent.type === "Property" && parent.key.range[0] === parent.value.range[0] &&
parent.key.range[1] === parent.value.range[1]) {
node.name = node.name + ":this." + node.name
} else if (parent.object === node) {
return true
}
}
}
}
return false
}
exports.parseExpression = parseExpression

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2020 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 reg = '{{{((.|\n)+?)}}}|{{((.|\n)+?)}}'
const dataReg = new RegExp(reg, 'g')
const expressionReg = new RegExp(reg)
/**
* Parse expression in hml text
*/
function parseData(v) {
v.match(dataReg).forEach(element => {
const repElement = element.toString().trim().replace(/\n/g, '')
v = v.replace(element, repElement)
})
if (!expressionReg.test(v)) {
return null
}
let start
let next = 0
const res = []
dataReg.lastIndex = 0
for (let i = next; i < v.length; i++) {
let match = dataReg.exec(v)
if (!match) {
break
}
start = match.index
getValue(next, start, v, res)
parseValue(match, res)
next = start + match[0].length
}
getValue(next, v.length, v, res)
return res
}
function getValue(begin, end, v, res) {
if (begin < end) {
res.push({
value: v.slice(begin, end)
})
}
}
function parseValue(match, res) {
let three= /^{{{.*}}}$/.test(match[0])
let v = three ? match[1] : match[3]
res.push({
tag: true,
value: v.trim()
})
}
exports.parseText = parseData

View File

@ -0,0 +1,298 @@
/*
* Copyright (c) 2020 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 componentValidator = require('./component_validator')
const Parser = require('../parse/parser/index')
const path = require('path')
let compileResult
const EVENT_START_REGEXP = /^(on:|on|@|grab:)/
const REGEXP_TEXT = /^#/
const REGEXP_DATA = /^data-/
/**
* Compile html file into ast object.
* @param {String} source Hml file content.
* @param {Function} operate The second number.
* @param {String} filePath File resource path.
*/
function parse(source, operate, filePath) {
const pathParse = path.parse(filePath)
let relativePath = pathParse.dir.replace(process.env.aceModuleRoot ||
process.cwd(), '') + '/' + pathParse.base.replace(pathParse.ext, '')
relativePath = replaceAll(path.sep, '/', relativePath).replace('/', '')
const result = { jsonTemplate: {}, deps: [], log: [] }
compileResult = result
const template = hmlParse(source, {
sourceCodeLocationInfo: true,
})
if (checkNullNode(template, operate) || checkRootNode(template, operate, relativePath)) {
return
}
const rootArray = template.childNodes.filter(function(currentValue) {
return currentValue.nodeName.indexOf('#') === -1
})
let rootIndex = 0
rootArray.forEach((root, index) => {
if(root.tagName !== 'element') {
rootIndex = index
}
})
generate(rootArray[rootIndex], filePath, undefined, relativePath)
operate(null, compileResult)
}
/**
* Use parse5 to get html conversion results.
* @param {String} code Hml file content.
* @param {Object} config parse5 parseFragment function config.
* @return {Object} html conversion results.
*/
function hmlParse(code, config) {
const parse = new Parser({ sourceCodeLocationInfo: true, componentValidator, compileResult })
const res = parse.parseFragment(code, config)
return res
}
/**
* Check if the hml file does not contain nodes.
* @param {String} template hml conversion results.
* @return {Boolean} Check result.
*/
function checkNullNode(template, operate) {
let errorFlag = false
if (template.childNodes.length === 0) {
compileResult.log.push({ reason: 'ERROR: parsing hml file failed' })
operate(null, compileResult)
errorFlag = true
}
return errorFlag
}
/**
* Check if the root node is legal.
* @param {String} template hml conversion results.
* @return {Boolean} Check result.
*/
function checkRootNode(template, operate, relativePath) {
let errorFlag = false
const rootArray = template.childNodes.filter(function(currentValue) {
return currentValue.nodeName.indexOf('#') === -1
})
let rootNum = 0
rootArray.forEach(root => {
if (root.nodeName !== 'element') {
rootNum ++
} else if (root.attrs && root.attrs.length) {
for (let index = 0; index < root.attrs.length; index++) {
const element = root.attrs[index];
if (element.name === 'name') {
componentValidator.elementNames[relativePath] = componentValidator.elementNames[relativePath] || []
componentValidator.elementNames[relativePath].push(element.value)
break
}
}
}
})
if (rootNum !== 1) {
if (!rootNum) {
compileResult.log.push({
reason: 'ERROR: need a legal root node',
line: 1,
column: 1,
})
}
if (rootNum > 1) {
compileResult.log.push({
reason: 'ERROR: there can only be one root node',
line: 1,
column: 1,
})
}
operate(null, compileResult)
errorFlag = true
}
return errorFlag
}
/**
* Recursively parse every node.
* @param {Object} node Nodes that need to be resolved.
* @param {String} filePath File resource path.
* @param {Object} preNode the previous node.
*/
function generate(node, filePath, preNode, relativePath) {
componentValidator.validateTagName(node, compileResult, relativePath)
if (node.attrs && node.attrs.length !== 0) {
checkNodeAttrs(node, filePath, preNode, relativePath)
}
if (node.childNodes && node.childNodes.length !== 0) {
checkNodeChildren(node, filePath, relativePath)
}
}
/**
* Parse node properties.
* @param {Object} node Nodes that need to be resolved.
* @param {String} filePath File resource path.
* @param {Object} preNode the previous node.
*/
function checkNodeAttrs(node, filePath, preNode, relativePath) {
const attributes = node.attrs
const pos = {
line: node.sourceCodeLocation.startLine,
col: node.sourceCodeLocation.endLine,
}
attributes.forEach((attr, index) => {
const attrName = attr.name
const attrValue = attr.value
switch (attrName) {
case 'style':
componentValidator.validateStyle(attrValue, compileResult, pos, relativePath)
break
case 'class':
componentValidator.validateClass(attrValue, compileResult, pos, relativePath)
break
case 'id':
componentValidator.validateId(attrValue, compileResult, pos, relativePath)
break
case 'for':
checkAttrFor(node, attributes, pos);
componentValidator.validateFor(attrValue, compileResult, pos, relativePath)
break
case 'if':
componentValidator.validateIf(attrValue, compileResult, false, pos, relativePath)
break
case 'elif':
componentValidator.validateAttrElif(preNode, attrValue, attributes, index,
compileResult, pos, relativePath)
break
case 'else':
componentValidator.validateAttrElse(preNode, compileResult, pos, relativePath)
break
case 'append':
componentValidator.validateAppend(attrValue, compileResult, pos, relativePath)
break
default:
if (EVENT_START_REGEXP.test(attrName)) {
componentValidator.validateEvent(attrName, attrValue, compileResult, pos, relativePath)
} else if (REGEXP_DATA.test(attrName)) {
componentValidator.parseDataAttr(attrName, attrValue, compileResult, pos, relativePath)
} else {
componentValidator.validateAttr(
filePath,
attrName,
attrValue,
compileResult,
node.tagName,
pos,
relativePath
)
}
}
})
}
function checkAttrFor(node, attributes, pos) {
if (process.env.DEVICE_LEVEL === 'card') {
let tidExists = false
let ifExists = false
attributes.forEach(element => {
if(element.name === 'tid') {
tidExists = true
}
if(element.name === 'if' || element.name === 'elif' || element.name === 'else') {
ifExists = true
}
})
if (!tidExists) {
compileResult.log.push({
line: pos.line || 1,
column: pos.col || 1,
reason: `WARNING: The 'tid' is recommended to use here.`,
})
}
if (ifExists) {
compileResult.log.push({
line: pos.line || 1,
column: pos.col || 1,
reason: `ERROR: The 'for' and 'if' cannot be used in the same node.`,
})
}
let isParentFor = false
if (node && node.parentNode && node.parentNode.attrs) {
node.parentNode.attrs.forEach(element => {
if (element.name === 'for') {
isParentFor = true
}
})
}
if (isParentFor) {
compileResult.log.push({
line: pos.line || 1,
column: pos.col || 1,
reason: `ERROR: The nested 'for' is not support.`,
})
}
}
}
function replaceAll(find, replace, str) {
find = find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
return str.replace(new RegExp(find, 'g'), replace);
}
/**
* Parse node children.
* @param {Object} node Nodes that need to be resolved.
* @param {String} filePath File resource path.
* @param {Object} preNode the previous node.
*/
function checkNodeChildren(node, filePath, relativePath) {
const children = node.childNodes.filter((child) => {
return (
(child.nodeName === '#text' && child.value.trim()) ||
!REGEXP_TEXT.test(child.nodeName)
)
})
const temp=compileResult.jsonTemplate
for (let i = 0; i < children.length; i++) {
const child = children[i]
let preNode
if (i > 0) {
preNode = children[i - 1]
}
if (!REGEXP_TEXT.test(child.nodeName)) {
compileResult.jsonTemplate={}
temp.children=temp.children||[]
temp.children.push(compileResult.jsonTemplate)
generate(child, filePath, preNode, relativePath)
} else {
const pos = {
line: child.sourceCodeLocation.startLine,
col: child.sourceCodeLocation.endLine,
}
if (node.nodeName === 'option') {
componentValidator.validateAttr(filePath, 'content', child.value,
compileResult, child.tagName, pos, relativePath)
continue
}
componentValidator.validateAttr(filePath, 'value', child.value,
compileResult, child.tagName, pos, relativePath)
}
}
compileResult.jsonTemplate=temp
}
module.exports = { parse: parse }

View File

@ -0,0 +1,385 @@
/*
* Copyright (c) 2020 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 isType = require('../lite/lite-utils');
const rulePath = process.env.RULE_PATH;
const smartvisionTag = {
camera: {
events: ['error'],
},
video: {
events: [
'prepared',
'start',
'pause',
'finish',
'error',
'seeking',
'seeked',
'timeupdate',
],
attrs: {
autoplay: {
enum: ['false', 'true'],
},
controls: {
enum: ['true', 'false'],
},
muted: {
enum: ['false', 'true'],
},
src: { checkPath: true },
},
},
};
const litewearableTag = {
'div': {},
'canvas': {},
'stack': {},
'qrcode': {
atomic: true,
selfClosing: true,
uevents: ['click', 'longpress', 'swipe'],
attrs: {
value: {
required: true,
},
type: {
enum: ['rect', 'circle'],
},
},
},
'list': {
events: ['scrollend'],
children: ['list-item'],
},
'list-item': {
excludeRoot: true,
parents: ['list'],
},
'swiper': {
unSupportedChildren: ['list'],
events: ['change'],
attrs: {
index: {
checkFunc: 'number',
},
loop: {
enum: ['true', 'false'],
},
duration: {
checkFunc: 'number',
},
vertical: {
enum: ['false', 'true'],
},
},
},
'tabs': {
events: ['change'],
children: ['tab-content', 'tab-bar'],
},
'tab-bar': {
parents: ['tabs'],
children: ['text'],
attrs: {
mode: {
enum: ['fixed'],
},
},
},
'tab-content': {
parents: ['tabs'],
children: ['div', 'stack'], // to be checked
},
'image-animator': {
atomic: true,
selfClosing: true,
events: ['stop'],
attrs: {
images: {
required: true,
},
iteration: {},
reverse: {
enum: ['false', 'true'],
},
fixedsize: {
enum: ['true', 'false'],
},
duration: {
required: true,
},
fillmode: {
enum: ['none', 'forwards'],
},
},
},
'image': {
alias: ['img'],
atomic: true,
selfClosing: true,
attrs: {
src: {
checkPath: true,
},
},
},
'progress': {
atomic: true,
selfClosing: true,
attrs: {
type: {
enum: ['horizontal', 'arc'],
},
percent: {
checkFunc: 'number',
},
},
},
'text': {
atomic: true,
textContent: true,
attrs: {
type: {
enum: ['text', 'html'],
},
value: {},
},
},
'marquee': {
atomic: true,
attrs: {
scrollamount: {
def: 6,
checkFunc: 'number',
},
},
},
'analog-clock': {
attrs: {
hour: {
checkFunc: 'number',
},
min: {
checkFunc: 'number',
},
sec: {
checkFunc: 'number',
},
},
},
'clock-hand': {
parents: ['analog-clock'],
attrs: {
type: {
enum: ['hour', 'min', 'sec'],
},
src: {
checkPath: true,
},
},
},
'chart': {
atomic: true,
selfClosing: true,
attrs: {
type: {
enum: ['line', 'bar'],
},
datasets: {},
options: {},
},
},
'input': {
atomic: true,
selfClosing: true,
events: ['change'],
attrs: {
checked: {
enum: ['false', 'true'],
},
type: {
enum: ['button', 'checkbox', 'radio'],
},
name: {},
value: {},
},
},
'slider': {
atomic: true,
selfClosing: true,
events: ['change'],
attrs: {
min: {
def: 0,
checkFunc: 'number',
},
max: {
def: 100,
checkFunc: 'number',
},
value: {
def: 0,
checkFunc: 'number',
},
},
},
'switch': {
events: ['change'],
atomic: true,
selfClosing: true,
attrs: {
checked: {
enum: ['false', 'true'],
},
},
},
'picker-view': {
atomic: true,
selfClosing: true,
uevents: ['change'],
attrs: {
type: {
enum: ['text', 'time'],
},
range: {},
selected: {},
},
},
};
const liteCommonTag = {
events: [
'click',
'longpress',
'touchstart',
'touchmove',
'touchcancel',
'touchend',
'key',
'swipe',
],
attrs: {
id: {},
style: {},
class: {},
ref: {},
if: {
excludeRoot: true,
def: 'true',
},
elif: {
def: 'true',
},
else: {
excludeRoot: true,
},
for: {
excludeRoot: true,
},
tid: {},
show: {
excludeRoot: true,
def: 'true',
},
},
};
/**
* Rules for adapting to different environments. If it is `liteWearable` device type,
* set to this type of verification rule.
* @param {String} deviceType device type.
* @return {Object} Validation rules.
*/
function select(deviceType) {
tag = {
liteWearable: litewearableTag,
smartVision: { ...litewearableTag, ...smartvisionTag },
};
return tag[deviceType];
}
let liteNativeTag = select(process.env.DEVICE_TYPE);
/**
* Whether the file exists, get customized rules.
*/
(function checkFile() {
if (rulePath) {
const customTag = require(rulePath);
isExtends(customTag);
}
})();
/**
* Get the component types supported by the current verification rule.
* @return {Array} Supported component name.
*/
function getKeys() {
const res = [];
const keys = Object.keys(liteNativeTag);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
res.push(key);
}
res.push('attrs');
return res;
}
/**
* According to user-defined rules, combine into new verification rules.
* @param {Object} customTag User-defined rule object.
*/
function isExtends(customTag) {
if (customTag.extends == 'recommended') {
const nativekeys = getKeys();
merge(liteNativeTag, customTag.rules, nativekeys);
} else {
liteNativeTag = customTag.rules;
}
}
/**
* Combine the original rules and user-defined rules.
* @param {Object} object Original rules.
* @param {Object} source user-defined rules.
* @param {Array} nativekeys Supported component name.
* @return {Array} Merged object.
*/
function merge(object, source, nativekeys) {
const keys = Object.keys(source);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = source[key];
let target = object[key];
if (target != null && !nativekeys.includes(key)) {
console.error(
`\u001b[31mError in .literc.js: \n` +
`Attribute '${key}' already exists and cannot be modified\u001b[39m`,
);
process.exit(1);
} else if (isType.isObject(value)) {
target = isType.isObject(target) ? target : {};
object[key] = merge(target, value, nativekeys);
} else if (!(isType.isNull(value) || isType.isUndefined(value))) {
object[key] = value;
}
}
return object;
}
module.exports = {
liteNativeTag: liteNativeTag,
liteCommonTag: liteCommonTag,
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,452 @@
/*
* Copyright (c) 2020 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 THEME_PROP_GROUPS = {
emui_color_fg: "0",
ohos_color_fg: "0",
emui_color_fg_inverse: "1",
ohos_color_fg_inverse: "1",
emui_color_bg: "3",
ohos_color_bg: "3",
emui_accent: "4",
ohos_accent: "4",
emui_accent_inverse: "5",
ohos_accent_inverse: "5",
emui_functional_red: "6",
ohos_functional_red: "6",
emui_color_warning: "7",
ohos_color_warning: "7",
emui_color_handup: "8",
ohos_color_handup: "8",
emui_color_connected: "9",
ohos_color_connected: "9",
emui_color_control_activated: "50",
ohos_color_control_activated: "50",
emui_control_normal: "51",
ohos_control_normal: "51",
emui_color_divider_horizontal: "52",
ohos_color_divider_horizontal: "52",
emui_color_subheader_divider: "53",
ohos_color_subheader_divider: "53",
emui_color_click_effect_default: "54",
ohos_color_click_effect_default: "54",
emui_fab_icon: "124",
ohos_fab_icon: "124",
emui_fab_bg_normal: "127",
ohos_fab_bg_normal: "127",
emui_card_bg: "135",
ohos_card_bg: "135",
emui_color_tooltips_bg: "137",
ohos_color_tooltips_bg: "137",
emui_activated: "138",
ohos_activated: "138",
emui_color_primary: "200",
ohos_color_primary: "200",
emui_primary_inverse: "201",
ohos_primary_inverse: "201",
emui_color_secondary: "202",
ohos_color_secondary: "202",
emui_color_tertiary: "203",
ohos_color_tertiary: "203",
emui_color_text_primary: "250",
ohos_color_text_primary: "250",
emui_text_primary_inverse: "251",
ohos_text_primary_inverse: "251",
emui_color_text_secondary: "252",
ohos_color_text_secondary: "252",
emui_text_secondary_inverse: "253",
ohos_text_secondary_inverse: "253",
emui_color_text_tertiary: "254",
ohos_color_text_tertiary: "254",
emui_text_tertiary_inverse: "255",
ohos_text_tertiary_inverse: "255",
emui_text_color_alert_dialog_list_item: "256",
ohos_text_color_alert_dialog_list_item: "256",
emui_functional_blue: "257",
ohos_functional_blue: "257",
emui_text_hint: "258",
ohos_text_hint: "258",
emui_text_hint_inverse: "259",
ohos_text_hint_inverse: "259",
emui_functional_blue_inverse: "260",
ohos_functional_blue_inverse: "260",
emui_color_text_highlight: "261",
ohos_color_text_highlight: "261",
emui_text_highlight_inverse: "262",
ohos_text_highlight_inverse: "262",
emui_color_1: "300",
ohos_color_1: "300",
emui_color_2: "301",
ohos_color_2: "301",
emui_color_3: "302",
ohos_color_3: "302",
emui_color_4: "303",
ohos_color_4: "303",
emui_color_5: "304",
ohos_color_5: "304",
emui_color_6: "305",
ohos_color_6: "305",
emui_color_7: "306",
ohos_color_7: "306",
emui_color_8: "307",
ohos_color_8: "307",
emui_color_9: "308",
ohos_color_9: "308",
emui_color_10: "309",
ohos_color_10: "309",
emui_color_11: "310",
ohos_color_11: "310",
emui_color_fg_1: "311",
ohos_color_fg_1: "311",
emui_color_fg_2: "312",
ohos_color_fg_2: "312",
emui_color_fg_3: "313",
ohos_color_fg_3: "313",
emui_color_fg_4: "314",
ohos_color_fg_4: "314",
emui_color_fg_5: "315",
ohos_color_fg_5: "315",
emui_color_fg_6: "316",
ohos_color_fg_6: "316",
emui_color_fg_7: "317",
ohos_color_fg_7: "317",
emui_color_fg_8: "318",
ohos_color_fg_8: "318",
emui_color_fg_9: "319",
ohos_color_fg_9: "319",
emui_color_fg_10: "320",
ohos_color_fg_10: "320",
emui_color_fg_11: "321",
ohos_color_fg_11: "321",
emui_primary_content_alpha: "400",
ohos_primary_content_alpha: "400",
emui_secondary_content_alpha: "401",
ohos_secondary_content_alpha: "401",
emui_tertiary_content_alpha: "402",
ohos_tertiary_content_alpha: "402",
emui_disabled_alpha: "403",
ohos_disabled_alpha: "403",
emui_highlight_bg_alpha: "404",
ohos_highlight_bg_alpha: "404",
emui_normal_bg_alpha: "405",
ohos_normal_bg_alpha: "405",
emui_tips_bg_alpha: "406",
ohos_tips_bg_alpha: "406",
emui_divider_alpha: "407",
ohos_divider_alpha: "407",
emui_text_size_headline1: "500",
ohos_text_size_headline1: "500",
emui_text_size_headline2: "501",
ohos_text_size_headline2: "501",
emui_text_size_headline3: "502",
ohos_text_size_headline3: "502",
emui_text_size_headline4: "503",
ohos_text_size_headline4: "503",
emui_text_size_headline5: "504",
ohos_text_size_headline5: "504",
emui_text_size_headline6: "505",
ohos_text_size_headline6: "505",
emui_text_size_headline7: "506",
ohos_text_size_headline7: "506",
emui_text_size_headline8: "507",
ohos_text_size_headline8: "507",
emui_text_size_subtitle1: "508",
ohos_text_size_subtitle1: "508",
emui_text_size_subtitle2: "509",
ohos_text_size_subtitle2: "509",
emui_text_size_subtitle3: "510",
ohos_text_size_subtitle3: "510",
emui_text_size_button1: "511",
ohos_text_size_button1: "511",
emui_text_size_button2: "512",
ohos_text_size_button2: "512",
emui_text_size_body1: "513",
ohos_text_size_body1: "513",
emui_text_size_body2: "514",
ohos_text_size_body2: "514",
emui_text_size_body3: "515",
ohos_text_size_body3: "515",
emui_text_size_caption: "516",
ohos_text_size_caption: "516",
emui_text_size_caption1: "517",
ohos_text_size_caption1: "517",
emui_text_size_chart1: "518",
ohos_text_size_chart1: "518",
emui_text_size_chart2: "519",
ohos_text_size_chart2: "519",
emui_text_size_overline: "520",
ohos_text_size_overline: "520",
emui_text_font_family_regular: "550",
ohos_text_font_family_regular: "550",
emui_text_font_family_medium: "551",
ohos_text_font_family_medium: "551",
emui_corner_radius_notification: "611",
ohos_corner_radius_notification: "611",
emui_corner_radius_grid: "615",
ohos_corner_radius_grid: "615",
emui_corner_radius_icon: "619",
ohos_corner_radius_icon: "619",
emui_corner_radius_large: "650",
ohos_corner_radius_large: "650",
emui_corner_radius_mediums: "651",
ohos_corner_radius_mediums: "651",
emui_corner_radius_small: "652",
ohos_corner_radius_small: "652",
emui_corner_radius_xsmal: "653",
ohos_corner_radius_xsmal: "653",
emui_dimens_default_start: "700",
ohos_dimens_default_start: "700",
emui_dimens_max_start: "701",
ohos_dimens_max_start: "701",
emui_dimens_default_end: "702",
ohos_dimens_default_end: "702",
emui_dimens_max_end: "703",
ohos_dimens_max_end: "703",
emui_dimens_default_top: "704",
ohos_dimens_default_top: "704",
emui_dimens_default_bottom_flexible: "705",
ohos_dimens_default_bottom_flexible: "705",
emui_dimens_default_bottom_fixed: "706",
ohos_dimens_default_bottom_fixed: "706",
emui_dimens_card_start: "725",
ohos_dimens_card_start: "725",
emui_dimens_card_end: "726",
ohos_dimens_card_end: "726",
emui_dimens_card_middle: "727",
ohos_dimens_card_middle: "727",
emui_dimens_text_vertical: "740",
ohos_dimens_text_vertical: "740",
emui_dimens_text_horizontal: "741",
ohos_dimens_text_horizontal: "741",
emui_dimens_text_margin_primary: "742",
ohos_dimens_text_margin_primary: "742",
emui_dimens_text_margin_secondary: "743",
ohos_dimens_text_margin_secondary: "743",
emui_dimens_text_margin_tertiary: "744",
ohos_dimens_text_margin_tertiary: "744",
emui_dimens_text_margin_fourth: "745",
ohos_dimens_text_margin_fourth: "745",
emui_dimens_text_margin_fifth: "746",
ohos_dimens_text_margin_fifth: "746",
emui_dimens_element_vertical_large: "760",
ohos_dimens_element_vertical_large: "760",
emui_dimens_element_vertical_middle: "761",
ohos_dimens_element_vertical_middle: "761",
emui_dimens_element_horizontal_large: "762",
ohos_dimens_element_horizontal_large: "762",
emui_dimens_element_horizontal_middle: "763",
ohos_dimens_element_horizontal_middle: "763",
emui_text_size_space_short: "780",
ohos_text_size_space_short: "780",
emui_text_size_space_large: "781",
ohos_text_size_space_large: "781",
app_background: "900",
select_clicked_color: "1000",
select_disabled_text_color: "1001",
menu_selected_color: "1002",
select_font_size: "1003",
select_font_color: "1004",
select_triangle_icon_size: "1011",
menu_background_radius: "1012",
menu_min_width: "1015",
button_background_color: "1100",
button_disabled_color: "1102",
button_text_focus_color: "1120",
button_text_color: "1121",
button_text_disabled_color: "1122",
button_text_waiting_color: "1123",
button_text_fontsize: "1124",
button_text_fontsize_min: "1125",
button_text_fontweight: "1126",
button_text_max_lines: "1127",
button_radius: "1140",
button_min_width: "1141",
button_height: "1142",
button_padding_horizontal: "1143",
button_padding_vertical: "1144",
checkbox_foreground_color: "1200",
checkbox_active_color: "1201",
checkbox_inactive_color: "1202",
checkbox_size: "1204",
checkbox_border_radius: "1206",
checkbox_border_width: "1207",
checkbox_stroke_width: "1208",
radio_foreground_color: "1300",
radio_active_color: "1301",
radio_inactive_color: "1302",
radio_size: "1304",
radio_border_width: "1306",
switch_foreground_color: "1400",
switch_active_color: "1401",
switch_inactive_color: "1402",
switch_width: "1404",
switch_height: "1405",
switch_border_width: "1409",
marquee_text_color: "1500",
marquee_font_size: "1501",
progress_color: "1611",
progress_secondary_color: "1600",
progress_bg_color: "1601",
progress_thickness: "1602",
progress_loading_color: "1603",
progress_scale_length: "1604",
progress_scale_width: "1605",
progress_scale_number: "1608",
rating_width: "1700",
rating_height: "1701",
rating_indicator_width: "1702",
rating_indicator_height: "1703",
rating_star_num: "1705",
rating_score: "1706",
rating_indicator_score: "1707",
rating_step_size: "1708",
slider_block_color: "1800",
slider_track_thickness: "1803",
slider_track_selected: "1804",
slider_track_bg: "1805",
text_size: "1900",
dialog_radius: "2000",
dialog_background_color: "2001",
dialog_title_text_color: "2002",
dialog_title_text_fontsize: "2003",
dialog_title_text_fontsize_min: "2004",
dialog_title_text_fontweight: "2005",
dialog_title_text_max_lines: "2006",
dialog_content_text_color: "2007",
dialog_content_text_fontsize: "2008",
dialog_animation_duration_in: "2020",
dialog_animation_duration_out: "2021",
dialog_content_text_fontsize_min: "2032",
popup_padding_horizontal: "2100",
popup_padding_vertical: "2101",
popup_background_color: "2103",
popup_text_color: "2104",
popup_text_fontsize: "2105",
swiper_indicator_normal_color: "2200",
swiper_indicator_selected_color: "2201",
swiper_indicator_size: "2202",
swiper_indicator_selected_size: "2203",
toast_padding_horizontal: "2300",
toast_padding_vertical: "2301",
toast_background_color: "2304",
toast_text_fontweight: "2305",
toast_text_color: "2306",
toast_text_fontsize: "2307",
toast_radius: "2308",
textfield_padding_horizontal: "2400",
textfield_padding_vertical: "2401",
textfield_height: "2402",
textfield_font_size: "2403",
textfield_font_weight: "2404",
textfield_border_radius: "2405",
textfield_background_color: "2407",
textfield_placeholder_color: "2408",
textfield_text_color: "2409",
textfield_focus_background_color: "2410",
textfield_focus_placeholder_color: "2411",
textfield_focus_text_color: "2412",
textfield_cursor_color: "2415",
textfield_icon_size: "2417",
textfield_error_text_color: "2420",
textfield_error_border_color: "2424",
textfield_text_selected_color: "2425",
video_bar_time_text_color: "2615",
video_error_text_color: "2616",
video_bar_background: "2617",
tab_active_indicator_color: "2705",
navigation_bar_title_color: "2900",
navigation_bar_title_font_size: "2901",
navigation_bar_title_font_size_emphasize: "2902",
navigation_bar_subtitle_color: "2903",
navigation_bar_subtitle_font_size: "2904",
navigation_bar_height: "2905",
navigation_bar_height_emphasize: "2906",
navigation_bar_menu_zone_width: "2909",
navigation_bar_menu_icon_width: "2910",
navigation_bar_logo_icon_width: "2911",
navigation_bar_more_zone_width: "2912",
navigation_bar_more_zone_height: "2913",
navigation_bar_more_icon_width: "2914",
navigation_bar_more_icon_height: "2915",
navigation_bar_max_padding_start: "2920",
navigation_bar_max_padding_end: "2921",
navigation_bar_default_padding_start: "2922",
navigation_bar_default_padding_end: "2923",
picker_popup_radius: "3002",
picker_popup_padding: "3003",
picker_button_font_size: "3019",
picker_button_text_color: "3020",
picker_select_option_font_size: "3021",
picker_select_option_text_color: "3022",
picker_normal_option_font_size: "3025",
picker_normal_option_font_color: "3026",
picker_title_font_size: "3028",
picker_title_text_color: "3029",
scroll_bar_background_color: "3304",
scroll_bar_foreground_color: "3305",
refresh_default_progress_diameter: "3404",
search_icon_size: "3600",
search_text_field_padding_left: "3602",
search_text_field_radius: "3603",
search_text_color: "3605",
search_placeholder_color: "3606",
search_close_icon_size: "3607",
search_font_size: "3610",
search_font_weight: "3611",
search_focus_text_color: "3613",
text_overlay_handle_color: "3718",
text_overlay_handle_diameter: "3719",
calendar_week_font_size: "3500",
calendar_day_font_size : "3501",
calendar_lunar_font_size: "3502",
calendar_week_color: "3503",
calendar_day_color: "3504",
calendar_lunar_color: "3505",
calendar_weekend_day_color: "3506",
calendar_weekend_lunar_color: "3507",
calendar_today_day_color: "3508",
calendar_today_lunar_color: "3509",
calendar_non_current_month_day_color: "3510",
calendar_non_current_month_lunar_color: "3511",
calendar_work_day_mark_font_size: "3512",
calendar_off_day_mark_font_size: "3513",
calendar_work_day_mark_color: "3514",
calendar_off_day_mark_color: "3515",
calendar_not_current_month_work_day_mark_color: "3516",
calendar_not_current_month_off_day_mark_color: "3517",
calendar_focused_day_color: "3518",
calendar_focused_lunar_color: "3519",
calendar_focused_area_radius: "3520",
calendar_focused_area_background_color: "3521",
calendar_top_padding: "3522",
calendar_blur_area_background_color : "3523",
calendar_col_space: "3524",
calendar_week_height: "3525",
calendar_day_height: "3526",
calendar_week_width: "3527",
calendar_day_width: "3528",
calendar_week_and_day_row_space: "3529",
calendar_daily_five_row_space: "3530",
calendar_daily_six_row_space: "3531",
calendar_gregorian_calendar_height: "3532",
calendar_work_state_width: "3533",
theme_calendar_day_font_wight: "3534",
theme_calendar_lunar_day_font_wight: "3535",
theme_calendar_work_state_font_wight: "3536",
theme_calendar_work_state_horizontal_moving_distance: "3566",
theme_calendar_work_state_vertical_moving_distance: "3567"
};
module.exports = THEME_PROP_GROUPS;

View File

@ -0,0 +1,684 @@
/*
* Copyright (c) 2020 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 OHOS_THEME_STYLES = {
ic_app: '0',
request_location_reminder_title: '1',
request_location_reminder_content: '2',
theme_light: '3',
theme_dark: '4',
theme_transparent: '5',
id_color_foreground: '6',
id_color_foreground_dark: '7',
id_color_foreground_transparent: '8',
id_color_foreground_contrary: '9',
id_color_foreground_contrary_dark: '10',
id_color_foreground_contrary_transparent: '11',
id_color_foreground_contrary_disable: '12',
id_color_foreground_contrary_disable_dark: '13',
id_color_foreground_contrary_disable_transparent: '14',
id_color_background: '15',
id_color_background_dark: '16',
id_color_background_transparent: '17',
id_color_sub_background: '18',
id_color_sub_background_dark: '19',
id_color_sub_background_transparent: '20',
id_color_emphasize: '21',
id_color_emphasize_dark: '22',
id_color_emphasize_transparent: '23',
id_color_emphasize_contrary: '24',
id_color_emphasize_contrary_dark: '25',
id_color_emphasize_contrary_transparent: '26',
id_color_alert: '27',
id_color_alert_dark: '28',
id_color_alert_transparent: '29',
id_color_warning: '30',
id_color_warning_dark: '31',
id_color_warning_transparent: '32',
id_color_handup: '33',
id_color_handup_dark: '34',
id_color_handup_transparent: '35',
id_color_connected: '36',
id_color_connected_dark: '37',
id_color_connected_transparent: '38',
id_color_component_activated: '39',
id_color_component_activated_dark: '40',
id_color_component_activated_transparent: '41',
id_color_component_normal: '42',
id_color_component_normal_dark: '43',
id_color_component_normal_transparent: '44',
id_color_list_separator: '45',
id_color_list_separator_dark: '46',
id_color_list_separator_transparent: '47',
id_color_subheading_separator: '48',
id_color_subheading_separator_dark: '49',
id_color_subheading_separator_transparent: '50',
id_color_click_effect: '51',
id_color_click_effect_dark: '52',
id_color_click_effect_transparent: '53',
id_color_hover: '54',
id_color_hover_dark: '55',
id_color_hover_transparent: '56',
id_color_focused_content_primary: '57',
id_color_focused_content_primary_dark: '58',
id_color_focused_content_primary_transparent: '59',
id_color_focused_content_second: '60',
id_color_focused_content_second_dark: '61',
id_color_focused_content_second_transparent: '62',
id_color_focused_content_tertiary: '63',
id_color_focused_content_tertiary_dark: '64',
id_color_focused_content_tertiary_transparent: '65',
id_color_focused_outline: '66',
id_color_focused_outline_dark: '67',
id_color_focused_outline_transparent: '68',
id_color_focused_bg: '69',
id_color_focused_bg_dark: '70',
id_color_focused_bg_transparent: '71',
id_color_primary: '72',
id_color_primary_dark: '73',
id_color_primary_transparent: '74',
id_color_primary_contrary: '75',
id_color_primary_contrary_dark: '76',
id_color_primary_contrary_transparent: '77',
id_color_secondary: '78',
id_color_secondary_dark: '79',
id_color_secondary_transparent: '80',
id_color_tertiary: '81',
id_color_tertiary_dark: '82',
id_color_tertiary_transparent: '83',
id_color_fourth: '84',
id_color_fourth_dark: '85',
id_color_fourth_transparent: '86',
id_color_activated: '87',
id_color_activated_dark: '88',
id_color_activated_transparent: '89',
id_color_activated_start: '90',
id_color_activated_start_dark: '91',
id_color_activated_start_transparent: '92',
id_color_activated_end: '93',
id_color_activated_end_dark: '94',
id_color_activated_end_transparent: '95',
id_color_text_primary: '96',
id_color_text_primary_dark: '97',
id_color_text_primary_transparent: '98',
id_color_text_primary_contrary: '99',
id_color_text_primary_contrary_dark: '100',
id_color_text_primary_contrary_transparent: '101',
id_color_text_secondary: '102',
id_color_text_secondary_dark: '103',
id_color_text_secondary_transparent: '104',
id_color_text_secondary_contrary: '105',
id_color_text_secondary_contrary_dark: '106',
id_color_text_secondary_contrary_transparent: '107',
id_color_text_tertiary: '108',
id_color_text_tertiary_dark: '109',
id_color_text_tertiary_transparent: '110',
id_color_text_tertiary_contrary: '111',
id_color_text_tertiary_contrary_dark: '112',
id_color_text_tertiary_contrary_transparent: '113',
id_color_text_primary_activated: '114',
id_color_text_primary_activated_dark: '115',
id_color_text_primary_activated_transparent: '116',
id_color_text_secondary_activated: '117',
id_color_text_secondary_activated_dark: '118',
id_color_text_secondary_activated_transparent: '119',
id_color_text_search_url: '120',
id_color_text_search_url_dark: '121',
id_color_text_search_url_transparent: '122',
id_color_text_hint: '123',
id_color_text_hint_dark: '124',
id_color_text_hint_transparent: '125',
id_color_text_hint_contrary: '126',
id_color_text_hint_contrary_dark: '127',
id_color_text_hint_contrary_transparent: '128',
id_color_text_hyperlink: '129',
id_color_text_hyperlink_dark: '130',
id_color_text_hyperlink_transparent: '131',
id_color_text_hyperlink_contrary: '132',
id_color_text_hyperlink_contrary_dark: '133',
id_color_text_hyperlink_contrary_transparent: '134',
id_color_text_highlight_bg: '135',
id_color_text_highlight_bg_dark: '136',
id_color_text_highlight_bg_transparent: '137',
id_color_text_highlight_bg_contrary: '138',
id_color_text_highlight_bg_contrary_dark: '139',
id_color_text_highlight_bg_contrary_transparent: '140',
id_color_palette1: '141',
id_color_palette1_dark: '142',
id_color_palette1_transparent: '143',
id_color_palette2: '144',
id_color_palette2_dark: '145',
id_color_palette2_transparent: '146',
id_color_palette3: '147',
id_color_palette3_dark: '148',
id_color_palette3_transparent: '149',
id_color_palette4: '150',
id_color_palette4_dark: '151',
id_color_palette4_transparent: '152',
id_color_palette5: '153',
id_color_palette5_dark: '154',
id_color_palette5_transparent: '155',
id_color_palette6: '156',
id_color_palette6_dark: '157',
id_color_palette6_transparent: '158',
id_color_palette7: '159',
id_color_palette7_dark: '160',
id_color_palette7_transparent: '161',
id_color_palette8: '162',
id_color_palette8_dark: '163',
id_color_palette8_transparent: '164',
id_color_palette9: '165',
id_color_palette9_dark: '166',
id_color_palette9_transparent: '167',
id_color_palette10: '168',
id_color_palette10_dark: '169',
id_color_palette10_transparent: '170',
id_color_palette11: '171',
id_color_palette11_dark: '172',
id_color_palette11_transparent: '173',
id_color_palette_aux1: '174',
id_color_palette_aux1_dark: '175',
id_color_palette_aux1_transparent: '176',
id_color_palette_aux2: '177',
id_color_palette_aux2_dark: '178',
id_color_palette_aux2_transparent: '179',
id_color_palette_aux3: '180',
id_color_palette_aux3_dark: '181',
id_color_palette_aux3_transparent: '182',
id_color_palette_aux4: '183',
id_color_palette_aux4_dark: '184',
id_color_palette_aux4_transparent: '185',
id_color_palette_aux5: '186',
id_color_palette_aux5_dark: '187',
id_color_palette_aux5_transparent: '188',
id_color_palette_aux6: '189',
id_color_palette_aux6_dark: '190',
id_color_palette_aux6_transparent: '191',
id_color_palette_aux7: '192',
id_color_palette_aux7_dark: '193',
id_color_palette_aux7_transparent: '194',
id_color_palette_aux8: '195',
id_color_palette_aux8_dark: '196',
id_color_palette_aux8_transparent: '197',
id_color_palette_aux9: '198',
id_color_palette_aux9_dark: '199',
id_color_palette_aux9_transparent: '200',
id_color_palette_aux10: '201',
id_color_palette_aux10_dark: '202',
id_color_palette_aux10_transparent: '203',
id_color_palette_aux11: '204',
id_color_palette_aux11_dark: '205',
id_color_palette_aux11_transparent: '206',
id_color_special1: '207',
id_color_special1_dark: '208',
id_color_special1_transparent: '209',
id_color_special2: '210',
id_color_special2_dark: '211',
id_color_special2_transparent: '212',
id_color_special3: '213',
id_color_special3_dark: '214',
id_color_special3_transparent: '215',
id_color_special4: '216',
id_color_special4_dark: '217',
id_color_special4_transparent: '218',
id_color_special5: '219',
id_color_special5_dark: '220',
id_color_special5_transparent: '221',
id_color_special6: '222',
id_color_special6_dark: '223',
id_color_special6_transparent: '224',
id_color_special7: '225',
id_color_special7_dark: '226',
id_color_special7_transparent: '227',
id_color_special8: '228',
id_color_special8_dark: '229',
id_color_special8_transparent: '230',
id_color_special9: '231',
id_color_special9_dark: '232',
id_color_special9_transparent: '233',
id_color_special10: '234',
id_color_special10_dark: '235',
id_color_special10_transparent: '236',
id_color_special11: '237',
id_color_special11_dark: '238',
id_color_special11_transparent: '239',
id_color_mask_thin: '240',
id_color_mask_thin_dark: '241',
id_color_mask_thin_transparent: '242',
id_color_mask_light: '243',
id_color_mask_light_dark: '244',
id_color_mask_light_transparent: '245',
id_color_mask_regular: '246',
id_color_mask_regular_dark: '247',
id_color_mask_regular_transparent: '248',
id_color_mask_thick: '249',
id_color_mask_thick_dark: '250',
id_color_mask_thick_transparent: '251',
id_alpha_content_primary: '252',
id_alpha_content_primary_dark: '253',
id_alpha_content_primary_transparent: '254',
id_alpha_content_secondary: '255',
id_alpha_content_secondary_dark: '256',
id_alpha_content_secondary_transparent: '257',
id_alpha_content_tertiary: '258',
id_alpha_content_tertiary_dark: '259',
id_alpha_content_tertiary_transparent: '260',
id_alpha_content_fourth: '261',
id_alpha_content_fourth_dark: '262',
id_alpha_content_fourth_transparent: '263',
id_alpha_disabled: '264',
id_alpha_disabled_dark: '265',
id_alpha_disabled_transparent: '266',
id_alpha_highlight_bg: '267',
id_alpha_highlight_bg_dark: '268',
id_alpha_highlight_bg_transparent: '269',
id_alpha_normal_bg: '270',
id_alpha_normal_bg_dark: '271',
id_alpha_normal_bg_transparent: '272',
id_alpha_inapptip_bg: '273',
id_alpha_inapptip_bg_dark: '274',
id_alpha_inapptip_bg_transparent: '275',
id_alpha_separator_line: '276',
id_alpha_separator_line_dark: '277',
id_alpha_separator_line_transparent: '278',
id_color_statusbar_bg: '279',
id_color_statusbar_bg_dark: '280',
id_color_statusbar_bg_transparent: '281',
id_color_navigationbar_bg: '282',
id_color_navigationbar_bg_dark: '283',
id_color_navigationbar_bg_transparent: '284',
id_color_titlebar_icon: '285',
id_color_titlebar_icon_dark: '286',
id_color_titlebar_icon_transparent: '287',
id_color_titlebar_icon_pressed: '288',
id_color_titlebar_icon_pressed_dark: '289',
id_color_titlebar_icon_pressed_transparent: '290',
id_color_titlebar_text: '291',
id_color_titlebar_text_dark: '292',
id_color_titlebar_text_transparent: '293',
id_color_titlebar_text_off: '294',
id_color_titlebar_text_off_dark: '295',
id_color_titlebar_text_off_transparent: '296',
id_color_titlebar_subtitle_text: '297',
id_color_titlebar_subtitle_text_dark: '298',
id_color_titlebar_subtitle_text_transparent: '299',
id_color_titlebar_bg: '300',
id_color_titlebar_bg_dark: '301',
id_color_titlebar_bg_transparent: '302',
id_color_titlebar_sub_bg: '303',
id_color_titlebar_sub_bg_dark: '304',
id_color_titlebar_sub_bg_transparent: '305',
id_color_bottom_tab_icon: '306',
id_color_bottom_tab_icon_dark: '307',
id_color_bottom_tab_icon_transparent: '308',
id_color_bottom_tab_icon_off: '309',
id_color_bottom_tab_icon_off_dark: '310',
id_color_bottom_tab_icon_off_transparent: '311',
id_color_bottom_tab_icon_auxcolor01: '312',
id_color_bottom_tab_icon_auxcolor01_dark: '313',
id_color_bottom_tab_icon_auxcolor01_transparent: '314',
id_color_bottom_tab_icon_auxcolor_off01: '315',
id_color_bottom_tab_icon_auxcolor_off01_dark: '316',
id_color_bottom_tab_icon_auxcolor_off01_transparent: '317',
id_color_bottom_tab_icon_auxcolor02: '318',
id_color_bottom_tab_icon_auxcolor02_dark: '319',
id_color_bottom_tab_icon_auxcolor02_transparent: '320',
id_color_bottom_tab_icon_auxcolor_off02: '321',
id_color_bottom_tab_icon_auxcolor_off02_dark: '322',
id_color_bottom_tab_icon_auxcolor_off02_transparent: '323',
id_color_bottom_tab_text_on: '324',
id_color_bottom_tab_text_on_dark: '325',
id_color_bottom_tab_text_on_transparent: '326',
id_color_bottom_tab_text_off: '327',
id_color_bottom_tab_text_off_dark: '328',
id_color_bottom_tab_text_off_transparent: '329',
id_color_bottom_tab_bg: '330',
id_color_bottom_tab_bg_dark: '331',
id_color_bottom_tab_bg_transparent: '332',
id_color_bottom_tab_bg_blur: '333',
id_color_bottom_tab_bg_blur_dark: '334',
id_color_bottom_tab_bg_blur_transparent: '335',
id_color_bottom_tab_sub_bg: '336',
id_color_bottom_tab_sub_bg_dark: '337',
id_color_bottom_tab_sub_bg_transparent: '338',
id_color_bottom_tab_sub_bg_blur: '339',
id_color_bottom_tab_sub_bg_blur_dark: '340',
id_color_bottom_tab_sub_bg_blur_transparent: '341',
id_color_subtab_text_on: '342',
id_color_subtab_text_on_dark: '343',
id_color_subtab_text_on_transparent: '344',
id_color_subtab_text_off: '345',
id_color_subtab_text_off_dark: '346',
id_color_subtab_text_off_transparent: '347',
id_color_subtab_line_on: '348',
id_color_subtab_line_on_dark: '349',
id_color_subtab_line_on_transparent: '350',
id_color_subtab_bg: '351',
id_color_subtab_bg_dark: '352',
id_color_subtab_bg_transparent: '353',
id_color_toolbar_icon: '354',
id_color_toolbar_icon_dark: '355',
id_color_toolbar_icon_transparent: '356',
id_color_toolbar_icon_actived: '357',
id_color_toolbar_icon_actived_dark: '358',
id_color_toolbar_icon_actived_transparent: '359',
id_color_toolbar_text: '360',
id_color_toolbar_text_dark: '361',
id_color_toolbar_text_transparent: '362',
id_color_toolbar_text_actived: '363',
id_color_toolbar_text_actived_dark: '364',
id_color_toolbar_text_actived_transparent: '365',
id_color_toolbar_bg: '366',
id_color_toolbar_bg_dark: '367',
id_color_toolbar_bg_transparent: '368',
id_color_toolbar_sub_bg: '369',
id_color_toolbar_sub_bg_dark: '370',
id_color_toolbar_sub_bg_transparent: '371',
id_color_text_field_bg: '372',
id_color_text_field_bg_dark: '373',
id_color_text_field_bg_transparent: '374',
id_color_text_field_sub_bg: '375',
id_color_text_field_sub_bg_dark: '376',
id_color_text_field_sub_bg_transparent: '377',
id_color_progress: '378',
id_color_progress_dark: '379',
id_color_progress_transparent: '380',
id_color_spinner_icon: '381',
id_color_spinner_icon_dark: '382',
id_color_spinner_icon_transparent: '383',
id_color_badge: '384',
id_color_badge_dark: '385',
id_color_badge_transparent: '386',
id_color_badge_red: '387',
id_color_badge_red_dark: '388',
id_color_badge_red_transparent: '389',
id_color_dialog_bg: '390',
id_color_dialog_bg_dark: '391',
id_color_dialog_bg_transparent: '392',
id_color_button_normal: '393',
id_color_button_normal_dark: '394',
id_color_button_normal_transparent: '395',
id_color_switch_outline_off: '396',
id_color_switch_outline_off_dark: '397',
id_color_switch_outline_off_transparent: '398',
id_color_switch_bg_off: '399',
id_color_switch_bg_off_dark: '400',
id_color_switch_bg_off_transparent: '401',
id_color_floating_button_icon: '402',
id_color_floating_button_icon_dark: '403',
id_color_floating_button_icon_transparent: '404',
id_color_floating_button_icon_start: '405',
id_color_floating_button_icon_start_dark: '406',
id_color_floating_button_icon_start_transparent: '407',
id_color_floating_button_icon_end: '408',
id_color_floating_button_icon_end_dark: '409',
id_color_floating_button_icon_end_transparent: '410',
id_color_floating_button_bg_normal: '411',
id_color_floating_button_bg_normal_dark: '412',
id_color_floating_button_bg_normal_transparent: '413',
id_color_floating_button_start: '414',
id_color_floating_button_start_dark: '415',
id_color_floating_button_start_transparent: '416',
id_color_floating_button_center: '417',
id_color_floating_button_center_dark: '418',
id_color_floating_button_center_transparent: '419',
id_color_floating_button_end: '420',
id_color_floating_button_end_dark: '421',
id_color_floating_button_end_transparent: '422',
id_color_floating_button_shadow_start: '423',
id_color_floating_button_shadow_start_dark: '424',
id_color_floating_button_shadow_start_transparent: '425',
id_color_floating_button_shadow_end: '426',
id_color_floating_button_shadow_end_dark: '427',
id_color_floating_button_shadow_end_transparent: '428',
id_color_floating_button_bg_pressed: '429',
id_color_floating_button_bg_pressed_dark: '430',
id_color_floating_button_bg_pressed_transparent: '431',
id_color_instant_tip_bg: '432',
id_color_instant_tip_bg_dark: '433',
id_color_instant_tip_bg_transparent: '434',
id_color_panel_bg: '435',
id_color_panel_bg_dark: '436',
id_color_panel_bg_transparent: '437',
id_color_card_bg: '438',
id_color_card_bg_dark: '439',
id_color_card_bg_transparent: '440',
id_color_list_card_bg: '441',
id_color_list_card_bg_dark: '442',
id_color_list_card_bg_transparent: '443',
id_color_tooltip_foreground: '444',
id_color_tooltip_foreground_dark: '445',
id_color_tooltip_foreground_transparent: '446',
id_color_tooltip_background: '447',
id_color_tooltip_background_dark: '448',
id_color_tooltip_background_transparent: '449',
id_color_help_tip_bg: '450',
id_color_help_tip_bg_dark: '451',
id_color_help_tip_bg_transparent: '452',
id_text_size_headline1: '453',
id_text_size_headline2: '454',
id_text_size_headline3: '455',
id_text_size_headline4: '456',
id_text_size_headline5: '457',
id_text_size_headline6: '458',
id_text_size_headline7: '459',
id_text_size_headline8: '460',
id_text_size_headline9: '461',
id_text_size_sub_title1: '462',
id_text_size_sub_title2: '463',
id_text_size_sub_title3: '464',
id_text_size_button1: '465',
id_text_size_button2: '466',
id_text_size_button3: '467',
id_text_size_body1: '468',
id_text_size_body2: '469',
id_text_size_body3: '470',
id_text_size_caption: '471',
id_text_size_caption1: '472',
id_text_size_chart1: '473',
id_text_size_chart2: '474',
id_text_size_over_line: '475',
id_text_font_family_regular: '476',
id_text_font_family_medium: '477',
id_corner_radius_tips_toast: '478',
id_corner_radius_tips_badge: '479',
id_corner_radius_tips_tips: '480',
id_corner_radius_toggle_button: '481',
id_corner_radius_switch: '482',
id_corner_radius_piece: '483',
id_corner_radius_button: '484',
id_corner_radius_small_button: '485',
id_corner_radius_mark: '486',
id_corner_radius_subtab: '487',
id_corner_radius_clicked: '488',
id_corner_radius_panel: '489',
id_corner_radius_notification: '490',
id_corner_radius_card: '491',
id_corner_radius_progress_bar: '492',
id_corner_radius_dialog: '493',
id_corner_radius_grid: '494',
id_corner_radius_check_box: '495',
id_corner_radius_menu: '496',
id_corner_radius_banner: '497',
id_corner_radius_icon: '498',
id_corner_radius_text_field: '499',
id_corner_radius_default_xl: '500',
id_corner_radius_default_l: '501',
id_corner_radius_default_m: '502',
id_corner_radius_default_s: '503',
id_corner_radius_default_xs: '504',
id_default_padding_start: '505',
id_max_padding_start: '506',
id_default_padding_end: '507',
id_max_padding_end: '508',
id_default_padding_top: '509',
id_default_padding_bottom_flexible: '510',
id_default_padding_bottom_fixed: '511',
id_dialog_margin_start: '512',
id_dialog_margin_end: '513',
id_dialog_margin_bottom: '514',
id_notification_margin_start: '515',
id_notification_margin_end: '516',
id_card_margin_start: '517',
id_card_margin_end: '518',
id_card_margin_middle: '519',
id_text_margin_vertical: '520',
id_text_margin_horizontal: '521',
id_text_paragraph_margin_xl: '522',
id_text_paragraph_margin_l: '523',
id_text_paragraph_margin_m: '524',
id_text_paragraph_margin_s: '525',
id_text_paragraph_margin_xs: '526',
id_elements_margin_vertical_l: '527',
id_elements_margin_vertical_m: '528',
id_elements_margin_horizontal_l: '529',
id_elements_margin_horizontal_m: '530',
id_text_line_space_s: '531',
id_text_line_space_l: '532',
button_pattern_light: '533',
button_pattern_dark: '534',
button_pattern_transparent: '535',
button_bg_light: '536',
button_bg_dark: '537',
button_bg_transparent: '538',
button_radius: '539',
checkbox_pattern_light: '540',
checkbox_pattern_dark: '541',
checkbox_pattern_transparent: '542',
radio_pattern_light: '543',
radio_pattern_dark: '544',
radio_pattern_transparent: '545',
switch_pattern_light: '546',
switch_pattern_dark: '547',
switch_pattern_transparent: '548',
swiper_pattern_light: '549',
swiper_pattern_dark: '550',
swiper_pattern_transparent: '551',
data_panel_pattern_light: '552',
data_panel_pattern_dark: '553',
data_panel_pattern_transparent: '554',
toolbar_pattern_light: '555',
toolbar_pattern_dark: '556',
toolbar_pattern_transparent: '557',
toggle_pattern_light: '558',
toggle_pattern_dark: '559',
toggle_pattern_transparent: '560',
theme_hide_title_bar: '561',
emergency_number: '562',
fa_foreground: '563',
fa_foreground_dark: '564',
fa_foreground_contrary: '565',
fa_foreground_contrary_dark: '566',
fa_emphasize: '567',
fa_emphasize_dark: '568',
fa_emphasize_outline: '569',
fa_emphasize_outline_dark: '570',
fa_alert: '571',
fa_alert_dark: '572',
fa_warning: '573',
fa_warning_dark: '574',
fa_handup: '575',
fa_handup_dark: '576',
fa_connected: '577',
fa_connected_dark: '578',
fa_component_normal: '579',
fa_component_normal_dark: '580',
fa_click_effect: '581',
fa_click_effect_dark: '582',
fa_list_separator: '583',
fa_list_separator_dark: '584',
fa_list_card_bg_blur: '585',
fa_list_card_bg_blur_dark: '586',
fa_list_card_bg: '587',
fa_list_card_bg_dark: '588',
fa_background_blur: '589',
fa_background_blur_dark: '590',
fa_background: '591',
fa_background_dark: '592',
fa_sub_background: '593',
fa_sub_background_dark: '594',
fa_text_primary: '595',
fa_text_primary_dark: '596',
fa_text_secondary: '597',
fa_text_secondary_dark: '598',
fa_text_tertiary: '599',
fa_text_tertiary_dark: '600',
fa_text_fourth: '601',
fa_text_fourth_dark: '602',
fa_text_contrary: '603',
fa_text_contrary_dark: '604',
fa_text_activated: '605',
fa_text_activated_dark: '606',
fa_icon_primary: '607',
fa_icon_primary_dark: '608',
fa_icon_secondary: '609',
fa_icon_secondary_dark: '610',
fa_icon_tertiary: '611',
fa_icon_tertiary_dark: '612',
fa_icon_fourth: '613',
fa_icon_fourth_dark: '614',
fa_icon_contrary: '615',
fa_icon_contrary_dark: '616',
fa_activated: '617',
fa_activated_dark: '618',
fa_palette1: '619',
fa_palette1_dark: '620',
fa_palette2: '621',
fa_palette2_dark: '622',
fa_palette3: '623',
fa_palette3_dark: '624',
fa_palette4: '625',
fa_palette4_dark: '626',
fa_palette5: '627',
fa_palette5_dark: '628',
fa_palette6: '629',
fa_palette6_dark: '630',
fa_palette7: '631',
fa_palette7_dark: '632',
fa_palette8: '633',
fa_palette8_dark: '634',
fa_palette9: '635',
fa_palette9_dark: '636',
fa_palette10: '637',
fa_palette10_dark: '638',
fa_palette11: '639',
fa_palette11_dark: '640',
fa_palette12: '641',
fa_palette12_dark: '642',
fa_alpha_content_primary: '643',
fa_alpha_content_primary_dark: '644',
fa_alpha_content_secondary: '645',
fa_alpha_content_secondary_dark: '646',
fa_alpha_content_tertiary: '647',
fa_alpha_content_tertiary_dark: '648',
fa_alpha_content_fourth: '649',
fa_alpha_content_fourth_dark: '650',
fa_alpha_disabled: '651',
fa_alpha_disabled_dark: '652',
fa_alpha_highlight_bg: '653',
fa_alpha_highlight_bg_dark: '654',
fa_corner_radius_card: '655',
fa_corner_radius_list_card_bg: '656',
fa_corner_radius_default_s: '657',
fa_corner_radius_default_xs: '658',
fa_card_background: '659',
fa_card_background_dark: '660',
fa_card_border: '661',
fa_card_border_dark: '662',
fa_card_icon_mask: '663',
id_text_size_dialog_tittle: '664',
};
module.exports = OHOS_THEME_STYLES;

View File

@ -0,0 +1,86 @@
/*
* 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 os = require("os")
const http = require("http");
const crypto = require('crypto');
const localHost = '127.0.0.1'
const uri = '/api/system/deviceinfo'
const timeout = 300
const IPv4 = 'IPv4'
const SHA256 = 'SHA256'
const hex = 'hex'
function fliterAlias(alias) {
return alias.family === IPv4 && alias.address !== localHost && !alias.internal
}
function getIP() {
let IPAdress = [];
Object.values(os.networkInterfaces()).forEach(
iface => iface.filter(fliterAlias).forEach(
alias => {
ip = alias.address.replace(/\.\d+$/, '.1')
!IPAdress.includes(ip) && IPAdress.push(ip)
}
)
);
return IPAdress;
}
async function getName(ip) {
return await new Promise(resolve => {
let req = http.get(`http://${ip}${uri}`, { timeout: timeout }, resp => {
if (resp.statusCode != 200) {
req.destroy();
resolve(null);
return;
}
resp.setEncoding('utf8');
let ret = "";
resp.on('data', chunk => ret += chunk);
resp.on('end', () => {
try {
const parsedData = JSON.parse(ret)
resolve({ ip, name: parsedData.FriendlyName, udid: crypto.createHash(SHA256).update(parsedData.uuid).digest(hex) });
} catch (error) {
resolve(null);
}
});
});
req.on("error", () => {
req.destroy();
resolve(null);
}).on("timeout", () => {
req.destroy();
resolve(null);
});
});
}
async function main() {
let ipArr = getIP();
let ret = [];
for (let i = 0; i < ipArr.length; i++) {
let route = await getName(ipArr[i]);
route && ret.push(route)
}
console.info("resp : 200");
console.info(JSON.stringify(ret));
}
main();

View File

@ -0,0 +1,57 @@
/*
* 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 path = require("path");
const fs = require("fs");
let aceModuleRoot = process.env.aceModuleRoot;
const buildPath = process.env.aceModuleBuild;
const config = path.join(aceModuleRoot, "../../config.json");
const appJSPath = path.join(aceModuleRoot, "app.js");
let pluginInfo = {};
loadEntryObj();
function loadEntryObj() {
const red = "\u001b[31m";
const reset = "\u001b[39m";
if (!fs.existsSync(config)) {
throw Error(red + "ERROR: missing config" + reset).message;
}
if (!fs.existsSync(appJSPath)) {
throw Error(red + "ERROR: missing app.js" + reset).message;
}
pluginInfo = JSON.parse(fs.readFileSync(config, {
encoding: "utf-8"
}));
if (!(pluginInfo && pluginInfo.app && pluginInfo.app.bundleName && pluginInfo.app.version.name)) {
throw Error(red + "ERROR: mainfest context invalid" + JSON.stringify(pluginInfo)).message;
}
}
module.exports = {
appJSPath,
pluginInfo,
buildPath: buildPath,
projectPath: aceModuleRoot,
manifestFilePath: config,
pkgName: pluginInfo.app.bundleName,
hapName: pluginInfo.app.bundleName + "-" + pluginInfo.app.version.name + "_unsigned",
};

View File

@ -0,0 +1,24 @@
/*
* 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.
*/
module.exports = function (context) {
if (this.query == undefined || this.query.pkgName == undefined) {
throw Error("custom loader haven't recv the pkgName");
}
return context.replace(
/import (\w+) from [\'\"]{1}@system\.(\w+)[\'\"]{1}/g,
`var $1 = requireNative('${this.query.pkgName}','$2')`
);
};

206
ace-loader/router/push.js Normal file
View File

@ -0,0 +1,206 @@
/*
* 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 crypto = require("crypto");
const fs = require("fs");
const path = require("path");
const http = require("http");
const os = require("os");
const { login, GET, POST, decryptStr2Str } = require("./pushHelper");
let localIp = undefined;
let argv = getArgv();
checkArgv();
let pwd = decryptStr2Str(argv.metePath, argv.session);
if (pwd == undefined) {
finish(12, "incorrect password.");
}
function constainsKey(array, key) {
for (let i = 0; i < array.length; i++) {
if (array[i].pkgName === key) {
return true;
}
}
return false;
}
let cnt = 0;
function getErr(data) {
if (cnt == 20) {
POST(`http://${argv.ip}/api/system/user_logout`);
finish(41, "install timeout");
}
cnt++;
GET(`http://${argv.ip}/api/hap/all_infos`).then(
allInfos => {
if (constainsKey(allInfos.installedHap, data.pkgName)) {
POST(`http://${argv.ip}/api/system/user_logout`);
finish(31, "install success.");
}
if (constainsKey(allInfos.installingHap, data.pkgName)) {
return;
}
return POST(`http://${argv.ip}/api/acelite/get_err`, data);
}
).then(
errInfo => {
POST(`http://${argv.ip}/api/system/user_logout`);
if (errInfo.errCode == 404) {
finish(30, "no interface.");
}
finish(errInfo.errCode, "install fail");
}
);
}
login(argv.ip, pwd).then(res => {
if (res == undefined) {
finish(10, "internal error.");
};
if (res.err == 0) {
let port = createListen(argv.file);
if (port == null) {
finish(8, "create the file server failed.");
}
let data = {
pkgName: argv.pkgName,
name: argv.name,
versionName: argv.versionName || "1.0.0",
versionCode: parseInt(argv.versionCode) || 1,
appId: argv.appId || "C" + new Date().getTime(),
downloadUrl: `http://${localIp}:${port}/signed.hap`,
iconUrl: "https://appimg.dbankcdn.com/application/icon144/a02cb676dfdf49ccad87471b421a5276.png",
isDebug: 1,
};
POST(`http://${argv.ip}/api/acelite/hap_delete`, data).then(
() => {
return POST(`http://${argv.ip}/api/acelite/hap_debug`, data);
}
).then(
res => {
if (res.errcode != 0) {
finish(14, "push fail.");
}
setInterval(()=>getErr(data), 3000);
}
);
} else if ((res.err == 4784230 || res.err == 4784231) && res.waitTime) {
finish(13, "too many errors. Please try again later.");
} else {
finish(9, "login failed.");
}
}).catch(err => {
finish(10, "internal error.");
});
if (!argv.file) {
finish(2, "Path is null")
}
function checkArgv() {
if (!argv.ip || !(localIp = getLocalIp(argv.ip))) {
finish(1, "ip error")
}
if (!argv.file || !fs.existsSync(argv.file)) {
finish(2, "file error.")
}
if (!argv.metePath || !fs.statSync(argv.metePath).isDirectory()) {
finish(3, "metePath error.")
}
if (!argv.session) {
finish(4, "session error.")
}
if (!argv.pkgName) {
finish(5, "pkgName error.")
}
if (!argv.name) {
finish(6, "name error.")
}
}
function finish(code, msg) {
process.exit(code)
}
/**
* Listen to external download requirements on random port from 9000 to 9100.
* @param {String} hapPath hap file path.
* @return {Number} service port.
*/
function createListen(hapPath) {
/* Generate a random number 9000~9100. randomBytes() return number is 0~255. */
let port = 9000 + Math.round(new Uint8Array(crypto.randomBytes(1))[0] * 100 / 255);
let server = http.createServer(function (req, res) {
res.writeHead(200, {
'Content-Type': 'application/octet-stream',
'Content-Disposition': 'attachment; filename=' + path.basename(hapPath),
"Content-Length": fs.statSync(hapPath).size
});
fs.createReadStream(hapPath).pipe(res);
server.close();
}).listen(port);
server.on("error", () => {
finish(8, "create the file server failed.");
})
return port;
}
/**
* Get parameter from command.
* @return {Object} Object of parameter
*/
function getArgv() {
let ret = {};
process.argv.splice(2).forEach((value, index, array) => {
if (/^--[a-zA-Z]+/.test(value)) {
if (index < array.length - 1 && /[^-]+/.test(array[index + 1])) {
ret[value.substr(2)] = array[index + 1];
} else {
ret[value.substr(2)] = true;
}
}
});
return ret;
}
function getLocalIp(ip) {
let localIp = undefined;
Object.values(os.networkInterfaces()).forEach(
iface => {
iface.forEach(
alias => {
if (alias.address.replace(/\.\d+$/, '.1') == ip) {
localIp = alias.address;
return;
}
}
);
if (localIp) {
return;
}
}
);
return localIp;
}

View File

@ -0,0 +1,320 @@
/*
* 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.
*/
var http = require("http");
const crypto = require("crypto");
const fs = require("fs");
const path = require("path");
let ip = undefined;
let pwd = undefined;
let csrf = {};
let globalCookie = '';
const defaultHeader = {
'X-Requested-With': 'XMLHttpRequest',
Accept: 'application/json, text/javascript, */*; q=0.01',
'Content-Type': 'application/json; charset=utf-8'
}
module.exports = { decryptStr2Str, login, GET, POST };
function login(ipParam, pwdParam) {
return new Promise(async resolve => {
if (!ipParam || pwdParam == undefined) {
resolve();
}
ip = ipParam;
pwd = pwdParam;
await GET(`http://${ip}/api/system/deviceinfo`);
let count = 0;
let proofData = undefined;
do {
let firstNonce = crypto.createHash('sha256').update(crypto.randomBytes(8)).digest("hex");
let res = await POST(`http://${ip}/api/system/user_login_nonce`, { username: 'admin', firstnonce: firstNonce })
if (res.err != 0) {
continue;
}
proofData = getProofData(res, firstNonce);
} while (!proofData && ++count < 5);
if (proofData == undefined) {
resolve();
return;
}
res = await POST(`http://${ip}/api/system/user_login_proof`, proofData)
resolve(res);
});
};
function getProofData(res, firstNonce) {
if (!res || res.err != 0) {
return undefined;
}
let iter = res.iterations;
let finalNonce = res.servernonce;
let salt = res.salt;
if (!iter || !finalNonce || !salt) {
return undefined;
}
let authMsg = firstNonce + "," + finalNonce + "," + finalNonce;
let saltPwd = crypto.pbkdf2Sync(Buffer.from(stringToByte(pwd)), hexStringToByte(salt), iter, 32, "sha256");
let clientKey = crypto.createHmac("sha256", "Client Key").update(saltPwd).digest();
let storekey = crypto.createHash("sha256").update(clientKey).digest();
let clientsignature = crypto.createHmac("sha256", authMsg).update(storekey).digest();
let len = clientKey.byteLength;
let clientproof = Buffer.alloc(len);
for (let i = 0; i < len; i++) {
clientproof.writeUInt8(clientKey.readUInt8(i) ^ clientsignature.readUInt8(i), i);
}
clientproof = clientproof.toString("hex")
return {
clientproof: clientproof,
finalnonce: finalNonce
}
}
function refreshSession(header, ret) {
let cookie = header && header["set-cookie"] && header["set-cookie"][0];
cookie && (globalCookie = (cookie.substring(0, cookie.indexOf(";"))));
ret.csrf_param && (csrf.csrf_param = ret.csrf_param);
ret.csrf_token && (csrf.csrf_token = ret.csrf_token);
}
function POST(url, data) {
return new Promise(resolve => {
let req = http.request(url, {
method: "post",
timeout: 300,
headers: {
...defaultHeader,
Cookie: globalCookie
}
}, resp => {
if (resp.statusCode != 200) {
resolve({errCode: 404});
return;
}
let ret = "";
resp.on('data', chunk => ret += chunk);
resp.on('end', () => {
try{
ret = JSON.parse(ret);
}catch(err) {
resolve(null);
return;
}
refreshSession(resp.headers, ret);
resolve(ret);
});
});
req.write(JSON.stringify({
data,
csrf,
}));
req.end();
req.on("error", () => {
req.destroy();
resolve(null);
}).on("timeout", () => {
req.destroy();
resolve(null);
});
});
}
function GET(url) {
return new Promise(resolve => {
let req = http.get(url, {
timeout: 300, headers: {
...defaultHeader,
Cookie: globalCookie
}
}, resp => {
let ret = "";
resp.on('data', chunk => ret += chunk);
resp.on('end', () => {
ret = JSON.parse(ret);
refreshSession(resp.headers, ret);
resolve(ret);
});
});
req.on("error", () => {
req.destroy();
resolve(null);
}).on("timeout", () => {
req.destroy();
resolve(null);
});
});
}
/**
* fd Root key component directory.
* ac Directory for storing the salt used to generate the final root key in iteration mode.
* ce work key material directory
*/
const comDirs = ["fd", "ac", "ce"];
/**
* Root path of key materials. All materials are stored in this path.
*/
const meteDir = "material";
/**
* A part of the root key component. It must work with other components to form a root key.
* For details, see the Key Management Security Specifications V1.3.
*/
let COMPONENT = Array.from(new Int8Array([
0x31, 0xf3, 0x09, 0x73, 0xd6, 0xaf, 0x5b, 0xb8,
0xd3, 0xbe, 0xb1, 0x58, 0x65, 0x83, 0xc0, 0x77
]));
function decryptStr2Str(rootPath, input) {
let metePath = path.resolve(rootPath, meteDir);
let components = readComponents(metePath);
let saltDir = path.resolve(metePath, comDirs[1]);
let salt = readDirBytes(saltDir);
let rootKey = deriveRootKey(components, salt);
let workMeteDir = path.resolve(metePath, comDirs[2]);
let workMete = readDirBytes(workMeteDir);
let key = decrypt(rootKey, workMete);
let bts = hexStringToByte(input);
let output = decrypt(key, bts);
return (Buffer.from(output).toString("utf-8"));
}
function hexStringToByte(str) {
if (!str) {
return new Uint8Array();
}
var a = [];
for (var i = 0, len = str.length; i < len; i += 2) {
a.push(parseInt(str.substr(i, 2), 16));
}
return new Int8Array(a);
}
function decrypt(rootKey, workMete) {
if (workMete.length < 32) {
return null;
}
let bodyLength = ((workMete[0] & 0xFF) << 24) | ((workMete[1] & 0xFF) << 16) | ((workMete[2] & 0xFF) <<
8) | ((workMete[3] & 0xFF));
let iv = workMete.slice(4, workMete.length - bodyLength);
let cipher = crypto.createCipheriv("aes-128-gcm", new Int8Array(rootKey), new Int8Array(iv), {
authTagLength: 16
});
let encrypted = cipher.update(new Int8Array(workMete.slice(workMete.length - bodyLength)))
cipher.final();
return new Int8Array(encrypted).slice(0, bodyLength - 16);
}
function deriveRootKey(components, salt) {
let fullComponents = components;
fullComponents.push(COMPONENT);
let finalComponent = sortFullComponent(fullComponents);
let key = Array.from(new Int8Array(crypto.pbkdf2Sync(finalComponent, new Int8Array(salt), 10000, 16, "sha256")));
return key;
}
function sortFullComponent(fullComponents) {
let ret = fullComponents[0];
for (let i = 1; i < fullComponents.length; i++) {
ret = xor(ret, fullComponents[i]);
}
return new Int8Array(stringToByte(Buffer.from(ret).toString("utf-8")));
}
function stringToByte(str) {
var bytes = new Array();
var len, c;
len = str.length;
for (var i = 0; i < len; i++) {
c = str.charCodeAt(i);
if (c >= 0x010000 && c <= 0x10FFFF) {
bytes.push(((c >> 18) & 0x07) | 0xF0);
bytes.push(((c >> 12) & 0x3F) | 0x80);
bytes.push(((c >> 6) & 0x3F) | 0x80);
bytes.push((c & 0x3F) | 0x80);
} else if (c >= 0x000800 && c <= 0x00FFFF) {
bytes.push(((c >> 12) & 0x0F) | 0xE0);
bytes.push(((c >> 6) & 0x3F) | 0x80);
bytes.push((c & 0x3F) | 0x80);
} else if (c >= 0x000080 && c <= 0x0007FF) {
bytes.push(((c >> 6) & 0x1F) | 0xC0);
bytes.push((c & 0x3F) | 0x80);
} else {
bytes.push(c & 0xFF);
}
}
return bytes;
}
function xor(arr1, arr2) {
if (!arr1 || !arr2 || arr1.length != arr2.length) {
return null;
}
let ret = [];
for (let i = 0; i < arr1.length; i++) {
ret.push(arr1[i] ^ arr2[i]);
}
return ret;
}
function readDirBytes(dir) {
let files = fs.readdirSync(dir);
if (files.length != 1) {
return null;
}
return Array.from(new Int8Array(fs.readFileSync(path.resolve(dir, files[0]))));
}
function readComponents(dir) {
let files = fs.readdirSync(path.resolve(dir, comDirs[0]));
if (files == null || files.length != 3) {
return null;
}
let ret = [];
for (let i = 0; i < files.length; i++) {
ret.push(readDirBytes(path.resolve(dir, comDirs[0], files[i])));
}
return ret;
}

View File

@ -0,0 +1,5 @@
{
"message":{
"hello": "hello world"
}
}

View File

@ -0,0 +1,5 @@
{
"message": {
"hello": "你好世界"
}
}

View File

@ -0,0 +1,15 @@
{
"appID": "com.example.ace.helloworld",
"appName": "HelloAce",
"versionName": "1.0.0",
"versionCode": 1,
"minPlatformVersion": "1.0.1",
"pages": [
"pages/index/index"
],
"window": {
"designWidth": 720,
"autoDesignWidth": false
},
"type": "form"
}

View File

@ -0,0 +1,23 @@
.container {
justify-content: center;
align-items: center;
}
.title {
font-size: 50px;
}
.button-div {
padding-top: 50px;
align-items: center;
justify-content: center;
}
.text-div {
align-items: center;
justify-content: center;
}
.button {
font-size: 30px;
}

View File

@ -0,0 +1,8 @@
<div class="container">
<div class="text-div">
<text class="title">This is the index page.</text>
</div>
<div class="button-div">
<button value="Go to the second page" class="button" onclick="router"/>
</div>
</div>

View File

@ -0,0 +1,19 @@
{
"data": {
"show": true,
"display": false,
"card_name": "weather",
"temperature": "35°",
"city": "SH",
"date": "2020.09.04",
"weather_info": "cloud",
"image_src":"../../common/clouds.png"
},
"actions": {
"router": {
"action": "router",
"bundleName": "com.example.helloworld",
"bundleAbility": "com.example.helloworld.MainAbility"
}
}
}

View File

@ -0,0 +1,8 @@
export default {
onCreate() {
console.info("AceApplication onCreate");
},
onDestroy() {
console.info("AceApplication onDestroy");
}
};

View File

@ -0,0 +1,11 @@
{
"appID": "com.example.ace.helloworld",
"appName": "HelloAce",
"versionName": "1.0.0",
"versionCode": 1,
"minPlatformVersion": "zsdk 1.0.0",
"pages": [
"pages/index/index",
"pages/detail/detail"
]
}

View File

@ -0,0 +1,11 @@
.commonStyle {
left: 95px;
top: 95px;
width: 200px;
height: 200px;
margin: 10px;
padding: 30px;
border-width: 1px;
border-radius: 10px;
background-color: #ff0000;
}

View File

@ -0,0 +1,11 @@
<stack
style="width: 444px;height: 444px;margin: 20px;border-width: 5px;border-color: #00ff00;border-radius: 10px;opacity: 0.5"
>
<text style="left:140px;top:50px;width:300px;height:40px">common style</text>
<div class="commonStyle"></div>
<image
src="common/nextRow.bin"
style="left:390px;top:227px;width:30px;height:42px"
onclick="nextPage"
/>
</stack>

View File

@ -0,0 +1,19 @@
var router = require('@system.router')
export default {
data: {},
nextPage () {
router.replace({ uri: 'pages/chart/index' })
},
onInit () {
console.log('onInit called...')
},
onReady () {
console.log('onReady called...')
},
onShow () {
console.log('onShow called...')
},
onDestroy () {
console.log('onDestroy called...')
}
}

View File

@ -0,0 +1,23 @@
.btn .table {
color: #ff0000;
}
.btn {
height: 33px;
}
.table {
width: 444px;
}
.container {
justify-content: center;
align-items: center;
left: 0px;
top: 0px;
width: 454px;
height: 454px;
}
.title {
font-size: 30px;
text-align: center;
width: 200px;
height: 100px;
}

View File

@ -0,0 +1,5 @@
<div class="container">
<text class="title">
Hello {{title}}
</text>
</div>

View File

@ -0,0 +1,5 @@
export default {
data: {
title: 'World'
}
}

View File

@ -0,0 +1,8 @@
export default {
onCreate() {
console.info('AceApplication onCreate');
},
onDestroy() {
console.info('AceApplication onDestroy');
}
}

View File

@ -0,0 +1,5 @@
{
"message":{
"hello": "hello world"
}
}

View File

@ -0,0 +1,5 @@
{
"message": {
"hello": "你好世界"
}
}

View File

@ -0,0 +1,15 @@
{
"appID": "com.example.ace.helloworld",
"appName": "HelloAce",
"versionName": "1.0.0",
"versionCode": 1,
"minPlatformVersion": "1.0.1",
"pages": [
"pages/index/index",
"pages/detail/detail"
],
"window": {
"designWidth": 750,
"autoDesignWidth": false
}
}

View File

@ -0,0 +1,23 @@
.container {
justify-content: center;
align-items: center;
}
.title {
font-size: 50px;
}
.button-div {
padding-top: 50px;
align-items: center;
justify-content: center;
}
.text-div {
align-items: center;
justify-content: center;
}
.button {
font-size: 30px;
}

View File

@ -0,0 +1,8 @@
<div class="container">
<div class="text-div">
<text class="title">This is the detail page.</text>
</div>
<div class="button-div">
<input type="button" value="Go back" class="button" onclick="launch"/>
</div>
</div>

View File

@ -0,0 +1,11 @@
import router from '@system.router'
export default {
data: {
},
launch: function() {
router.push ({
uri:'pages/index/index',
})
}
}

View File

@ -0,0 +1,23 @@
.container {
justify-content: center;
align-items: center;
}
.title {
font-size: 50px;
}
.button-div {
padding-top: 50px;
align-items: center;
justify-content: center;
}
.text-div {
align-items: center;
justify-content: center;
}
.button {
font-size: 30px;
}

View File

@ -0,0 +1,8 @@
<div class="container">
<div class="text-div">
<text class="title">This is the index page.</text>
</div>
<div class="button-div">
<input type="button" value="Go to the second page" class="button" onclick="launch"/>
</div>
</div>

View File

@ -0,0 +1,11 @@
import router from '@system.router';
export default {
data: {
},
launch: function() {
router.push ({
uri:'pages/detail/detail',
})
}
}

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2020 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.
*/
import path from 'path'
import fs from 'fs'
import {
getRequireString,
jsonLoaders,
logWarn
}
from './util'
import { parseFragment } from './parser'
function loader(source) {
this.cacheable && this.cacheable()
const options = {
lang: {
sass:['sass-loader'],
scss:['sass-loader'],
less:['less-loader']
}
}
const customLang = options.lang || {}
const resourcePath = this.resourcePath
const fileName = resourcePath.replace(path.extname(resourcePath).toString(), '')
let output = ''
output = getRequireString(this, jsonLoaders('template'), resourcePath)
const styleInfo = findStyleFile(fileName)
if (styleInfo.extStyle == true) {
output += getRequireString(this, jsonLoaders('style', customLang[styleInfo.type]), styleInfo.styleFileName)
}
output = addJson(this, output, fileName, '')
const frag = parseFragment(source)
const nameSet = new Set()
if (frag.element) {
frag.element.forEach(item => {
let customElementName
if (!item.src) {
logWarn(this, [{
reason: `ERROR: The attribute 'src' must be set in the custom element.`,
line: item.node.__location.line,
column: item.node.__location.col
}])
return
}
if (!item.src.match(/\.hml$/)) {
item.src = item.src.concat('.hml')
}
const compResourcepath = path.join(resourcePath, '..', item.src)
if (!fs.existsSync(compResourcepath)) {
logWarn(this, [{
reason: `ERROR: The custom element '${compResourcepath}' can not be found.`,
line: item.node.__location.line,
column: item.node.__location.col
}])
return
}
if (!item.name) {
customElementName = path.parse(item.src).name.toLowerCase()
} else {
customElementName = item.name.toLowerCase()
}
if (nameSet.has(customElementName)) {
logWarn(this, [{
reason: `ERROR: The custom elements cannot have the same attribute 'name' or file name (case insensitive).`,
line: item.node.__location.line,
column: item.node.__location.col
}])
return
} else {
nameSet.add(customElementName)
}
const compFileName = compResourcepath.replace(path.extname(compResourcepath).toString(), '')
output += getRequireString(this, jsonLoaders('template'),
compResourcepath + `?${customElementName}#${fileName}`)
const compStyleInfo = findStyleFile(compFileName)
if (compStyleInfo.extStyle == true) {
output += getRequireString(this, jsonLoaders('style', customLang[compStyleInfo.type]),
compStyleInfo.styleFileName + `?${customElementName}#${fileName}`)
}
output = addJson(this, output, compFileName, `?${customElementName}#${fileName}`)
})
}
return output
}
function findStyleFile (fileName) {
let extStyle = false
let styleFileName = fileName + '.css'
let type = 'css'
if (fs.existsSync(styleFileName)) {
extStyle = true
type = 'css'
} else {
styleFileName = fileName + '.less'
if (fs.existsSync(styleFileName)) {
extStyle = true
type = 'less'
} else {
styleFileName = fileName + '.sass'
if (fs.existsSync(styleFileName)) {
extStyle = true
type = 'sass'
} else {
styleFileName = fileName + '.scss'
if (fs.existsSync(styleFileName)) {
extStyle = true
type = 'sass'
} else {
extStyle = false
}
}
}
}
return {extStyle: extStyle, styleFileName: styleFileName, type: type}
}
function addJson(_this, output, fileName, query) {
if (fs.existsSync(fileName + '.json') && !fs.existsSync(fileName + '.js')) {
output += getRequireString(_this, jsonLoaders('json'), fileName + '.json' + query)
} else if (fs.existsSync(fileName + '.js') && !fs.existsSync(fileName + '.json')) {
logWarn(_this, [{
reason: `WARNING: The JS file '${fileName}.js' will be discarded in future version, ` +
`use the JSON file '${fileName}.json' instead.`,
}])
output += getRequireString(_this, jsonLoaders('json'), fileName + '.js' + query)
} else if (fs.existsSync(fileName + '.json') && fs.existsSync(fileName + '.js')) {
logWarn(_this, [{
reason: `WARNING: '${fileName}' cannot have the same name files '.json' and '.js', otherwise '.json' in default.`,
}])
output += getRequireString(_this, jsonLoaders('json'), fileName + '.json' + query)
}
return output
}
module.exports = loader

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2020 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 fs = require('fs')
const path = require('path')
let output = ''
const initIndexJSONObject = { "template": {}, "styles": {}, "actions": {},"data":{} }
function compileJson(compiler, type, filePath, content, contentType, elementType) {
compiler.hooks.done.tap(type + contentType, () => {
if (type === 'init') {
writeFileSync(filePath, initIndexJSONObject)
} else {
writeFileSync(filePath, content, contentType, elementType)
}
})
}
function writeFileSync(filePath, content, contentType, elementType) {
if (!fs.existsSync(filePath)) {
fs.writeFileSync(filePath, stringify(content))
} else {
const fileContent = fs.readFileSync(filePath, {encoding:'utf-8'})
try {
const jsonContent = JSON.parse(fileContent)
if (contentType && !elementType) {
jsonContent[contentType] = content ? content : {}
fs.writeFileSync(filePath, stringify(jsonContent))
} else if (contentType && elementType) {
if (!jsonContent[contentType]) {
jsonContent[contentType] = {}
}
jsonContent[contentType][elementType] = content ? content : {}
fs.writeFileSync(filePath, stringify(jsonContent))
}
} catch (e) {
fs.writeFileSync(filePath, stringify(initIndexJSONObject))
writeFileSync(filePath, content, contentType)
}
}
}
function stringify (jsonObect) {
return JSON.stringify(jsonObect, null, 2)
}
class AfterEmitPlugin {
constructor(output_) {
output = output_
}
apply(compiler) {
compiler.hooks.afterEmit.tap('delete', (compilation) => {
const assets = compilation.assets
const keys = Object.keys(assets)
keys.forEach(key => {
if (fs.existsSync(path.resolve(output, key))) {
if (key.indexOf('i18n') !== 0) {
fs.unlinkSync(path.resolve(output, key))
}
}
})
})
}
}
module.exports = {
compileJson: compileJson,
AfterEmitPlugin: AfterEmitPlugin
}

View File

@ -0,0 +1,159 @@
/*
* Copyright (c) 2020 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 Stats = require('webpack/lib/Stats');
const fs = require('fs');
const path = require('path');
const { DEVICE_LEVEL } = require('./lite/lite-enum');
const REG = /\([^\)]+\)/;
let mStats;
let mErrorCount = 0;
let mWarningCount = 0;
let isShowError = true;
let isShowWarning = true;
let isShowNote = true;
let warningCount = 0;
let noteCount = 0;
let errorCount = 0;
class ResultStates {
constructor(options) {
this.options = options;
}
apply(compiler) {
const buildPath = this.options.build;
compiler.hooks.done.tap('Result States', (stats) => {
mStats = stats;
warningCount = 0;
noteCount = 0;
errorCount = 0;
if (mStats.compilation.errors) {
mErrorCount = mStats.compilation.errors.length;
}
if (mStats.compilation.warnings) {
mWarningCount = mStats.compilation.warnings.length;
}
if (process.env.error === 'false') {
isShowError = false;
}
if (process.env.warning === 'false') {
isShowWarning = false;
}
if (process.env.note === 'false') {
isShowNote = false;
}
printResult(buildPath);
});
}
}
const red = '\u001b[31m';
const yellow = '\u001b[33m';
const blue = '\u001b[34m';
const reset = '\u001b[39m';
const writeError = (buildPath, content) => {
fs.writeFile(path.resolve(buildPath, 'compile_error.log'), content, (err) => {
if (err) {
return console.error(err);
}
});
};
function printResult(buildPath) {
printWarning();
printError(buildPath);
if (errorCount + warningCount + noteCount > 0) {
let result;
const resultInfo = {};
if (errorCount > 0) {
resultInfo.ERROR = errorCount;
result = 'FAIL ';
} else {
result = 'SUCCESS ';
}
if (warningCount > 0) {
resultInfo.WARN = warningCount;
}
if (noteCount > 0) {
resultInfo.NOTE = noteCount;
}
console.log(blue, 'COMPILE RESULT:' + result + JSON.stringify(resultInfo), reset);
} else {
console.log(blue, 'COMPILE RESULT:SUCCESS ', reset);
}
}
function printWarning() {
if (mWarningCount > 0) {
const warnings = mStats.compilation.warnings;
const length = warnings.length;
for (let index = 0; index < length; index++) {
let message = warnings[index].message
if (message.match(/noteStart(([\s\S])*)noteEnd/) !== null) {
noteCount++;
if (isShowNote) {
console.info(' ' + message.match(/noteStart(([\s\S])*)noteEnd/)[1].trim(), reset, '\n')
}
} else if (message.match(/warnStart(([\s\S])*)warnEnd/) !== null) {
warningCount++;
if (isShowWarning) {
console.warn(yellow, message.match(/warnStart(([\s\S])*)warnEnd/)[1].trim(), reset, '\n')
}
}
}
if (mWarningCount > length) {
warningCount = warningCount + mWarningCount - length;
}
}
}
function printError(buildPath) {
if (mErrorCount > 0) {
const errors = mStats.compilation.errors;
const length = errors.length;
if (isShowError) {
let errorContent = '';
for (let index = 0; index < length; index++) {
if (errors[index]) {
let message = errors[index].message
if (message) {
if (message.match(/errorStart(([\s\S])*)errorEnd/) !== null) {
const errorMessage = message.match(/errorStart(([\s\S])*)errorEnd/)[1];
console.error(red, errorMessage.trim(), reset, '\n');
} else {
const messageArrary = message.split('\n')
let logContent = ''
messageArrary.forEach(element => {
if (!(/^at/.test(element.trim()))) {
logContent = logContent + element + '\n'
}
});
console.error(red, logContent, reset, '\n');
}
errorCount ++;
errorContent += message
}
}
}
writeError(buildPath, errorContent);
}
}
}
module.exports = ResultStates;

38
ace-loader/src/extgen.js Normal file
View File

@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import loaderUtils from 'loader-utils'
const codegen = require("./codegen/index.js");
module.exports = function (source, map) {
this.cacheable && this.cacheable()
const callback = this.async()
const hmlCss = codegen.genHmlAndCss(source);
const loaderQuery = loaderUtils.getOptions(this) || {}
if (hmlCss.errorType && hmlCss.errorType !== '' && loaderQuery.type === 'template') {
callback(hmlCss.errorType + ' : ' + hmlCss.errorMessage, '')
} else {
if(loaderQuery.type === 'template') {
callback(null, hmlCss.hmlCss.hml, map)
} else {
callback(null, hmlCss.hmlCss.css, map)
}
}
}

View File

@ -0,0 +1,136 @@
/*
* 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 fs = require('fs')
const path = require('path')
const process = require('child_process')
const js2abc = path.join(__dirname, '..', 'bin', 'panda', 'build', 'src', 'index.js')
const js2abc_win = path.join(__dirname, '..', 'bin', 'panda', 'build-win', 'src', 'index.js')
const js2abc_mac = path.join(__dirname, '..', 'bin', 'panda', 'build-mac', 'src', 'index.js')
const libraryPath = path.join(__dirname, '..', 'bin', 'panda', 'build', 'panda', 'lib')
const libraryJsonPath = path.join(__dirname, '..', 'bin', 'panda', 'build','lib')
const forward = '(global.___mainEntry___ = function (globalObjects) {' + '\n' +
' var define = globalObjects.define;' + '\n' +
' var require = globalObjects.require;' + '\n' +
' var bootstrap = globalObjects.bootstrap;' + '\n' +
' var register = globalObjects.register;' + '\n' +
' var render = globalObjects.render;' + '\n' +
' var $app_define$ = globalObjects.$app_define$;' + '\n' +
' var $app_bootstrap$ = globalObjects.$app_bootstrap$;' + '\n' +
' var $app_require$ = globalObjects.$app_require$;' + '\n' +
' var history = globalObjects.history;' + '\n' +
' var Image = globalObjects.Image;' + '\n' +
' var OffscreenCanvas = globalObjects.OffscreenCanvas;' + '\n' +
' (function(global) {' + '\n' +
' "use strict";' + '\n'
const last = '\n' + '})(this.__appProto__);' + '\n' + '})'
const firstFileEXT = '_.js'
let output
let webpackPath
let isWin = false
let isMac = false
let isDebug = false
class GenAbcPlugin {
constructor(output_, webpackPath_, isDebug_) {
output = output_
webpackPath = webpackPath_
isDebug = isDebug_
}
apply(compiler) {
if (fs.existsSync(path.resolve(webpackPath, 'panda/build-win'))) {
isWin = true
} else {
if (fs.existsSync(path.resolve(webpackPath, 'panda/build-mac'))) {
isMac = true
} else {
if (!fs.existsSync(path.resolve(webpackPath, 'panda/build'))) {
console.error('\u001b[31m', `find build fail`, '\u001b[39m')
return
}
}
}
compiler.hooks.emit.tap('GenAbcPlugin', (compilation) => {
const assets = compilation.assets
const keys = Object.keys(assets)
keys.forEach(key => {
// choice *.js
if (output && webpackPath && path.extname(key) === '.js') {
const newContent = forward + assets[key].source() + last
const keyPath = key.replace(/\.js$/, firstFileEXT)
writeFileSync(newContent, path.resolve(output, keyPath), key)
}
})
})
}
}
function writeFileSync(inputString, output, jsBundleFile) {
const parent = path.join(output, '..')
if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) {
mkDir(parent)
}
fs.writeFileSync(output, inputString)
if (fs.existsSync(output)){
qjscFirst(output)
} else {
console.error('\u001b[31m', `Failed to convert file ${jsBundleFile} to bin. ${output} is lost`, '\u001b[39m')
}
}
function mkDir(path_) {
const parent = path.join(path_, '..')
if (!(fs.existsSync(parent) && !fs.statSync(parent).isFile())) {
mkDir(parent)
}
fs.mkdirSync(path_)
}
function qjscFirst(inputPath) {
let param = '-r'
if (isDebug) {
param += ' --debug'
}
let cmd
if (isWin) {
cmd = `node --expose-gc "${js2abc_win}" "${inputPath}" ${param}`
} else if (isMac){
cmd = `node --expose-gc "${js2abc_mac}" "${inputPath}" ${param}`
} else {
cmd = `export LD_LIBRARY_PATH="${libraryPath}":"${libraryJsonPath}":$LD_LIBRARY_PATH;node --expose-gc "${js2abc}" "${inputPath}" ${param}`
}
try {
process.execSync(cmd)
console.info(cmd)
} catch (e) {
console.error('\u001b[31m', `Failed to convert file ${inputPath} to abc`, '\u001b[39m')
}
if (fs.existsSync(inputPath)) {
fs.unlinkSync(inputPath)
} else {
console.error('\u001b[31m', `Failed to convert file ${inputPath} to abc. ${inputPath} is lost`, '\u001b[39m')
}
let abcFile = inputPath.replace(/\.js$/, '.abc');
if (fs.existsSync(abcFile)) {
let abcFileNew = abcFile.replace(/\_.abc$/, '.abc');
fs.renameSync(abcFile, abcFileNew)
} else {
console.error('\u001b[31m', `${abcFile} is lost`, '\u001b[39m')
}
}
module.exports = GenAbcPlugin

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2020 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 fs = require('fs')
const path = require('path')
const process = require('child_process')
const qjsc = path.join(__dirname, '..', 'bin', 'qjsc')
const forward = '(global.___mainEntry___ = function (globalObjects) {' + '\n' +
' const define = globalObjects.define;' + '\n' +
' const require = globalObjects.require;' + '\n' +
' const bootstrap = globalObjects.bootstrap;' + '\n' +
' const register = globalObjects.register;' + '\n' +
' const render = globalObjects.render;' + '\n' +
' const $app_define$ = globalObjects.$app_define$;' + '\n' +
' const $app_bootstrap$ = globalObjects.$app_bootstrap$;' + '\n' +
' const $app_require$ = globalObjects.$app_require$;' + '\n' +
' const history = globalObjects.history;' + '\n' +
' const Image = globalObjects.Image;' + '\n' +
' const OffscreenCanvas = globalObjects.OffscreenCanvas;' + '\n' +
' (function(global) {' + '\n' +
' "use strict";' + '\n'
const last = '\n' + '})(this.__appProto__);' + '\n' + '})'
const firstFileEXT = '.jtc'
const sencondFileEXT = '.c'
const lastFileEXT = '.bin'
let output
let webpackPath
class GenBinPlugin {
constructor(output_, webpackPath_) {
output = output_
webpackPath = webpackPath_
}
apply(compiler) {
if (!fs.existsSync(path.resolve(webpackPath, 'qjsc.exe')) && !fs.existsSync(path.resolve(webpackPath, 'qjsc'))) {
return
}
compiler.hooks.emit.tap('GenBinPlugin', (compilation) => {
const assets = compilation.assets
const keys = Object.keys(assets)
keys.forEach(key => {
// choice *.js
if (output && webpackPath && path.extname(key) === '.js') {
const newContent = forward + assets[key].source() + last
const keyPath = key.replace(/\.js$/, firstFileEXT)
writeFileSync(newContent, path.resolve(output, keyPath), key)
}
})
})
}
}
function writeFileSync(inputString, output, jsBundleFile) {
const parent = path.join(output, '..')
if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) {
mkDir(parent)
}
fs.writeFileSync(output, inputString)
if (fs.existsSync(output)){
qjscFirst(output, output.replace(/\.jtc$/, sencondFileEXT))
} else {
console.error('\u001b[31m', `Failed to convert file ${jsBundleFile} to bin. ${output} is lost`, '\u001b[39m')
}
}
function mkDir(path_) {
const parent = path.join(path_, '..')
if (!(fs.existsSync(parent) && !fs.statSync(parent).isFile())) {
mkDir(parent)
}
fs.mkdirSync(path_)
}
function qjscFirst(inputPath, outputPath) {
const cmd = `"${qjsc}" -o "${outputPath}" -N buf -c "${inputPath}"`
try {
process.execSync(cmd)
} catch (e) {
console.error('\u001b[31m', `Failed to convert file ${inputPath} to bin`, '\u001b[39m')
}
if (fs.existsSync(inputPath)) {
fs.unlinkSync(inputPath)
qjscSecond(outputPath)
} else {
console.error('\u001b[31m', `Failed to convert file ${inputPath} to bin. ${inputPath} is lost`, '\u001b[39m')
}
}
function qjscSecond(filePath) {
let data = fs.readFileSync(filePath, 'utf8')
data = data.substr(data.indexOf('{') + 1, data.indexOf('}') - data.indexOf('{') - 1).trim()
const lastFilePath = filePath.replace(/\.c$/, lastFileEXT)
const parent = path.join(lastFilePath, '..')
if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) {
mkDir(parent)
}
fs.writeFileSync(lastFilePath, toBuffer(data))
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath)
} else {
console.error('\u001b[31m', `Failed to clean file ${filePath}.`, '\u001b[39m')
}
}
function toBuffer(str) {
const bytes = str.split(',')
const b = Buffer.alloc(bytes.length)
for (let i = 0; i < bytes.length; i++) {
b[i] = bytes[i]
}
return b
}
module.exports = GenBinPlugin

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2020 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 path = require('path');
const fs = require('fs');
const os = require('os');
const isType = require('./lite-utils');
/**
* Check if the custom file exists.If it does not exist, follow the normal process.
* If it exists, get the file content.
*/
function checkFilePath() {
const rulePath = path.resolve(os.userInfo().homedir, '.literc.js');
if (fs.existsSync(rulePath)) {
process.env.RULE_PATH = rulePath;
const customTag = require(rulePath);
checkContent(customTag);
}
}
/**
* Check if the object thrown by the file is correct.
* @param {Object} customTag User defined custom file content.
*/
function checkContent(customTag) {
throwError(
!isType.isObject(customTag),
`The configuration in the '.literc.js' file is incorrect.(it should be an object.)`,
);
throwError(
isType.isUndefined(customTag.rules),
`You must write the 'rules' attribute in '.literc.js' file`,
);
throwError(
!isType.isObject(customTag.rules),
`The value of 'rules' in '.literc.js' file is incorrect.(it should be an object)`,
);
if (customTag.extends == 'recommended') {
validatorCustomTag(customTag.rules);
}
}
/**
* Check whether the user-defined rules are correct.
* @param {Object} rules User defined custom file content.
*/
function validatorCustomTag(rules) {
const keys = Object.keys(rules);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = rules[key];
throwError(
!isType.isObject(value),
`The value of '${key}' is incorrect, it should be an object.`,
);
const childs = Object.keys(value);
for (let j = 0; j < childs.length; j++) {
const child = childs[j];
throwError(
child != 'attrs',
`'${key}' object can only contain 'attrs' attributes`,
);
}
}
}
/**
* Tool method, if the condition is true, throw an exception.
* @param {Boolean} condition Analyzing conditions.
* @param {String} reason Output wrong information.
*/
function throwError(condition, reason) {
if (condition) {
throw Error(`\u001b[31mError: ${reason} \u001b[39m`).message;
}
}
exports.checkFilePath = checkFilePath;

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2020 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 SPECIAL_STYLE = {
OPACITY: 'opacity',
BORDEROPACITY: 'borderOpacity',
ANIMATION_DELAY: 'animationDelay',
ANIMATION_DURATION: 'animationDuration',
ANIMATION_ITERATION_COUNT: 'animationIterationCount',
BACKGROUND_IMAGE: 'backgroundImage',
BACKGROUND_IMAGE_ACTIVE: 'backgroundImage:active',
BACKGROUND_IMAGE_CHECKED: 'backgroundImage:checked',
};
const DEVICE_LEVEL = {
RICH: 'rich',
LITE: 'lite',
CARD: 'card',
};
const DEVICE_TYPE = {
LITEWEARABLE: 'liteWearable',
SMARTVISION: 'smartVision',
};
const PLATFORM = {
VERSION3: 'Version3',
VERSION4: 'Version4',
VERSION5: 'Version5',
VERSION6: 'Version6',
};
const REGEXP_NUMBER_PX = /^[-+]?[0-9]*\.?[0-9]+(px|cm|em|deg|rad)?$/;
const REGEXP_COLOR = /^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/;
const REGEXP_UNIT = /px|cm|em|deg|rad/;
const REGEXP_PNG = /(\.png|\.jpg|\.bmp|\.jpeg|\.BMP|\.JPG|\.PNG|\.JPEG)$/;
const REGXP_QUOTES = /"|'/g;
const REGXP_LANGUAGE = /\$t/;
const REGXP_LANGUAGE_KEY = /_vm\.\$t\([^()]+?\)/g;
const REGXP_FUNC_RETURN = /return(.*)}/g;
exports.SPECIAL_STYLE = SPECIAL_STYLE;
exports.REGEXP_NUMBER_PX = REGEXP_NUMBER_PX;
exports.REGEXP_COLOR = REGEXP_COLOR;
exports.REGEXP_UNIT = REGEXP_UNIT;
exports.DEVICE_LEVEL = DEVICE_LEVEL;
exports.REGEXP_PNG = REGEXP_PNG;
exports.REGXP_QUOTES = REGXP_QUOTES;
exports.DEVICE_TYPE = DEVICE_TYPE;
exports.REGXP_LANGUAGE = REGXP_LANGUAGE;
exports.REGXP_LANGUAGE_KEY = REGXP_LANGUAGE_KEY;
exports.REGXP_FUNC_RETURN = REGXP_FUNC_RETURN;
exports.PLATFORM = PLATFORM;

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2020 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 _path = require('path');
const fs = require('fs');
const registerRequireContextHook = require('babel-plugin-require-context-hook/register');
const { REGEXP_PNG } = require('./lite-enum');
const iconPath = process.env.iconPath || '';
const img2bin = require('./lite-image2bin');
registerRequireContextHook();
/**
* Convert picture to bin format.
*/
class ImageCoverterPlugin {
/**
* constructor of the ImageCoverterPlugin class.
* @param {String} options The object of build folder.
*/
constructor(options) {
this.options = options;
}
/**
* Find all image paths in pngjpgbmpjpeg format in the directory.
* @param {String} buildPath The path of build folder.
* @return {Array} Image path array.
*/
getDir(buildPath) {
const pngPath = global.__requireContext('', buildPath, true, REGEXP_PNG);
const pathArray = pngPath.keys().map((element) => {
return _path.join(buildPath, element);
});
return pathArray;
}
/**
* Convert image format asynchronously, return code 0 successfully, otherwise return 1.
* @param {Object} compiler API specification, all configuration information of Webpack environment.
*/
apply(compiler) {
const buildPath = this.options.build;
const getDir = this.getDir;
compiler.hooks.done.tap('image coverter', function(compilation, callback) {
const pathArray = getDir(buildPath);
const writeResult = (content) => {
fs.writeFile(_path.resolve(buildPath, 'image_convert_result.txt'), content, (err) => {
if (err) {
return console.error(err);
}
});
};
const totalImageCount = pathArray.length;
if (totalImageCount > 0) {
const promiseArray = pathArray.map((path) => {
return img2bin(path);
});
Promise.all(promiseArray).then(() => {
writeResult('{exitCode:0}');
}).catch(() => {
writeResult('{exitCode:1}');
});
} else {
writeResult('{exitCode:0}');
}
if (iconPath !== '') {
const iconArray = getDir(iconPath);
iconArray.forEach((path) => {
img2bin(path);
});
}
});
}
}
module.exports = ImageCoverterPlugin;

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2020 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 Jimp = require('jimp');
const fs = require('fs');
const _path = require('path');
/**
* Find all image paths in pngjpgbmpjpeg format in the directory.
* @param {String} imgPath The path of build folder.
* @return {Array} Image path array.
*/
async function img2bin(imgPath) {
try {
const image = await Jimp.read(imgPath);
const HEAD_SIZE = 8;
const PIXEL_SIZE = 4;// BRGA
const DATA_SIZE = image.bitmap.width * image.bitmap.height * PIXEL_SIZE;
const binSize = HEAD_SIZE + DATA_SIZE;
const binBuffer = new ArrayBuffer(binSize);
const binView = new DataView(binBuffer);
const COLOR_MODE = 1 << 8 + 0;
const WIDTH_BIT_OFFSET = 0;
const HEIGHT_BIT_OFFSET = 16;
const header = (image.bitmap.width << WIDTH_BIT_OFFSET) +
(image.bitmap.height << HEIGHT_BIT_OFFSET);
let binFileOffset = 0;
binView.setUint32(binFileOffset, COLOR_MODE, true);
binFileOffset += 4;
binView.setUint32(binFileOffset, header, true);
binFileOffset += 4;
image.scan(0, 0, image.bitmap.width, image.bitmap.height, function(x, y, idx) {
// eslint-disable-next-line no-invalid-this
const blue = this.bitmap.data[idx + 2];
binView.setUint8(binFileOffset, blue, true);
binFileOffset += 1;
// eslint-disable-next-line no-invalid-this
const green = this.bitmap.data[idx + 1];
binView.setUint8(binFileOffset, green, true);
binFileOffset += 1;
// eslint-disable-next-line no-invalid-this
const red = this.bitmap.data[idx + 0];
binView.setUint8(binFileOffset, red, true);
binFileOffset += 1;
// eslint-disable-next-line no-invalid-this
const alpha = this.bitmap.data[idx + 3];
binView.setUint8(binFileOffset, alpha, true);
binFileOffset += 1;
});
const binPath = imgPath.replace(/(\.png|\.jpg|\.bmp|\.jpeg|\.BMP|\.JPG|\.PNG|\.JPEG)$/, '.bin');
fs.writeFileSync(binPath, Buffer.from(binBuffer));
} catch (err) {
const imageName = _path.basename(imgPath);
console.error('\u001b[31m', `Failed to convert image ${imageName}.`, '\u001b[39m');
throw err;
}
}
module.exports = img2bin;

View File

@ -0,0 +1,45 @@
const pluginName = 'LiteReturnExportsPlugin';
/**
* LiteReturnExportsPlugin
*/
class LiteReturnExportsPlugin {
/**
* return exports from runtime
* @param {Object} compiler API specification, all configuration information of Webpack environment.
*/
apply(compiler) {
compiler.hooks.compilation.tap('SourcemapFixer', compilation => {
compilation.hooks.afterProcessAssets.tap('SourcemapFixer', assets => {
Reflect.ownKeys(assets).forEach(key => {
if (key.toString().includes('.map') && assets[key] && assets[key]._value) {
const sourceMapSources = JSON.parse(assets[key]._value).sources;
sourceMapSources.forEach((sourceMapSource, index) => {
sourceMapSource = sourceMapSource.replace(/\\/g,"/")
.replace(/webpack:\/\/\/[A-Z]:/g, function(a){return a.toLowerCase();});
sourceMapSources[index] = sourceMapSource;
});
const REG_SOURCES = new RegExp(/"sources":\[.*?\]/);
assets[key]._value = assets[key]._value.toString().replace(REG_SOURCES,
'"sources":' + JSON.stringify(sourceMapSources));
}
});
}
);
});
const { returnExportsFromRuntime } = compiler.webpack.RuntimeGlobals;
compiler.hooks.compilation.tap(pluginName, () => {
compiler.webpack.RuntimeGlobals.returnExportsFromRuntime = '__webpack_exports__';
});
compiler.hooks.afterCompile.tapAsync(pluginName, (_, callback) => {
compiler.webpack.RuntimeGlobals.returnExportsFromRuntime = returnExportsFromRuntime;
callback();
});
}
};
module.exports = LiteReturnExportsPlugin;

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2020 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 _require = require('child_process');
const exec = _require.exec;
const _path = require('path');
const snapshot = _path.join(__dirname, '..', '..', 'bin', 'jerry-snapshot');
const registerRequireContextHook = require('babel-plugin-require-context-hook/register');
registerRequireContextHook();
/**
* Convert Javascript file to snapshot.
*/
class SnapshotPlugin {
/**
* constructor of the SnapshotPlugin class.
* @param {String} options The object of build folder.
*/
constructor(options) {
this.options = options;
}
/**
* Find all javacript file paths in the directory.
* @param {Object} assets the object of javacript file path.
* @param {String} buildPath The path of build folder.
* @return {Array} Image path array.
*/
getDir(assets, buildPath) {
const pathArray = [];
Object.keys(assets).map((item) => {
if (/.js$/.test(item)) {
pathArray.push(_path.join(buildPath, item));
}
});
return pathArray;
};
/**
* Convert javacript file asynchronously. If an error occurs, print an error message.
* @param {Object} compiler API specification, all configuration information of Webpack environment.
*/
apply(compiler) {
const buildPath = this.options.build;
compiler.hooks.done.tap('snapshot coverter', (stats) => {
const pathArray = this.getDir(stats.compilation.assets, buildPath);
pathArray.forEach((element) => {
const bcPath = element.replace('.js', '.bc');
const fileName = _path.basename(element);
exec(`"${snapshot}" generate -o "${bcPath}" "${element}"`, (error) => {
if (error) {
console.error('\u001b[31m', `Failed to convert the ${fileName} file to a snapshot.`, '\u001b[39m');
}
});
});
});
}
}
module.exports = SnapshotPlugin;

View File

@ -0,0 +1,179 @@
/*
* Copyright (c) 2020 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.
*/
/*
* Customize the compiled style code into a styleSheet object, styleSheet object is divided into two parts, idSelectors
* and classSelectors. There are some detailed rules to explain:
* 1. Remove the "." And "#" symbols in front of the class selector and id selector;
* 2. Convert all numeric strings to numbers, such as:"32px" convert to number 32; "11" convert to number 11;
* 3. Convert all hex color to decimal number;
* 4. Convert all boolean strings to boolean type;
*/
const { SPECIAL_STYLE, REGEXP_NUMBER_PX, REGEXP_COLOR, REGEXP_UNIT, REGXP_QUOTES } = require('./lite-enum');
/**
* Split style into id Selectors and classSelectors.
* @param {Obejct} value Preliminary compilation results of css files.
* @return {String} String result stylesheet.
*/
function transformStyle(value) {
const style = Function(`return ${value}`)();
const idSelectors = {};
const classSelectors = {};
const styleSheet = {};
let res = '';
const KEYFRAMES = '@KEYFRAMES';
const keys = Object.keys(style);
for (const key of keys) {
if (key.charAt(0) === '.') {
classSelectors[key.slice(1)] = styleFormat(style[key]);
} else if (key.charAt(0) === '#') {
idSelectors[key.slice(1)] = styleFormat(style[key]);
} else if (key === KEYFRAMES) {
styleSheet['@keyframes'] = keyFrameFormat(style[key]);
} else {
// todo: Label style
}
}
if (style != null && keys.length !== 0) {
if (Object.keys(idSelectors).length !== 0) {
styleSheet['idSelectors'] = idSelectors;
}
if (Object.keys(classSelectors).length !== 0) {
styleSheet['classSelectors'] = classSelectors;
}
}
res = JSON.stringify(styleSheet);
return res;
}
/**
* keyFrame style special compilation.
* @param {Obejct} obj Preliminary compilation results of keyFrame style.
* @return {Obejct} keyFrame style obejct.
*/
function keyFrameFormat(obj) {
for (const key of Object.keys(obj)) {
const value = obj[key];
for (const styleValue of value) {
for (const styleKey of Object.keys(styleValue)) {
const innerValue = styleValue[styleKey];
if (REGEXP_COLOR.test(innerValue)) {
styleValue[styleKey] = parseInt(innerValue.slice(1), 16);
}
try {
styleValue[styleKey] = JSON.parse(styleValue[styleKey]);
} catch (e) {
// Values cannot be converted to objects are not processed
}
}
}
}
return obj;
}
const rules = [
{
match: function(key, value) {
return key === SPECIAL_STYLE.ANIMATION_DELAY || key === SPECIAL_STYLE.ANIMATION_DURATION;
},
action: function(obj, key, value) {
obj[key] = value;
},
},
{
match: function(key, value) {
return key === SPECIAL_STYLE.ANIMATION_ITERATION_COUNT;
},
action: function(obj, key, value) {
if (value === -1) {
value = 'infinite';
}
obj[key] = value.toString();
},
},
{
match: function(key, value) {
return [
SPECIAL_STYLE.BACKGROUND_IMAGE,
SPECIAL_STYLE.BACKGROUND_IMAGE_ACTIVE,
SPECIAL_STYLE.BACKGROUND_IMAGE_CHECKED,
].includes(key);
},
action: function(obj, key, value) {
obj[key] = value.replace(REGXP_QUOTES, '');
},
},
{
match: function(key, value) {
return !isNaN(Number(value));
},
action: function(obj, key, value) {
obj[key] = Number(value);
},
},
{
match: function(key, value) {
return REGEXP_NUMBER_PX.test(value);
},
action: function(obj, key, value) {
obj[key] = parseInt(value.replace(REGEXP_UNIT, ''), 10);
},
},
{
match: function(key, value) {
return REGEXP_COLOR.test(value);
},
action: function(obj, key, value) {
obj[key] = parseInt(value.slice(1), 16);
},
},
{
match: function(key, value) {
return value === 'true';
},
action: function(obj, key, value) {
obj[key] = true;
},
},
{
match: function(key, value) {
return value === 'false';
},
action: function(obj, key, value) {
obj[key] = false;
},
},
];
/**
* Loop and format style, There are two rules defined here, types of number+px and color convert to number 16777215.
* @param {Obejct} obj Preliminary compilation results of style object.
* @return {Obejct} style obejct.
*/
function styleFormat(obj) {
let value = '';
for (const key of Object.keys(obj)) {
value = obj[key];
for (let i = 0; i < rules.length; i++) {
if (rules[i].match(key, value)) {
rules[i].action(obj, key, value);
break;
}
}
}
return obj;
}
exports.transformStyle = transformStyle;

View File

@ -0,0 +1,557 @@
/*
* Copyright (c) 2020 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.
*/
/*
* Customize the compiled template code into a render function. There are some detailed rules to explain:
* 1. Convert all numeric strings to numbers, such as:"32px" convert to number 32; "11" convert to number 11;
* 2. Convert all hex color to decimal number;
* 3. Convert all boolean strings to boolean type;
* 4. compile events, the value of event Cannot be enclosed in double quotes;
*/
const { isFunction, isObject, isUndefined } = require('./lite-utils');
const {
SPECIAL_STYLE,
REGEXP_NUMBER_PX,
REGEXP_COLOR,
REGEXP_UNIT,
REGXP_QUOTES,
REGXP_LANGUAGE,
REGXP_LANGUAGE_KEY,
REGXP_FUNC_RETURN,
} = require('./lite-enum');
const parameterArray = [];
let parameter1 = '';
let parameter2 = '';
let i18nMapping = {};
const ATTRBUTES = 'attrs';
const EVENTS_ON_FUNC = 'on';
const KEY = 'key';
const AST_KEY = {
ATTR: 'attr',
CLASSLIST: 'classList',
STYLE: 'style',
EVENTS: 'events',
TYPE: 'type',
CHILDREN: 'children',
KEY: 'key',
};
const EVENT_KEY = [
'onBubbleEvents',
'catchBubbleEvents',
'onCaptureEvents',
'catchCaptureEvents',
];
const optionRules = {
[AST_KEY.ATTR]: function(dataContent, node, key) {
if (Object.keys(node.attr).length !== 0) {
dataContent += `'${ATTRBUTES}' : ${transformProps(node.attr)},`;
}
return dataContent;
},
[AST_KEY.CLASSLIST]: function(dataContent, node, key) {
dataContent += sortClass(node[key]);
return dataContent;
},
[AST_KEY.STYLE]: function(dataContent, node, key) {
dataContent += sortStyle(node[key]);
return dataContent;
},
[AST_KEY.EVENTS]: function(dataContent, node, key) {
dataContent += `'${EVENTS_ON_FUNC}' : ${transformEvents(node.events)},`;
return dataContent;
},
[AST_KEY.KEY]: function(dataContent, node, key) {
dataContent += `'${KEY}' : ${node.key},`;
return dataContent;
},
};
const styleRules = [
{
match: function(key, value) {
return key === SPECIAL_STYLE.ANIMATION_DELAY || key === SPECIAL_STYLE.ANIMATION_DURATION;
},
action: function(staticStyle, key, value) {
staticStyle += `'${key}' : ${JSON.stringify(value)},`;
return staticStyle;
},
},
{
match: function(key, value) {
return key === SPECIAL_STYLE.ANIMATION_ITERATION_COUNT;
},
action: function(staticStyle, key, value) {
if (value === -1) {
value = 'infinite';
}
staticStyle += `'${key}' : ${JSON.stringify(value)},`;
return staticStyle;
},
},
{
match: function(key, value) {
return key === SPECIAL_STYLE.BACKGROUND_IMAGE;
},
action: function(staticStyle, key, value) {
staticStyle += `'${key}' : ${checkType(value.replace(REGXP_QUOTES, ''))},`;
return staticStyle;
},
},
{
match: function(key, value) {
return true;
},
action: function(staticStyle, key, value) {
staticStyle += `'${key}' : ${checkType(value)},`;
return staticStyle;
},
},
];
(function() {
EVENT_KEY.map(function(event) {
optionRules[event] = function(dataContent, node, key) {
dataContent += `'${event}' : ${transformEvents(node[event])},`;
return dataContent;
};
});
})();
/**
* Compile the ast object into an executable function.
* @param {Obejct} value template object compiled ast.
* @return {String} template string.
*/
function transformTemplate(value) {
const ast = Function(`return ${value}`)();
let template = isObject(ast) ? transformNode(ast) : `_c('div')`;
template = template.replace(/,$/, '');
const cachedI18nPushStrings = Object.values(i18nMapping);
const I18nContect = cachedI18nPushStrings.length === 0 ? '' : ` var i18ns = []; ${cachedI18nPushStrings.join(';')};`;
const res = `function (vm) { var _vm = vm || this;${I18nContect} return ${template} }`;
i18nMapping = {};
return res;
}
/**
* Divided into if\for\ordinary three kinds node transform.
* @param {Obejct} node template object compiled ast.
* @return {String} template string.
*/
function transformNode(node) {
if (node.repeat && !node.forCompiled) {
return transformFor(node);
} else if (node.shown && !node.ifCompiled) {
return transformIf(node);
} else {
return transformNodeDetail(node);
}
}
/**
* Divide node into type/child/data three parts and compiled separately.
* @param {Obejct} node ordinary node.
* @return {String} ordinary node string.
*/
function transformNodeDetail(node) {
const type = node.type;
const options = transformOptions(node);
const children = transformChildren(node);
const render = `_c('${type}'${options ? `, ${options} ` : ``}${children ? `, ${children} ` : ``}),`;
return render;
}
/**
* Compile node all key-value datas.
* @param {Obejct} node ordinary node.
* @return {String} ordinary node attributes string.
*/
function transformOptions(node) {
let dataContent = '';
parameter2 = parameterArray[parameterArray.length - 1];
if (node.attr && node.attr.tid && parameter2 !== '') {
node['key'] = `${parameter2}.${node.attr['tid']}`;
delete node.attr.tid;
}
for (const key of Object.keys(node)) {
if (key !== AST_KEY.TYPE && key !== AST_KEY.CHILDREN) {
if (optionRules[key]) {
dataContent = optionRules[key](dataContent, node, key);
}
}
}
if (dataContent === '') {
return null;
}
dataContent = '{' + dataContent.replace(/,$/, '') + '}';
return dataContent;
}
/**
* Compile node classList, divided into dynamicClass and staticClass.
* @param {Function|String} classList the object of class list.
* @return {String} class list string.
*/
function sortClass(classList) {
let classStr = '';
const DYNAMIC_CLASS = 'dynamicClass';
const STATIC_CLASS = 'staticClass';
const value = checkType(classList);
// Divid into two parts dynamicClass and staticClass depending on whether it is a method type
if ((isFunction(classList) || isUndefined(classList)) && !REGXP_LANGUAGE.test(classList)) {
classStr += `'${DYNAMIC_CLASS}' : ${formatForFunc(value)},`;
} else {
classStr += `'${STATIC_CLASS}' : ${value},`;
}
return classStr;
}
/**
* Compile node style, divided into staticStyle and staticStyle.
* @param {Object} props the object of style.
* @return {String} style list string.
*/
function sortStyle(props) {
let staticStyle = '';
let dynamicStyle = '';
const STASTIC_STYLE = 'staticStyle';
const DYNAMIC_STYLE = 'dynamicStyle';
for (const key of Object.keys(props)) {
const value = props[key];
// Divid into two parts staticStyle and dynamicStyle depending on whether it is a method type
if (isFunction(value) && !REGXP_LANGUAGE.test(value)) {
dynamicStyle += `'${key}' : ${formatForFunc(value)},`;
} else {
for (let i = 0; i < styleRules.length; i++) {
if (styleRules[i].match(key, value)) {
staticStyle = styleRules[i].action(staticStyle, key, value);
break;
}
}
}
}
if (staticStyle !== '') {
staticStyle = `'${STASTIC_STYLE}' : {${staticStyle.replace(/,$/, '')}}, `;
}
if (dynamicStyle !== '') {
dynamicStyle = `'${DYNAMIC_STYLE}' :{${dynamicStyle.replace(/,$/, '')}},`;
}
return staticStyle + dynamicStyle;
}
/**
* general method ,judge type and compile, There are some special rules defined here,
* such as:"32px" convert to number 32; "11" convert to number 11; "#ffffff" convert to number 16777215.
* @param {*} value Value to be formatted.
* @return {*} Formatted value.
*/
function checkType(value) {
if (isFunction(value) || isUndefined(value)) {
return formatForFunc(value);
// Use recursive conversion of object type values
} else if (isObject(value)) {
return transformProps(value);
// Convert all numeric strings to numbers
} else if (!isNaN(Number(value))) {
return Number(value);
} else if (REGEXP_NUMBER_PX.test(value)) {
return parseInt(value.replace(REGEXP_UNIT, ''), 10);
// Convert all colors to numbers
} else if (REGEXP_COLOR.test(value)) {
return parseInt(value.slice(1), 16);
// Convert all boolean strings to boolean type
} else if (value === 'true') {
return true;
} else if (value === 'false') {
return false;
} else {
return JSON.stringify(value);
}
}
/**
* general method, compile data of object type, and compile node attributes.
* apart from The case where key is "value".
* @param {Object} props Value to be formatted.
* @return {String} Formatted value.
*/
function transformProps(props) {
let propContent = '';
const VALUE = 'value';
for (const key of Object.keys(props)) {
const propValue = props[key];
// value is used to display, except for method types, no conversion is required
if (key === VALUE) {
if (isFunction(propValue) || isUndefined(propValue)) {
propContent += `'${key}' : ${formatForFunc(props[key])},`;
} else {
propContent += `'${key}' : ${JSON.stringify(props[key])},`;
}
} else {
propContent += `'${key}' : ${checkType(props[key])},`;
}
}
propContent = `{${propContent.replace(/,$/, '')}}`;
return propContent;
}
/**
* compile events, divided into two types of conversion methods and string types.
* @param {Object} props Value of events to be formatted.
* @return {String} Formatted Value of events.
*/
function transformEvents(props) {
let eventContent = '';
for (const key of Object.keys(props)) {
if (isFunction(props[key])) {
/**
* Method contains parameters and will be compiled into a method.
* such as: onclick = "test(value)" => "click": function(evt){this.test(this.value, evt)}
*/
eventContent += `'${key}' : ${formatForFunc(props[key])},`;
} else {
/**
* The method contains no parameters and will be compiled into a string.
* such as: onclick = "test" => "click": "test"
*/
eventContent += `'${key}' : ${formatForString(props[key])},`;
}
}
eventContent = `{${eventContent.replace(/,$/, '')}}`;
return eventContent;
}
/**
* Compile events of type string, add `_vm.` in front of ordinary events, such as: onclick="test" => "click": "_vm.test"
* do nothing for the data in the `for` loop, such as: onclick="{{$item.click}}" => "click": "$item.click"
* @param {Object} value string type of events to be formatted.
* @return {String} Formatted Value of events.
*/
function formatForString(value) {
let forCompiled = false;
for (const parameter of parameterArray) {
// '$' Needs to be escaped in regular expressions. The parameter in the for instruction may be '$idx' and '$item'
const escape = parameter.charAt(0) === '$' ? '\\' : '';
const itRE = new RegExp(escape + parameter);
// Match the variable name in the stack, to determine whether it is ordinary event or an event in the for
if (itRE.test(value)) {
forCompiled = true;
break;
}
}
const res = forCompiled ? value : '_vm.' + value;
return res;
}
/**
* compile "for" direct, return the _l function.
* @param {Object} node node obejct with "for" directive.
* @return {String} string of _l function.
*/
function transformFor(node) {
let exp = node.repeat.exp ? node.repeat.exp : node.repeat;
parameterArray.push(node.repeat.key ? node.repeat.key : '$idx');
parameterArray.push(node.repeat.value ? node.repeat.value : '$item');
node.forCompiled = true;
// Set context and stack to convert "this.index" to "index" in the for function
exp = formatForFunc(exp);
const children = transformNode(node).replace(/,$/, '');
parameter2 = parameterArray[parameterArray.length - 1];
parameter1 = parameterArray[parameterArray.length - 2];
const comma = parameter1 !== '' && parameter2 !== '' ? ',' : '';
parameterArray.pop();
parameterArray.pop();
return '_l' + '((' + exp + '),' + 'function(' + parameter2 + comma + parameter1 + '){' + 'return ' + children + '}),';
}
/**
* compile "if" direct, return the _i function.
* @param {Object} node node obejct with "if" directive.
* @return {String} string of _i function.
*/
function transformIf(node) {
node.ifCompiled = true;
const children = transformNode(node).replace(/,$/, '');
return '_i' + '((' + formatForFunc(node.shown) + '),' + 'function(){return ' + children + '}),';
}
/**
* convert "this.index" to "index" in the for function. if the element is not in the for function,
* there will be no value in parameterArray
* @param {Object} value Value of function to be formatted.
* @return {String} Formatted Value of events.
*/
function formatForFunc(value) {
let func = value.toString();
for (const parameter of parameterArray) {
// '$' Needs to be escaped in regular expressions. The parameter in the for instruction may be '$idx' and '$item'
const escape = parameter.charAt(0) === '$' ? '\\' : '';
const itRE = new RegExp('this.' + escape + parameter + '\\b', 'g');
/**
* If it is a parameter in the for instruction, remove 'this'.
* such as: {"value": function () {return this.$item.name}} => {"value": function () {return $item.name}}
*/
func = func.replace(itRE, parameter);
}
// Replace all "this" to "_vm"
func = func.replace(/this\./g, '_vm.');
// Internationalization performance optimization
func = cacheI18nTranslation(func);
return func;
}
/**
* There is only one $t internationalizations in the processing function.
* @param {String} i18nExpression match the value of $t in the internationalization method.
* @param {Array} cachedI18nExpressions all keys of i18n Mapping object.
* @return {String} treated internationalization method.
*/
function handleLangSingle(i18nExpression, cachedI18nExpressions) {
let res = '';
if (cachedI18nExpressions.includes(i18nExpression)) {
// The i18nExpression already exists in cachedI18nExpressions
const cachedI18nPushStrings = Object.values(i18nMapping);
const cachedI18nPushString = i18nMapping[i18nExpression];
res = `i18ns[${cachedI18nPushStrings.lastIndexOf(cachedI18nPushString)}]`;
} else {
// The i18nExpression does not exist in cachedI18nExpressions
i18nMapping[
i18nExpression
] = `i18ns.push( ${i18nExpression} )`;
res = `i18ns[${Object.keys(i18nMapping).length - 1}]`;
}
return res;
}
/**
* There are multiple $t internationalizations in the processing function..
* @param {Array} i18nExpressions match the value of $t in the internationalization method.
* @param {Array} cachedI18nExpressions all keys of i18n Mapping object.
* @param {String} funcExpression return value in the internationalization method.
* @param {String} func internationalization method.
* @return {String} treated internationalization method.
*/
function handleLangMulti(i18nExpressions, cachedI18nExpressions, funcExpression, func) {
let res = func;
// The funcExpression already exists in cachedI18nExpressions
if (cachedI18nExpressions.includes(funcExpression)) {
const cachedI18nPushStrings = Object.values(i18nMapping);
const cachedI18nPushString = i18nMapping[funcExpression];
res = `i18ns[${cachedI18nPushStrings.lastIndexOf(cachedI18nPushString)}]`;
// The funcExpression does not exist in cachedI18nExpressions
} else {
for (let i = 0; i < i18nExpressions.length; i++) {
const i18nExpression = i18nExpressions[i];
// The i18nExpression already exists in cachedI18nExpressions
if (cachedI18nExpressions.includes(i18nExpression)) {
const cachedI18nPushStrings = Object.values(i18nMapping);
const cachedI18nPushString = i18nMapping[i18nExpression];
res = res.replace(
i18nExpression,
`i18ns[${cachedI18nPushStrings.lastIndexOf(cachedI18nPushString)}]`,
);
// The i18nExpression does not exists in cachedI18nExpressions
} else {
i18nMapping[
i18nExpression
] = `i18ns.push( ${i18nExpression} )`;
res = res.replace(
i18nExpression,
`i18ns[${Object.keys(i18nMapping).length - 1}]`,
);
}
// For the last $t, replace the func value
if (i === i18nExpressions.length - 1 && !res.includes('_vm.')) {
const funcReturnMatches = REGXP_FUNC_RETURN.exec(res);
REGXP_FUNC_RETURN.lastIndex = 0;
const funcReturnMatch = funcReturnMatches[1].trim();
i18nMapping[funcExpression] = `i18ns.push( ${funcReturnMatch} )`;
res = `i18ns[${Object.keys(i18nMapping).length - 1}]`;
}
}
}
return res;
}
/**
* Internationalization performance optimization operation.
* @param {String} func string for globalization method.
* @return {String} Whether to use the parameters in 'for' instruction.
*/
function cacheI18nTranslation(func) {
if (!REGXP_LANGUAGE.test(func)) {
return func;
}
const i18nExpressions = func.match(REGXP_LANGUAGE_KEY);
const cachedI18nExpressions = Object.keys(i18nMapping);
const funcExpressions = REGXP_FUNC_RETURN.exec(func);
REGXP_FUNC_RETURN.lastIndex = 0;
const funcExpression = funcExpressions[1].trim();
// If the 'for' parameter is used in $t, nothing will be done
if (isUseForInstrucParam(funcExpression)) {
return func;
}
// There is only one $t internationalization in the function.
// such as:function () { return ( _vm.$t('i18n.text.value1')) }
if (i18nExpressions.length === 1 && i18nExpressions[0] === funcExpression) {
const i18nExpression = i18nExpressions[0];
func = handleLangSingle(i18nExpression, cachedI18nExpressions);
// There are multiple $t internationalization in the function.
// such as: function () { return ( _vm.$t('i18n.text.value1') - _vm.$t('i18n.text.value2')); }
} else {
func = handleLangMulti(i18nExpressions, cachedI18nExpressions, funcExpression, func);
}
return func;
}
/**
* Determine whether the parameters in the 'for' instruction are used in the globalization method.
* @param {String} value string for globalization method.
* @return {Blooean} Whether to use the parameters in 'for' instruction.
*/
function isUseForInstrucParam(value) {
let isUseParam = false;
for (const parameter of parameterArray) {
const escape = parameter.charAt(0) === '$' ? '\\' : '';
const itRE = new RegExp(escape + parameter);
// Match the variable name in the stack, to determine whether it is ordinary event or an event in the for
if (itRE.test(value)) {
isUseParam = true;
break;
}
}
return isUseParam;
}
/**
* compile node children.
* @param {Object} node ordinary node.
* @return {String} ordinary node children string.
*/
function transformChildren(node) {
const children = node.children;
if (!children) {
return null;
}
let childContent = '';
for (let i = 0; i < children.length; i++) {
childContent += transformNode(children[i]);
}
childContent = '[' + childContent.replace(/,$/, '') + ']';
return childContent;
}
exports.transformTemplate = transformTemplate;

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2020 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 is = (type) => {
return (source) => Object.prototype.toString.call(source) === `[object ${type}]`;
};
exports.isFunction = is('Function');
exports.isUndefined = is('Undefined');
exports.isObject = is('Object');
exports.isArray = is('Array');
exports.isNull = is('Null');

View File

@ -0,0 +1,226 @@
/**
* Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
*/
import loaderUtils from 'loader-utils'
import path from 'path'
import fs from 'fs'
import * as legacy from './legacy'
import {
parseFragment
}
from './parser'
import {
getNameByPath,
getRequireString,
stringifyLoaders,
logWarn,
loadBabelModule
}
from './util'
import { isReservedTag } from './templater/component_validator'
import loader from 'sass-loader'
const { DEVICE_LEVEL } = require('./lite/lite-enum')
const loaderPath = __dirname
const defaultLoaders = {
none: '',
main: path.resolve(loaderPath, 'loader.js'),
template: path.resolve(loaderPath, 'template.js'),
style: path.resolve(loaderPath, 'style.js'),
script: path.resolve(loaderPath, 'script.js'),
json: path.resolve(loaderPath, 'json.js'),
babel: loadBabelModule('babel-loader'),
manifest: path.resolve(loaderPath, 'manifest-loader.js'),
extgen: path.resolve(loaderPath, 'extgen.js')
}
function getLoaderString (type, config) {
config = config || {}
const customLoader = loadCustomLoader(config)
let loaders
switch (type) {
case 'main':
return mainLoaderString(loaders)
case 'element':
return elementLoaderString(loaders, config)
case 'template':
return templateLoaderString(loaders, config, customLoader)
case 'style':
return styleLoaderString(loaders, config, customLoader)
case 'script':
return scriptLoaderString(loaders, config, customLoader)
case 'config':
return configLoaderString(loaders, config)
case 'data':
return dataLoaderString(loaders, config)
default:
return
}
}
function loadCustomLoader (config) {
if (config.lang && config.customLang[config.lang]) {
return loadBabelModule(config.customLang[config.lang][0])
}
}
function mainLoaderString (loaders) {
loaders = [{
name: defaultLoaders.main
}]
return stringifyLoaders(loaders)
}
function elementLoaderString (loaders, config) {
loaders = [{
name: defaultLoaders.main,
query: {
element: config.source ? undefined : true
}
}]
return stringifyLoaders(loaders)
}
function templateLoaderString (loaders, config, customLoader) {
loaders = [{
name: defaultLoaders.json
}, {
name: defaultLoaders.template
}]
if (customLoader) {
loaders = loaders.concat(customLoader)
}
loaders.push({
name: defaultLoaders.extgen,
query: {
type: 'template'
}
})
return stringifyLoaders(loaders)
}
function styleLoaderString (loaders, config, customLoader) {
loaders = [{
name: defaultLoaders.json
}, {
name: defaultLoaders.style
}]
if (customLoader) {
loaders = loaders.concat(customLoader)
}
loaders.push({
name: defaultLoaders.extgen,
query: {
type: 'style'
}
})
return stringifyLoaders(loaders)
}
function scriptLoaderString (loaders, config, customLoader) {
loaders = [{
name: defaultLoaders.script
}]
if (customLoader) {
loaders = loaders.concat(customLoader)
}
else {
loaders.push({
name: defaultLoaders.babel,
query: {
presets: [loadBabelModule('@babel/preset-env')],
plugins: [loadBabelModule('@babel/plugin-transform-modules-commonjs')],
comments: 'false'
}
})
}
if (config.app) {
loaders.push({
name: defaultLoaders.manifest,
query: {
path: config.source
}
})
}
return stringifyLoaders(loaders)
}
function configLoaderString (loaders, config) {
loaders = [{
name: defaultLoaders.json
}]
return stringifyLoaders(loaders)
}
function dataLoaderString (loaders, config) {
loaders = [{
name: defaultLoaders.json
}]
return stringifyLoaders(loaders)
}
function codegenHmlAndCss() {
const options = {
lang: {
sass:['sass-loader'],
scss:['sass-loader'],
less:['less-loader']
}
}
const customLang = options.lang || {}
const loaderQuery = loaderUtils.getOptions(this) || {}
const isElement = loaderQuery.element
const resourceQuery = this.resourceQuery && loaderUtils.parseQuery(this.resourceQuery) || {}
const isEntry = resourceQuery.entry
let output = ''
let jsFileName = this.resourcePath.replace(process.env.aceSuperVisualPath, process.env.aceModuleRoot)
jsFileName = jsFileName.substr(0, jsFileName.length - 6) + 'js';
output = 'var $app_script$ = ' + getRequireString(this, getLoaderString('script', {
customLang,
lang: undefined,
element: undefined,
elementName: undefined,
source: jsFileName
}), jsFileName)
output += 'var $app_template$ = ' + getRequireString(this, getLoaderString('template', {
customLang,
lang: undefined,
element: isElement,
elementName: undefined,
source: this.resourcePath
}), this.resourcePath)
output += 'var $app_style$ = ' + getRequireString(this, getLoaderString('style', {
customLang,
lang: undefined,
element: isElement,
elementName: undefined,
source: this.resourcePath
}), this.resourcePath)
output += `
$app_define$('@app-component/${getNameByPath(this.resourcePath)}', [], function($app_require$, $app_exports$, $app_module$) {
` + `
$app_script$($app_module$, $app_exports$, $app_require$)
if ($app_exports$.__esModule && $app_exports$.default) {
$app_module$.exports = $app_exports$.default
}
` + `
$app_module$.exports.template = $app_template$
` + `
$app_module$.exports.style = $app_style$
` + `
})
`
if (isEntry) {
output += `$app_bootstrap$('@app-component/${getNameByPath(this.resourcePath)}'` + ',undefined' + ',undefined' + `)`
}
return output
}
module.exports = codegenHmlAndCss

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2020 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 utils = require('./util');
const path = require('path');
let projectPath = process.env.aceModuleRoot || process.cwd();
const manifestFilePath = process.env.aceManifestPath || path.resolve(projectPath, 'manifest.json');
function manifestLoader(source) {
const manifestPlugin = utils.stringifyLoaders([{ name: path.resolve(__dirname, 'manifest-plugin.js') }]);
const queryString = utils.getRequireString(this, manifestPlugin, manifestFilePath);
source += ';(exports.default || module.exports).manifest = ' + queryString;
return source;
}
module.exports = manifestLoader;

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2020 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 { DEVICE_LEVEL } = require('./lite/lite-enum');
module.exports = function(source, map) {
this.cacheable && this.cacheable()
const callback = this.async()
if (process.env.DEVICE_LEVEL === DEVICE_LEVEL.LITE) {
callback(null, JSON.stringify({ 'manifest.json': 'content' }), map)
} else {
callback(null, source, map)
}
};

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 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.
*/
import {
parseRequireModule
} from './util';
module.exports = function(source, map) {
source = parseRequireModule(source);
this.cacheable && this.cacheable()
const callback = this.async()
callback(null, source, map)
};

View File

@ -0,0 +1,233 @@
/*
* Copyright (c) 2020 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 fs = require('fs');
const path = require('path');
const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
const CUSTOM_THEME_PROP_GROUPS = require('./theme/customThemeStyles');
const OHOS_THEME_PROP_GROUPS = require('./theme/ohosStyles');
const FILE_EXT_NAME = ['.js', '.css', '.jsx', '.less', '.sass', '.scss', '.md', '.DS_Store', '.hml'];
const red = '\u001b[31m';
const reset = '\u001b[39m';
let input = '';
let output = '';
let manifestFilePath = '';
let shareThemePath = '';
let internalThemePath = '';
function copyFile(input, output) {
try {
if (fs.existsSync(input)) {
const parent = path.join(output, '..');
if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) {
mkDir(parent);
}
const pathInfo = path.parse(input);
const entryObj = addPageEntryObj();
const indexPath = pathInfo.dir + path.sep + pathInfo.name + '.hml?entry';
for (const key in entryObj) {
if (entryObj[key] === indexPath) {
return;
}
}
if (pathInfo.ext === '.json' && (pathInfo.dir === shareThemePath ||
pathInfo.dir === internalThemePath)) {
if (themeFileBuild(input, output)) {
return;
}
}
const readStream = fs.createReadStream(input);
const writeStream = fs.createWriteStream(output);
readStream.pipe(writeStream);
readStream.on('close', function() {
writeStream.end();
});
}
} catch (e) {
console.error(red, `Failed to build file ${input}.`, reset);
throw e.message;
}
}
function mkDir(path_) {
const parent = path.join(path_, '..');
if (!(fs.existsSync(parent) && !fs.statSync(parent).isFile())) {
mkDir(parent);
}
fs.mkdirSync(path_);
}
function circularFile(inputPath, outputPath, ext) {
const realPath = path.join(inputPath, ext);
const localI18n = path.join(input, 'i18n')
if (!fs.existsSync(realPath) || realPath === output || realPath === localI18n) {
return;
}
fs.readdirSync(realPath).forEach(function(file_) {
const file = path.join(realPath, file_);
const fileStat = fs.statSync(file);
if (fileStat.isFile()) {
const baseName = path.basename(file);
const extName = path.extname(file);
if (FILE_EXT_NAME.indexOf(extName) < 0 && baseName !== '.DS_Store') {
const outputFile = path.join(outputPath, ext, path.basename(file_));
if (outputFile === path.join(output, 'manifest.json')) {
return;
}
if (fs.existsSync(outputFile)) {
const outputFileStat = fs.statSync(outputFile);
if (outputFileStat.isFile() && fileStat.size !== outputFileStat.size) {
copyFile(file, outputFile);
}
} else {
copyFile(file, outputFile);
}
}
} else if (fileStat.isDirectory()) {
circularFile(inputPath, outputPath, path.join(ext, file_));
}
});
}
class ResourcePlugin {
constructor(input_, output_, manifestFilePath_) {
input = input_;
output = output_;
manifestFilePath = manifestFilePath_;
shareThemePath = path.join(input_, '../share/resources/styles');
internalThemePath = path.join(input_, 'resources/styles');
}
apply(compiler) {
compiler.hooks.beforeCompile.tap('resource Copy', () => {
circularFile(input, output, '');
circularFile(input, output, '../share');
});
compiler.hooks.normalModuleFactory.tap('OtherEntryOptionPlugin', () => {
addPageEntryObj();
for (const key in entryObj) {
if (!compiler.options.entry[key]) {
const singleEntry = new SingleEntryPlugin('', entryObj[key], key);
singleEntry.apply(compiler);
}
}
});
compiler.hooks.done.tap('copyManifest', () => {
copyManifest();
if (fs.existsSync(path.join(output, 'app.js'))) {
fs.utimesSync(path.join(output, 'app.js'), new Date(), new Date())
}
});
}
}
function copyManifest() {
copyFile(manifestFilePath, path.join(output, 'manifest.json'));
}
let entryObj = {};
function addPageEntryObj() {
entryObj = {};
if (!fs.existsSync(manifestFilePath)) {
throw Error('ERROR: missing manifest').message;
}
const jsonString = fs.readFileSync(manifestFilePath).toString();
const obj = JSON.parse(jsonString);
const pages = obj.pages;
if (pages === undefined) {
throw Error('ERROR: missing pages').message;
}
pages.forEach((element) => {
const sourcePath = element;
const hmlPath = path.join(input, sourcePath + '.hml')
const aceSuperVisualPath = process.env.aceSuperVisualPath || ''
const visualPath = path.join(aceSuperVisualPath, sourcePath + '.visual')
const isHml = fs.existsSync(hmlPath)
const isVisual = fs.existsSync(visualPath)
if (isHml && isVisual) {
logWarn(this, [{
reason: 'ERROR: ' + sourcePath + ' cannot both have hml && visual'
}])
} else if (isHml) {
entryObj['./' + element] = hmlPath + '?entry';
} else if (isVisual){
entryObj['./' + element] = visualPath + '?entry';
}
});
if (process.env.isPreview !== 'true' && process.env.DEVICE_LEVEL === 'rich') {
loadWorker(entryObj);
}
return entryObj;
}
function loadWorker(entryObj) {
const workerPath = path.resolve(input, 'workers');
if (fs.existsSync(workerPath)) {
const workerFiles = [];
readFile(workerPath, workerFiles);
workerFiles.forEach((item) => {
if (/\.js$/.test(item)) {
const relativePath = path.relative(workerPath, item).replace(/\.js$/, '');
entryObj[`./workers/` + relativePath] = item;
}
})
}
}
function readFile(dir, utFiles) {
try {
const files = fs.readdirSync(dir);
files.forEach((element) => {
const filePath = path.join(dir, element);
const status = fs.statSync(filePath);
if (status.isDirectory()) {
readFile(filePath, utFiles);
} else {
utFiles.push(filePath);
}
})
} catch (e) {
console.error(e.message);
}
}
function themeFileBuild(customThemePath, customThemeBuild) {
if (fs.existsSync(customThemePath)) {
const themeContent = JSON.parse(fs.readFileSync(customThemePath));
const newContent = {};
if (themeContent && themeContent['style']) {
newContent['style'] = {};
const styleContent = themeContent['style'];
Object.keys(styleContent).forEach(function(key) {
const customKey = CUSTOM_THEME_PROP_GROUPS[key];
const ohosKey = OHOS_THEME_PROP_GROUPS[key];
if (ohosKey) {
newContent['style'][ohosKey] = styleContent[key];
} else if (customKey) {
newContent['style'][customKey] = styleContent[key];
} else {
newContent['style'][key] = styleContent[key];
}
});
fs.writeFileSync(customThemeBuild, JSON.stringify(newContent, null, 2));
return true;
}
}
return false;
}
module.exports = ResourcePlugin;

View File

@ -0,0 +1,67 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 OHOS_THEME_PROP_GROUPS = require('./theme/ohosStyles')
module.exports = function (source) {
let result
// target format: this.$r("ohos.id_color_background") or this.$r('ohos.id_color_background') or
// "this.$r('ohos.id_color_background')"
let ResourceRefReg = /"?this\s*\.\$r\s*\(\s*((['"]ohos\.(?<resName>\w+)['"]))\s*\)"?/g
while (result = ResourceRefReg.exec(source)) {
const resourceName = result.groups['resName']
if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
const resourceId = "\"@ohos_id_" + OHOS_THEME_PROP_GROUPS[resourceName] + "\""
source = source.replace(result[0], resourceId)
// update the start position of the next match
ResourceRefReg.lastIndex -= result[0].length - resourceId.length
}
}
// target format: this.$r("sys.type.id_color_background") or this.$r('sys.type.id_color_background') or
// "this.$r('sys.type.id_color_background')"
// The "type" field can be "float", "color", "string" and so on.
let SysResourceTypeRefReg = /"?this\s*\.\$r\s*\(\s*((['"]sys\.(?<resType>\w+)\.(?<resName>\w+)['"]))\s*\)"?/g
while (result = SysResourceTypeRefReg.exec(source)) {
const resourceName = result.groups['resName']
const resourceType = result.groups['resType']
if (resourceName && resourceType && OHOS_THEME_PROP_GROUPS[resourceName]) {
const resourceId = "\"@sys." + resourceType + "." + OHOS_THEME_PROP_GROUPS[resourceName] + "\""
source = source.replace(result[0], resourceId)
// update the start position of the next match
SysResourceTypeRefReg.lastIndex -= result[0].length - resourceId.length
}
}
// target format: this.$r("app.type.developer_defined_color") or this.$r('app.type.developer_defined_color') or
// "this.$r('app.type.developer_defined_color')"
// The "type" field can be "float", "color", "string" and so on.
let AppResourceTypeRefReg = /"?this\s*\.\$r\s*\(\s*((['"]app\.(?<resType>\w+)\.(?<resName>\w+)['"]))\s*\)"?/g
while (result = AppResourceTypeRefReg.exec(source)) {
const resourceName = result.groups['resName']
const resourceType = result.groups['resType']
if (resourceName && resourceType) {
const resourceId = "\"@app." + resourceType + "." + resourceName + "\""
source = source.replace(result[0], resourceId)
// update the start position of the next match
AppResourceTypeRefReg.lastIndex -= result[0].length - resourceId.length
}
}
return source
}

View File

@ -0,0 +1,134 @@
{
"template": {
"attr": {},
"type": "div",
"classList": [
"container"
],
"children": [
{
"attr": {
"value": "id_test1"
},
"type": "div",
"id": "testid"
},
{
"attr": {
"value": "style_test_1"
},
"type": "div",
"style": {
"color": "#008000"
}
},
{
"attr": {
"value": "style_test_2"
},
"type": "div",
"style": {
"borderTopColor": "{{col}}",
"borderRightColor": "{{col}}",
"borderBottomColor": "{{col}}",
"borderLeftColor": "{{col}}"
}
},
{
"attr": {
"value": "style_test_2"
},
"type": "div",
"style": {
"borderTopColor": "{{col}}",
"borderRightColor": "{{col}}",
"borderBottomColor": "{{col}}",
"borderLeftColor": "{{col}}",
"width": "50px"
}
},
{
"attr": {
"value": "class_test1"
},
"type": "div",
"classList": [
"title"
]
},
{
"attr": {
"value": "class_test2"
},
"type": "div",
"classList": [
"title",
"table"
]
},
{
"attr": {
"value": "class_test3"
},
"type": "div",
"classList": [
"title",
"table"
]
},
{
"attr": {
"value": "class_test4"
},
"type": "div",
"classList": [
"{{testclass1}}"
]
},
{
"attr": {
"value": "class_test5"
},
"type": "div",
"classList": [
"{{testclass1}}",
"{{testclass2}}"
]
},
{
"attr": {
"value": "class_test6"
},
"type": "div",
"classList": [
"{{testclass1}}",
"{{testclass2}}"
]
},
{
"attr": {
"disabled": "{{disabled}}",
"value": "disable_test1"
},
"type": "div"
}
]
},
"styles": {},
"actions": {},
"data": {
"testclass1": "testclass1",
"testclass2": "testclass2",
"col": "#008000",
"disabled": true
},
"apiVersion": {
"5": {
"disabled": false
},
"6": {
"col": "#808080",
"content": "Hello World!"
}
}
}

View File

@ -0,0 +1,37 @@
{
"template": {
"type": "div",
"attr": {},
"children": [
{
"type": "div",
"attr": {},
"events": {
"click": "router"
}
},
{
"type": "div",
"attr": {},
"events": {
"click": "router"
}
}
]
},
"styles": {},
"actions": {
"click": {
"action": "router",
"bundleName": "com.example.helloworld",
"abilityName": "com.example.helloworld.MainAbility",
"params": {
"day": "$event.day",
"time": "$event.time",
"year": "$event.year"
}
}
},
"data": {},
"apiVersion": {}
}

View File

@ -0,0 +1,23 @@
{
"template": {
"type": "div",
"attr": {},
"classList": [
"container"
],
"children": [
{
"type": "text",
"attr": {
"value": "{{content}}"
}
}
]
},
"actions": {},
"styles": {},
"data": {
"content": "Hello World!"
},
"apiVersion": {}
}

View File

@ -0,0 +1,86 @@
{
"template": {
"type": "div",
"attr": {
"value": "exteriorStyle_test"
}
},
"styles": {
".a": {
"width": "100%",
"height": "50%"
},
".b": {
"width": "100px",
"height": "200px"
},
".c": {
"color": "#808080"
},
".d": {
"color": "#008000"
},
".e": {
"color": "rgba(80,60,150,1)"
},
".j": {
"gridTemplateColumns": "50px 40px 80px"
},
".l": {
"gridRowStart": 3
},
".m": {
"borderTopWidth": "5px",
"borderRightWidth": "5px",
"borderBottomWidth": "5px",
"borderLeftWidth": "5px",
"borderStyle": "solid",
"borderTopColor": "#808080",
"borderRightColor": "#808080",
"borderBottomColor": "#808080",
"borderLeftColor": "#808080"
},
".n": {
"textIndent": "50px"
},
".o": {
"backgroundImage": "/common/img/a.jpg"
},
".t": {
"startAngle": "240deg"
},
".v": {
"paddingTop": "10px",
"paddingRight": "15px",
"paddingBottom": "10px",
"paddingLeft": "15px"
},
"#w": {
"fontSize": "15px",
"fontFamily": "PingFangSC-Regular"
},
".gradient1": {
"background": "{\"values\":[{\"type\":\"linearGradient\",\"directions\":[\"to\",\"bottom\"],\"values\":[\"#ff0000\",\"#00ff00\"]}]}"
},
".gradient2": {
"background": "{\"values\":[{\"type\":\"linearGradient\",\"directions\":[\"45deg\"],\"values\":[\"rgb(255,0,0)\",\"rgb(0,255,0)\"]}]}"
},
".gradient3": {
"background": "{\"values\":[{\"type\":\"linearGradient\",\"directions\":[\"to\",\"right\"],\"values\":[\"rgb(255,0,0) 90px\",\"rgb(0,0,255) 60%\"]}]}"
},
".gradient4": {
"background": "{\"values\":[{\"type\":\"repeatingLinearGradient\",\"directions\":[\"to\",\"right\"],\"values\":[\"rgba(255,255,0,1) 30px\",\"rgba(0,0,255,0.5) 60px\"]}]}"
},
"@FONT-FACE": [
{
"fontFamily": "HWfont",
"src": "url(/common/HWfont.ttf)"
}
],
".txt": {
"fontFamily": "HWfont"
}
},
"actions": {},
"data": {}
}

View File

@ -0,0 +1,36 @@
{
"template": {
"type": "div",
"attr": {},
"children": [
{
"type": "text",
"attr": {
"value": "Hello-TV"
},
"shown": "{{show}}"
},
{
"type": "text",
"attr": {
"value": "Hello-Wearable"
},
"shown": "{{display}}&&!{{show}}"
},
{
"type": "text",
"attr": {
"value": "Hello-World"
},
"shown": "!{{display}}&&!{{show}}"
}
]
},
"styles": {},
"actions": {},
"data": {
"show": false,
"display": true
},
"apiVersion": {}
}

View File

@ -0,0 +1,21 @@
{
"template": {
"type": "div",
"attr": {
"value": "importCSS_test"
},
"classList": [
"container"
]
},
"styles": {
".title": {
"fontSize": "50px"
},
".container": {
"justifyContent": "center"
}
},
"actions": {},
"data": {}
}

View File

@ -0,0 +1,18 @@
{
"template": {
"type": "div",
"attr": {
"value": "importLess_test"
},
"classList": [
"container"
]
},
"styles": {
".container": {
"backgroundColor": "#000000"
}
},
"actions": {},
"data": {}
}

View File

@ -0,0 +1,145 @@
{
"template": {
"type": "div",
"attr": {},
"classList": [
"container"
],
"children": [
{
"type": "div",
"attr": {
"value": "style_test1"
},
"style": {
"width": "100%"
}
},
{
"type": "div",
"attr": {
"value": "style_test2"
},
"style": {
"height": "{{height}}"
}
},
{
"type": "div",
"attr": {
"value": "style_test3"
},
"style": {
"color": "#008000"
}
},
{
"type": "div",
"attr": {
"value": "style_test4"
},
"style": {
"color": "#FF0000"
}
},
{
"type": "div",
"attr": {
"value": "style_test5"
},
"style": {
"color": "rgba(200,180,120,1)"
}
},
{
"type": "div",
"attr": {
"value": "style_test10"
},
"style": {
"gridTemplateColumns": "50px 100px 60px"
}
},
{
"type": "div",
"attr": {
"value": "style_test11"
},
"style": {
"gridRowStart": 2
}
},
{
"type": "div",
"attr": {
"value": "style_test12"
},
"style": {
"borderTopWidth": "5px",
"borderRightWidth": "5px",
"borderBottomWidth": "5px",
"borderLeftWidth": "5px",
"borderTopStyle": "solid",
"borderRightStyle": "solid",
"borderBottomStyle": "solid",
"borderLeftStyle": "solid",
"borderTopColor": "#FF0000",
"borderRightColor": "#FF0000",
"borderBottomColor": "#FF0000",
"borderLeftColor": "#FF0000"
}
},
{
"type": "div",
"attr": {
"value": "style_test13"
},
"style": {
"textIndent": "50px"
}
},
{
"type": "div",
"attr": {
"value": "style_test14"
},
"style": {
"backgroundImage": "/common/img/xmad.jpg"
}
},
{
"type": "progress",
"attr": {
"value": "style_test19"
},
"style": {
"startAngle": "240deg"
}
},
{
"type": "div",
"attr": {
"value": "style_test21"
},
"style": {
"paddingTop": "10px",
"paddingRight": "15px",
"paddingBottom": "10px",
"paddingLeft": "15px"
}
},
{
"type": "div",
"attr": {
"value": "style_test23"
},
"style": {
"backgroundImage": "https://huawei.com/logo.jpg"
}
}
]
},
"styles": {},
"actions": {},
"data": {}
}

View File

@ -0,0 +1,49 @@
{
"template": {
"type": "div",
"attr": {
"value": "mediaQuery_test"
}
},
"styles": {
"@MEDIA": [
{
"condition": "(dark-mode:true)",
".header": {
"width": "100%",
"height": "60px",
"fontSize": "16px",
"alignItems": "center",
"justifyContent": "center"
},
".footer": {
"width": "100%",
"height": "40px",
"alignItems": "center"
}
},
{
"condition": "(dark-mode:true)",
".title": {
"fontSize": "16px",
"color": "#333333",
"alignItems": "center"
},
".container": {
"width": "500px",
"height": "500px",
"backgroundColor": "#fa8072"
},
".button": {
"paddingTop": "50px",
"fontSize": "16px",
"color": "#666666",
"alignItems": "center",
"justifyContent": "center"
}
}
]
},
"actions": {},
"data": {}
}

View File

@ -0,0 +1,61 @@
{
"template": {
"type": "div",
"attr": {},
"classList": [
"container"
],
"children": [
{
"type": "image",
"attr": {
"alt": "img",
"src": "{{src}}"
}
},
{
"type": "progress",
"attr": {
"type": "horizontal",
"percent": "{{percent}}",
"secondarypercent": "{{secondarypercent}}"
}
},
{
"type": "progress",
"attr": {
"type": "scale-ring",
"percent": "{{percent}}",
"secondarypercent": "{{secondarypercent}}",
"clockwise": "{{clockwise}}"
}
},
{
"type": "progress",
"attr": {
"type": "arc",
"percent": "{{percent}}"
}
},
{
"type": "chart",
"attr": {
"type": "line",
"options": "{{options}}",
"datasets": "{{datasets}}"
}
},
{
"type": "button",
"attr": {
"type": "capsule",
"value": "{{value}}",
"icon": "{{icon}}"
}
}
]
},
"styles": {},
"actions": {},
"data": {}
}

View File

@ -0,0 +1,31 @@
{
"template": {
"type": "div",
"attr": {},
"classList": [
"container"
],
"children": [
{
"type": "text",
"attr": {
"show": "false",
"value": "Hello World"
}
},
{
"type": "text",
"attr": {
"show": "{{visible}}",
"value": "Hello World"
}
}
]
},
"styles": {},
"actions": {},
"data": {
"visible": false
},
"apiVersion": {}
}

View File

@ -0,0 +1,96 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
'use strict';
const fs = require('fs');
const path =require('path');
const chai = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');
const expect = chai.expect;
chai.use(sinonChai);
function getActualJSON(componentName, filaName) {
const filePath = path.join(__dirname,"testcase/build/pages",`${componentName}`, filaName + `.json`);
if(!fs.existsSync(filePath)){
return {}
}
const fileContent = fs.readFileSync(filePath, "utf-8");
const fileString = fileContent.toString();
return JSON.parse(fileString);
}
function getExpectJSON(componentName, filaName) {
const filePath = path.join(__dirname, "expected", `${componentName}`, filaName + `.json`);
if(!fs.existsSync(filePath)){
return {}
}
const expectedContent = fs.readFileSync(filePath, "utf-8");
const expectedObj = JSON.parse(expectedContent.toString());
return expectedObj;
}
describe('build', () => {
it('commonAttr', () => {
const page = 'commonAttr'
expect(getActualJSON(page, 'commonAttr')).eql(getExpectJSON(page, 'commonAttr'));
});
it('event', () => {
const page = 'event'
expect(getActualJSON(page, 'event')).eql(getExpectJSON(page, 'event'));
});
it('expression', () => {
const page = 'expression'
expect(getActualJSON(page, 'expression')).eql(getExpectJSON(page, 'expression'));
});
it('exteriorStyle', () => {
const page = 'exteriorStyle'
expect(getActualJSON(page, 'exteriorStyl')).eql(getExpectJSON(page, 'exteriorStyl'));
});
it('ifAttr', () => {
const page = 'ifAttr'
expect(getActualJSON(page, 'ifAttr')).eql(getExpectJSON(page, 'ifAttr'));
});
it('importCSS', () => {
const page = 'importCSS'
expect(getActualJSON(page, 'importCSS')).eql(getExpectJSON(page, 'importCSS'));
});
it('importLess', () => {
const page = 'importLess'
expect(getActualJSON(page, 'importLess')).eql(getExpectJSON(page, 'importLess'));
});
it('inlineStyle', () => {
const page = 'inlineStyle'
expect(getActualJSON(page, 'inlineStyle')).eql(getExpectJSON(page, 'inlineStyle'));
});
it('mediaQuery', () => {
const page = 'mediaQuery'
expect(getActualJSON(page, 'mediaQuer')).eql(getExpectJSON(page, 'mediaQuer'));
});
it('privateAttr', () => {
const page = 'privateAttr'
expect(getActualJSON(page, 'privateAttr')).eql(getExpectJSON(page, 'privateAttr'));
});
it('showAttr', () => {
const page = 'showAttr'
expect(getActualJSON(page, 'showAttr')).eql(getExpectJSON(page, 'showAttr'));
});
});

View File

@ -0,0 +1,13 @@
.item{
width: 700px;
flex-direction: column;
height: 300px;
align-items: center;
margin-top: 100px;
}
.text_style {
font-weight:500;
font-family:Courier;
font-size:40px
}

View File

@ -0,0 +1,5 @@
<div>
<slot>
<text>default content form part1</text>
</slot>
</div>

View File

@ -0,0 +1,14 @@
export default {
props:{
title: {
default: "title"
}
},
data: {
show: false,
},
textClicked () {
this.$emit('textClicked');
this.show = !this.show;
},
}

View File

@ -0,0 +1,20 @@
{
"appID": "com.example.ace.helloworld",
"appName": "HelloAce",
"versionName": "1.0.0",
"versionCode": 1,
"minPlatformVersion": "1.0.1",
"pages": [
"pages/for/for",
"pages/element/element",
"pages/pseudoclasses/pseudoclasses",
"pages/selector/selector",
"pages/amimation/amimation",
"pages/transition/transition",
"pages/gradient/gradient"
],
"window": {
"designWidth": 720,
"autoDesignWidth": false
}
}

View File

@ -0,0 +1,43 @@
.container {
justify-content: center;
align-items: center;
}
.title {
font-size: 50px;
}
.button-div {
padding-top: 50px;
align-items: center;
justify-content: center;
}
.text-div {
align-items: center;
justify-content: center;
}
.button {
font-size: 30px;
}
.animate {
transform-origin: 20% 40%;
transform: translate(0px) ;
animation-name: myfirst;
animation-delay: 2s;
animation-duration: 5s;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-fill-mode: none;
}
@keyframes Go
{
from {
transform:translate(0px) rotate(0deg) scale(1.0);
}
to {
transform-style:translate(100px) rotate(180deg) scale(2.0);
}
}

View File

@ -0,0 +1,8 @@
<div class="container">
<div class="text-div animate">
<text class="title">amimation_test</text>
</div>
<div class="button-div">
<input type="button" value="Go to the second page" class="button" onclick="launch"/>
</div>
</div>

View File

@ -0,0 +1,7 @@
<element name='comp' src='../../common/component/comp'></element>
<div class="container">
<div class="text-div">
<text class="title">element_test</text>
</div>
<comp @textClicked="textClicked"></comp>
</div>

View File

@ -0,0 +1,17 @@
.container {
justify-content: center;
align-items: center;
}
.title {
font-size: 50px;
}
.text-div {
align-items: center;
justify-content: center;
}
.button {
font-size: 30px;
}

View File

@ -0,0 +1,15 @@
<div class="container">
<div class="text-div">
<text class="title">for列表渲染.</text>
</div>
<div for="{{array}}" tid="id">
<text>{{$idx}}.{{$item.name}}</text>
</div>
<div for="{{value in array}}" tid="id">
<text>{{$idx}}.{{value.name}}</text>
</div>
<div for="{{(i, v) in array}}" tid="id">
<text>{{i}}{{v.name}}</text>
</div>
</div>

View File

@ -0,0 +1,3 @@
.button:active {
background-color: #888888;
}

View File

@ -0,0 +1,8 @@
<div class="container">
<div class="text-div">
<text class="title">pseudoclasses_test</text>
</div>
<div class="button-div">
<input type="button" value="Go to the second page" class="button" onclick="launch"/>
</div>
</div>

View File

@ -0,0 +1,23 @@
div {
flex-direction: column;
}
.title {
font-size: 30px;
}
#contentId {
font-size: 20px;
}
.title, .content {
padding: 5px;
}
.container text {
color: #007dff;
};
.container > text {
color: #fa2a2d;
}

View File

@ -0,0 +1,7 @@
<div id="containerId" class="container">
<text id="titleId" class="title">selector_test</text>
<div class="content">
<text id="contentId">content</text>
</div>
</div>

View File

@ -0,0 +1,22 @@
.a {
shared-transition-effect: exchange;
shared-transition-name: shared-transition;
shared-transition-timing-function: friction;
}
@keyframes shared-transition {
from {
opacity: 0;
transform: translate(0px) rotate(0deg) scale(1.0);
}
to {
opacity: 1;
transform: translate(100px) rotate(180deg) scale(2.0);
}
}
.s{
transition-enter: "translate(100px) rotate(180deg) scale(2.0)";
transition-exit: 'translate(100px) rotate(180deg) scale(2.0)';
transition-duration: 100ms;
transition-timing-function: friction
}

Some files were not shown because too many files have changed in this diff Show More