optimize ets-loader.

Signed-off-by: lihong <lihong67@huawei.com>
Change-Id: I9392d2044df4ae051d11b50aa410c8d542c103f0
This commit is contained in:
lihong
2022-03-03 11:42:23 +08:00
parent 62c73bfeec
commit 4d32f98447
25 changed files with 1046 additions and 489 deletions
+11 -1
View File
@@ -143,8 +143,18 @@ ets_loader_sources = [
"compiler/webpack.config.js",
]
ohos_copy("copy_deps") {
sources =
[ "//third_party/typescript/build_package/ohos-typescript-4.2.3-r2.tgz" ]
outputs = [ target_out_dir + "/ets_loader/deps/{{source_file_part}}" ]
license_file = "//third_party/typescript/LICENSE"
}
ohos_copy("ets_loader") {
deps = [ ":build_ets_loader_library" ]
deps = [
":build_ets_loader_library",
":copy_deps",
]
sources = ets_loader_sources
deps += [ ":build_ets_sysResource" ]
sources += [ ets_sysResource ]
+1 -1
View File
@@ -16,7 +16,7 @@
module.exports = function(api) {
api.cache(true);
const presets = ['@babel/preset-env', '@babel/typescript'];
const presets = ['@babel/typescript'];
const plugins = [
'@babel/plugin-transform-modules-commonjs',
'@babel/plugin-proposal-class-properties',
-2
View File
@@ -61,8 +61,6 @@ function generateTargetFile(filePath, output) {
const fileName = path.resolve(output, path.basename(item));
if (item === globalTsFile) {
content = license + '\n\n' + processsFile(content, fileName, true);
} else if (path.resolve(item) !== middleTsFile) {
content = license + '\n\n' + processsFile(content, fileName, false);
}
fs.writeFile(fileName, content, err => {
if (err) {
+1
View File
@@ -0,0 +1 @@
../../../../third_party/typescript/build_package/ohos-typescript-4.2.3-r2.tgz
+2 -3
View File
@@ -4073,9 +4073,8 @@
"dev": true
},
"typescript": {
"version": "4.5.4",
"resolved": "https://registry.npmmirror.com/typescript/download/typescript-4.5.4.tgz",
"integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg=="
"version": "file:deps/ohos-typescript-4.2.3-r2.tgz",
"integrity": "sha512-a94p5mnxZMe9sJebu6gw2ixGaVGuKo7H3fU+Vd+VrogYbRrrCphlrJ2nlZnpm9r0TYe4HwHrmGkeyeJW63XUSA=="
},
"uglify-js": {
"version": "3.14.5",
+1 -1
View File
@@ -42,7 +42,7 @@
"log4js": "^6.3.0",
"md5": "^2.3.0",
"ts-loader": "^8.0.12",
"typescript": "^4.1.3",
"typescript": "file:./deps/ohos-typescript-4.2.3-r2.tgz",
"webpack": "^5.48.0",
"webpack-cli": "^4.2.0",
"ws": "^8.3.0"
+47 -39
View File
@@ -13,6 +13,7 @@
* limitations under the License.
*/
import * as ts from 'typescript';
import Stats from 'webpack/lib/Stats';
import Compiler from 'webpack/lib/Compiler';
import Compilation from 'webpack/lib/Compilation';
@@ -27,23 +28,18 @@ import fs from 'fs';
import CachedSource from 'webpack-sources/lib/CachedSource';
import ConcatSource from 'webpack-sources/lib/ConcatSource';
import {
BUILDIN_STYLE_NAMES,
EXTEND_ATTRIBUTE,
STYLES_ATTRIBUTE
} from './component_map';
import { transformLog } from './process_ui_syntax';
import {
dollarCollection,
componentCollection,
moduleCollection
} from './validate_ui_syntax';
import { decoratorParamSet } from './process_component_member';
import { appComponentCollection } from './process_component_build';
import { moduleCollection } from './validate_ui_syntax';
import { projectConfig } from '../main';
import { circularFile } from './utils';
import { MODULE_SHARE_PATH, BUILD_SHARE_PATH } from './pre_define';
import { COMMON_ATTRS } from './component_map';
import {
createLanguageService,
dollarCollection,
appComponentCollection,
decoratorParamsCollection,
extendCollection
} from './ets_checker';
configure({
appenders: { 'ETS': {type: 'stderr', layout: {type: 'messagePassThrough'}}},
@@ -78,7 +74,7 @@ export class ResultStates {
compiler.hooks.compilation.tap('SourcemapFixer', compilation => {
compilation.hooks.afterProcessAssets.tap('SourcemapFixer', assets => {
Reflect.ownKeys(assets).forEach(key => {
if (/\.map$/.test(key.toString())) {
if (/\.map$/.test(key.toString()) && assets[key]._value) {
assets[key]._value = assets[key]._value.toString().replace('.ets?entry', '.ets');
}
});
@@ -146,17 +142,45 @@ export class ResultStates {
});
});
compiler.hooks.run.tapPromise('CheckSyntax', async(compiler) => {
const rootFileNames: string[] = [];
Object.values(projectConfig.entryObj).forEach((fileName: string) => {
rootFileNames.push(fileName.replace('?entry', ''));
});
const languageService: ts.LanguageService = createLanguageService(rootFileNames);
const rootProgram: ts.Program = languageService.getProgram();
props.push(...dollarCollection, ...decoratorParamsCollection, ...extendCollection);
let allDiagnostics: ts.Diagnostic[] = rootProgram
.getSyntacticDiagnostics()
.concat(rootProgram.getSemanticDiagnostics())
.concat(rootProgram.getDeclarationDiagnostics());
allDiagnostics = allDiagnostics.filter((item) => {
return this.validateError(ts.flattenDiagnosticMessageText(item.messageText, '\n'));
});
this.mErrorCount += allDiagnostics.length;
allDiagnostics.forEach((diagnostic: ts.Diagnostic) => {
const message: string = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
if (diagnostic.file) {
const { line, character }: ts.LineAndCharacter =
diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
logger.error(this.red,
`ETS:ERROR File: ${diagnostic.file.fileName}:${line + 1}:${character + 1}\n ${message}\n`);
} else {
logger.error(this.red, `ETS:ERROR: ${message}`);
}
});
});
compiler.hooks.done.tap('Result States', (stats: Stats) => {
this.mStats = stats;
this.warningCount = 0;
this.noteCount = 0;
if (this.mStats.compilation.errors) {
this.mErrorCount = this.mStats.compilation.errors.length;
this.mErrorCount += this.mStats.compilation.errors.length;
}
if (this.mStats.compilation.warnings) {
this.mWarningCount = this.mStats.compilation.warnings.length;
}
props.push(...dollarCollection, ...decoratorParamSet, ...BUILDIN_STYLE_NAMES);
this.printResult();
});
@@ -261,41 +285,25 @@ export class ResultStates {
}
private validateError(message: string): boolean {
const propInfoReg: RegExp = /Cannot find name\s*'(\$?\$?[_a-zA-Z0-9]+)'/;
const componentNameReg: RegExp = /'typeof\s*(\$?[_a-zA-Z0-9]+)' is not callable/;
const stateInfoReg: RegExp = /Property\s*'(\$[_a-zA-Z0-9]+)' does not exist on type/;
const extendInfoReg: RegExp =
/Property\s*'([_a-zA-Z0-9]+)' does not exist on type\s*'([_a-zA-Z0-9]+)(Attribute|Interface)'\./;
if (this.matchMessage(message, props.concat([...STYLES_ATTRIBUTE]), propInfoReg) ||
this.matchMessage(message, [...componentCollection.customComponents], componentNameReg) ||
this.matchMessage(message, props, stateInfoReg) ||
this.matchMessage(message, EXTEND_ATTRIBUTE, extendInfoReg, true) ||
this.matchMessage(message, [...STYLES_ATTRIBUTE, ...COMMON_ATTRS], extendInfoReg)) {
const stateInfoReg: RegExp = /Property\s*'(\$?[_a-zA-Z0-9]+)' does not exist on type/;
if (this.matchMessage(message, props, propInfoReg) ||
this.matchMessage(message, props, stateInfoReg)) {
return false;
}
return true;
}
private matchMessage(message: string, nameArr: any, reg: RegExp,
validateComponent: boolean = false): boolean {
private matchMessage(message: string, nameArr: any, reg: RegExp): boolean {
if (reg.test(message)) {
const match: string[] = message.match(reg);
if (validateComponent) {
if (match[1] && match[2] && nameArr.has(match[2])) {
const attributeArray: string[] = [...nameArr.get(match[2])].map(item => item.attribute);
if (attributeArray.includes(match[1])) {
return true;
}
}
} else {
if (match[1] && nameArr.includes(match[1])) {
return true;
}
if (match[1] && nameArr.includes(match[1])) {
return true;
}
}
return false;
}
private filterModuleError(message: string): string {
if (/You may need an additional loader/.test(message) && transformLog && transformLog.sourceFile) {
const fileName: string = transformLog.sourceFile.fileName.replace(/.ts$/, '');
const fileName: string = transformLog.sourceFile.fileName;
const errorInfos: string[] = message.split('You may need an additional loader to handle the result of these loaders.');
if (errorInfos && errorInfos.length > 1 && errorInfos[1]) {
message = `ERROR in ${fileName}\n The following syntax is incorrect.${errorInfos[1]}`;
+2 -2
View File
@@ -75,13 +75,13 @@ export interface ExtendParamterInterfance {
attribute: string,
parameterCount: number
}
export const EXTEND_ATTRIBUTE: Map<string, Set<ExtendParamterInterfance>> = new Map();
export const EXTEND_ATTRIBUTE: Map<string, Set<string>> = new Map();
export const STYLES_ATTRIBUTE: Set<string> = new Set();
export const INTERFACE_NODE_SET: Set<ts.InterfaceDeclaration> = new Set();
export const JS_BIND_COMPONENTS: Set<string> = new Set([
...GESTURE_TYPE_NAMES, 'Gesture',
'ForEach', 'LazyForEach', ...GESTURE_TYPE_NAMES, 'Gesture',
'PanGestureOption', 'CustomDialogController', 'Storage', 'Scroller', 'SwiperController',
'TabsController', 'CalendarController', 'AbilityController', 'VideoController', 'WebController',
'XComponentController', 'CanvasRenderingContext2D', 'CanvasGradient', 'ImageBitmap', 'ImageData',
+208
View File
@@ -0,0 +1,208 @@
/*
* Copyright (c) 2022 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 fs from 'fs';
import path from 'path';
import * as ts from 'typescript';
import { projectConfig } from '../main';
import {
processSystemApi,
preprocessExtend
} from './validate_ui_syntax';
import {
INNER_COMPONENT_MEMBER_DECORATORS,
COMPONENT_IF,
COMPONENT_DECORATORS_PARAMS
} from './pre_define';
import { JS_BIND_COMPONENTS } from './component_map';
function readDeaclareFiles(): string[] {
const declarationsFileNames: string[] = [];
fs.readdirSync(path.resolve(__dirname, '../declarations'))
.forEach((fileName: string) => {
if (/\.d\.ts$/.test(fileName)) {
declarationsFileNames.push(path.resolve(__dirname, '../declarations', fileName));
}
});
return declarationsFileNames;
}
export function createLanguageService(rootFileNames: string[]): ts.LanguageService {
const compilerOptions: ts.CompilerOptions = ts.readConfigFile(
path.resolve(__dirname, '../tsconfig.json'), ts.sys.readFile).config.compilerOptions;
Object.assign(compilerOptions, {
'moduleResolution': ts.ModuleResolutionKind.NodeJs,
'target': ts.ScriptTarget.ES2017,
'baseUrl': path.resolve(projectConfig.projectPath),
'paths': {
'*': [
'*',
'../../../../../*'
]
},
'lib': [
'lib.es2020.d.ts'
]
});
const files: ts.MapLike<{ version: number }> = {};
const servicesHost: ts.LanguageServiceHost = {
getScriptFileNames: () => [...rootFileNames, ...readDeaclareFiles()],
getScriptVersion: fileName =>
files[fileName] && files[fileName].version.toString(),
getScriptSnapshot: fileName => {
if (!fs.existsSync(fileName)) {
return undefined;
}
if (/(?<!\.d)\.(ets|ts)$/.test(fileName)) {
checkUISyntax(fs.readFileSync(fileName).toString(), fileName);
return ts.ScriptSnapshot.fromString(processContent(fs.readFileSync(fileName).toString()));
}
return ts.ScriptSnapshot.fromString(fs.readFileSync(fileName).toString());
},
getCurrentDirectory: () => process.cwd(),
getCompilationSettings: () => compilerOptions,
getDefaultLibFileName: options => ts.getDefaultLibFilePath(options),
fileExists: ts.sys.fileExists,
readFile: ts.sys.readFile,
readDirectory: ts.sys.readDirectory,
resolveModuleNames(moduleNames: string[], containingFile: string): ts.ResolvedModuleFull[] {
const resolvedModules: ts.ResolvedModuleFull[] = [];
for (const moduleName of moduleNames) {
const result = ts.resolveModuleName(moduleName, containingFile, compilerOptions, {
fileExists(fileName: string): boolean {
return ts.sys.fileExists(fileName);
},
readFile(fileName: string): string | undefined {
return ts.sys.readFile(fileName);
}
});
if (result.resolvedModule) {
resolvedModules.push(result.resolvedModule);
} else if (/^@(system|ohos)/.test(moduleName.trim())) {
const modulePath: string = path.resolve(__dirname, '../../../api', moduleName + '.d.ts');
if (ts.sys.fileExists(modulePath)) {
resolvedModules.push(getResolveModule(modulePath, '.d.ts'));
}
} else if (/\.ets$/.test(moduleName)) {
const modulePath: string = path.resolve(path.dirname(containingFile), moduleName);
if (ts.sys.fileExists(modulePath)) {
resolvedModules.push(getResolveModule(modulePath, '.ets'));
}
} else if (/\.ts$/.test(moduleName)) {
const modulePath: string = path.resolve(path.dirname(containingFile), moduleName);
if (ts.sys.fileExists(modulePath)) {
resolvedModules.push(getResolveModule(modulePath, '.ts'));
}
}
}
if (moduleNames.length !== resolvedModules.length) {
const length: number = moduleNames.length - resolvedModules.length;
for (let i = 0; i < length; i++) {
resolvedModules.push(null);
}
}
return resolvedModules;
},
directoryExists: ts.sys.directoryExists,
getDirectories: ts.sys.getDirectories
};
return ts.createLanguageService(servicesHost, ts.createDocumentRegistry());
}
function getResolveModule(modulePath: string, type): ts.ResolvedModuleFull {
return {
resolvedFileName: modulePath,
isExternalLibraryImport: false,
extension: type
};
}
export const dollarCollection: Set<string> = new Set();
export const appComponentCollection: Set<string> = new Set();
export const decoratorParamsCollection: Set<string> = new Set();
export const extendCollection: Set<string> = new Set();
function checkUISyntax(source: string, fileName: string): void {
if (/\.ets$/.test(fileName)) {
if (path.basename(fileName) !== 'app.ets') {
const sourceFile: ts.SourceFile = ts.createSourceFile(fileName, source,
ts.ScriptTarget.Latest, true, ts.ScriptKind.ETS);
collectComponents(sourceFile);
parseAllNode(sourceFile, sourceFile);
}
}
}
function collectComponents(node: ts.SourceFile): void {
// @ts-ignore
if (node.identifiers && node.identifiers.size) {
// @ts-ignore
for (const key of node.identifiers.keys()) {
if (JS_BIND_COMPONENTS.has(key)) {
appComponentCollection.add(key);
}
}
}
}
function parseAllNode(node: ts.Node, sourceFileNode: ts.SourceFile): void {
if (ts.isStructDeclaration(node)) {
if (node.members) {
node.members.forEach(item => {
if (ts.isPropertyDeclaration(item) && ts.isIdentifier(item.name)) {
const propertyName: string = item.name.getText();
if (item.decorators && item.decorators.length) {
for (let i = 0; i < item.decorators.length; i++) {
const decoratorName: string = item.decorators[i].getText().replace(/\(.*\)$/, '').trim();
if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName)) {
dollarCollection.add('$' + propertyName);
}
if (isDecoratorCollection(item.decorators[i], decoratorName)) {
decoratorParamsCollection.add(item.decorators[i].expression.arguments[0].getText());
}
}
}
}
});
}
}
if (ts.isIfStatement(node)) {
appComponentCollection.add(COMPONENT_IF);
}
node.getChildren().forEach((item: ts.Node) => parseAllNode(item, sourceFileNode));
}
function isDecoratorCollection(item: ts.Decorator, decoratorName: string): boolean {
return COMPONENT_DECORATORS_PARAMS.has(decoratorName) &&
// @ts-ignore
item.expression.arguments && item.expression.arguments.length &&
// @ts-ignore
ts.isIdentifier(item.expression.arguments[0]);
}
function processDraw(source: string): string {
const reg: RegExp = /new\s+\b(Circle|Ellipse|Rect|Path)\b/g;
return source.replace(reg, (item:string, item1: string) => {
return '\xa0'.repeat(item.length - item1.length) + item1;
});
}
function processContent(source: string): string {
source = processSystemApi(source);
source = preprocessExtend(source, extendCollection);
source = processDraw(source);
return source;
}
+6
View File
@@ -38,6 +38,9 @@ export const COMPONENT_OBJECT_LINK_DECORATOR: string = '@ObjectLink';
export const COMPONENT_WATCH_DECORATOR: string = '@Watch';
export const COMPONENT_BUILDERPARAM_DECORATOR: string = '@BuilderParam';
export const COMPONENT_DECORATORS_PARAMS: Set<string> = new Set([COMPONENT_CONSUME_DECORATOR,
COMPONENT_STORAGE_PROP_DECORATOR, COMPONENT_STORAGE_LINK_DECORATOR, COMPONENT_PROVIDE_DECORATOR,
COMPONENT_WATCH_DECORATOR]);
export const INNER_COMPONENT_DECORATORS: Set<string> = new Set([COMPONENT_DECORATOR_ENTRY,
COMPONENT_DECORATOR_PREVIEW, COMPONENT_DECORATOR_COMPONENT, COMPONENT_DECORATOR_CUSTOM_DIALOG]);
export const INNER_COMPONENT_MEMBER_DECORATORS: Set<string> = new Set([COMPONENT_STATE_DECORATOR,
@@ -49,6 +52,7 @@ export const COMPONENT_OBSERVED_DECORATOR: string = '@Observed';
export const COMPONENT_BUILDER_DECORATOR: string = '@Builder';
export const COMPONENT_EXTEND_DECORATOR: string = '@Extend';
export const COMPONENT_STYLES_DECORATOR: string = '@Styles';
export const CHECK_COMPONENT_EXTEND_DECORATOR: string = 'Extend';
export const OBSERVED_PROPERTY_SIMPLE: string = 'ObservedPropertySimple';
export const OBSERVED_PROPERTY_OBJECT: string = 'ObservedPropertyObject';
@@ -202,3 +206,5 @@ export const OBSERVED_PROPERTY_ABSTRACT:string = 'ObservedPropertyAbstract';
export const SUPERVISUAL: string = './supervisual';
export const SUPERVISUAL_SOURCEMAP_EXT: string = '.visual.js.map';
export const INSTANCE: string = 'Instance';
+2 -2
View File
@@ -150,8 +150,8 @@ function insertImport(visualContent: any, content: string): string {
function insertVarAndFunc(build: ts.MethodDeclaration, visualContent: any,
content: string, oriContent: string): string {
const visualVarAndFunc: string = (visualContent.etsVariable ?? '') +
(visualContent.etsFunction ?? '');
const visualVarAndFunc: string = (visualContent.etsVariable ? visualContent.etsVariable : '') +
(visualContent.etsFunction ? visualContent.etsFunction : '');
return visualVarAndFunc ? insertVisualCodeBeforePos(build, '\n' + visualVarAndFunc, content,
oriContent) : content;
}
+97 -97
View File
@@ -88,8 +88,6 @@ import { projectConfig } from '../main';
import { transformLog, contextGlobal } from './process_ui_syntax';
import { props } from './compile_info';
export const appComponentCollection: Set<string> = new Set();
export function processComponentBuild(node: ts.MethodDeclaration,
log: LogInfo[]): ts.MethodDeclaration {
let newNode: ts.MethodDeclaration;
@@ -130,27 +128,15 @@ export function processComponentBlock(node: ts.Block, isLazy: boolean, log: LogI
function validateRootNode(node: ts.MethodDeclaration, log: LogInfo[]): boolean {
let isValid: boolean = false;
if (node.body.statements.length < 4) {
switch (node.body.statements.length) {
case 1:
if (validateFirstNode(node.body.statements[0])) {
isValid = true;
}
break;
case 2:
if (validateFirstNode(node.body.statements[0]) &&
validateBlockNode(node.body.statements[1])) {
isValid = true;
}
break;
case 3:
if (validateFirstNode(node.body.statements[0]) &&
validateBlockNode(node.body.statements[1]) &&
validateSecondNode(node.body.statements[2])) {
isValid = true;
}
break;
if (node.body.statements.length === 1) {
const statement: ts.Node = node.body.statements[0];
if (ts.isIfStatement(statement) || ts.isExpressionStatement(statement) && statement.expression &&
(ts.isEtsComponentExpression(statement.expression) || ts.isCallExpression(statement.expression)) &&
validateEtsComponentNode(statement.expression)) {
isValid = true;
}
} else {
isValid = false;
}
if (!isValid) {
log.push({
@@ -174,6 +160,19 @@ let newsupplement: supplementType = {
column: 0
};
function validateEtsComponentNode(node: ts.CallExpression | ts.EtsComponentExpression) {
let childNode: ts.Node = node;
while (ts.isCallExpression(childNode) && childNode.expression &&
ts.isPropertyAccessExpression(childNode.expression) && childNode.expression.expression) {
childNode = childNode.expression.expression;
}
if (ts.isEtsComponentExpression(childNode)) {
return true;
} else {
return false;
}
}
export function processComponentChild(node: ts.Block | ts.SourceFile, newStatements: ts.Statement[],
log: LogInfo[], supplement: supplementType = {isAcceleratePreview: false, line: 0, column: 0}): void {
if (supplement.isAcceleratePreview) {
@@ -189,9 +188,9 @@ export function processComponentChild(node: ts.Block | ts.SourceFile, newStateme
newStatements, log, name);
break;
case ComponentType.customComponent:
if (index + 1 < array.length && ts.isBlock(array[index + 1])) {
if (processExpressionStatementChange(item, array[index + 1] as ts.Block, log)) {
item = processExpressionStatementChange(item, array[index + 1] as ts.Block, log);
if (item.expression && ts.isEtsComponentExpression(item.expression) && item.expression.body) {
if (processExpressionStatementChange(item, item.expression.body, log)) {
item = processExpressionStatementChange(item, item.expression.body, log);
}
}
processCustomComponent(item as ts.ExpressionStatement, newStatements, log);
@@ -205,7 +204,6 @@ export function processComponentChild(node: ts.Block | ts.SourceFile, newStateme
break;
}
} else if (ts.isIfStatement(item)) {
appComponentCollection.add(COMPONENT_IF);
processIfStatement(item, newStatements, log);
} else if (!ts.isBlock(item)) {
log.push({
@@ -262,6 +260,28 @@ function processBlockToExpression(node: ts.ExpressionStatement, nextNode: ts.Blo
return node;
}
type EtsComponentResult = {
etsComponentNode: ts.EtsComponentExpression;
hasAttr: boolean;
}
function parseEtsComponentExpression(node: ts.ExpressionStatement): EtsComponentResult {
let etsComponentNode: ts.EtsComponentExpression;
let hasAttr: boolean = false;
let temp: any = node.expression;
while (temp) {
if (ts.isCallExpression(temp) && temp.expression &&
ts.isPropertyAccessExpression(temp.expression)) {
hasAttr = true;
}
if (ts.isEtsComponentExpression(temp)) {
etsComponentNode = temp;
break;
}
temp = temp.expression;
}
return { etsComponentNode: etsComponentNode, hasAttr: hasAttr };
}
function processInnerComponent(node: ts.ExpressionStatement, index: number, arr: ts.Statement[],
newStatements: ts.Statement[], log: LogInfo[], name: string): void {
const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION);
@@ -293,7 +313,8 @@ function processInnerComponent(node: ts.ExpressionStatement, index: number, arr:
ts.factory.createNodeArray([ts.factory.createStringLiteral(debugInfo)])));
newStatements.push(debugNode);
}
if (index + 1 < arr.length && ts.isBlock(arr[index + 1])) {
const etsComponentResult: EtsComponentResult = parseEtsComponentExpression(node);
if (etsComponentResult.etsComponentNode.body && ts.isBlock(etsComponentResult.etsComponentNode.body)) {
if (res.isButton) {
if (projectConfig.isPreview) {
newStatements.splice(-2, 1, createComponent(node, COMPONENT_CREATE_CHILD_FUNCTION).newNode);
@@ -301,11 +322,10 @@ function processInnerComponent(node: ts.ExpressionStatement, index: number, arr:
newStatements.splice(-1, 1, createComponent(node, COMPONENT_CREATE_CHILD_FUNCTION).newNode);
}
}
if (index + 2 < arr.length && ts.isExpressionStatement(arr[index + 2]) &&
isAttributeNode(arr[index + 2] as ts.ExpressionStatement)) {
bindComponentAttr(arr[index + 2] as ts.ExpressionStatement, res.identifierNode, newStatements, log);
if (etsComponentResult.hasAttr) {
bindComponentAttr(node, res.identifierNode, newStatements, log);
}
processComponentChild(arr[index + 1] as ts.Block, newStatements, log);
processComponentChild(etsComponentResult.etsComponentNode.body, newStatements, log);
} else {
bindComponentAttr(node, res.identifierNode, newStatements, log);
}
@@ -516,7 +536,8 @@ function createComponent(node: ts.ExpressionStatement, type: string): CreateResu
while (temp && !ts.isIdentifier(temp) && temp.expression) {
temp = temp.expression;
}
if (temp && temp.parent && ts.isCallExpression(temp.parent) && ts.isIdentifier(temp)) {
if (temp && temp.parent && (ts.isCallExpression(temp.parent) ||
ts.isEtsComponentExpression(temp.parent)) && ts.isIdentifier(temp)) {
if (temp.getText() === COMPONENT_BUTTON && type !== COMPONENT_POP_FUNCTION) {
res.isButton = true;
identifierNode = type === COMPONENT_CREATE_CHILD_FUNCTION
@@ -837,7 +858,6 @@ function addComponentAttr(temp: any, node: ts.Identifier, lastStatement: any,
parseGesture(temp, propName, statements, log);
lastStatement.kind = true;
} else if (isExtendFunctionNode(identifierNode, propName)) {
validateExtendParameterCount(temp, identifierNode, propName, log);
statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression(
ts.factory.createIdentifier(`__${identifierNode.escapedText.toString()}__${propName}`),
undefined, temp.arguments)));
@@ -873,18 +893,36 @@ function addComponentAttr(temp: any, node: ts.Identifier, lastStatement: any,
if (!COMMON_ATTRS.has(propName)) {
validateStateStyleSyntax(temp, log);
}
if (isGlobalStyles) {
for (let i = 0; i < temp.arguments.length; i++) {
temp.arguments[i] = traverseStylesAttr(temp.arguments[i]);
}
}
}
temp = loopEtsComponent(temp, isStylesAttr, isGlobalStyles);
statements.push(ts.factory.createExpressionStatement(
createFunction(identifierNode, node, temp.arguments)));
lastStatement.kind = true;
}
}
function loopEtsComponent(temp: any, isStylesAttr: boolean, isGlobalStyles: boolean): ts.Node {
temp.arguments.forEach((item: ts.Node, index: number) => {
if (isStylesAttr && isGlobalStyles) {
temp.arguments[index] = traverseStylesAttr(item);
}
if (ts.isNewExpression(item) && item.expression && ts.isEtsComponentExpression(
item.expression)) {
temp.arguments[index] = ts.factory.updateNewExpression(item, item.expression.expression,
undefined, item.expression.arguments);
} else if (ts.isEtsComponentExpression(item)) {
temp.arguments[index] = ts.factory.createCallExpression(item.expression,
undefined, item.arguments);
} else if ((ts.isCallExpression(item) || ts.isNewExpression(item)) && item.expression &&
ts.isPropertyAccessExpression(item.expression) && item.expression.expression &&
ts.isEtsComponentExpression(item.expression.expression)) {
temp.arguments[index].expression.expression = ts.factory.createCallExpression(
item.expression.expression.expression, undefined, item.expression.expression.arguments);
}
});
return temp;
}
function classifyArgumentsNum(args: any, argumentsArr: ts.Expression[], propName: string,
identifierNode: ts.Identifier): void {
if (propName === BIND_POPUP && args.length === 2) {
@@ -967,7 +1005,7 @@ function traverseStateStylesAttr(temp: any, statements: ts.Statement[],
function isExtendFunctionNode(identifierNode: ts.Identifier, propName: string): boolean {
if (identifierNode && EXTEND_ATTRIBUTE.has(identifierNode.escapedText.toString())) {
const attributeArray: string[] =
[...EXTEND_ATTRIBUTE.get(identifierNode.escapedText.toString())].map(item => item.attribute);
[...EXTEND_ATTRIBUTE.get(identifierNode.escapedText.toString())];
if (attributeArray.includes(propName)) {
return true;
}
@@ -1053,7 +1091,8 @@ export function getName(node: ts.ExpressionStatement): string {
let temp: any = node.expression;
let name: string;
while (temp) {
if (ts.isIdentifier(temp) && temp.parent && ts.isCallExpression(temp.parent)) {
if (ts.isIdentifier(temp) && temp.parent && (ts.isCallExpression(temp.parent) ||
ts.isEtsComponentExpression(temp.parent))) {
name = temp.escapedText.toString();
break;
} else if (ts.isPropertyAccessExpression(temp) && temp.name && ts.isIdentifier(temp.name) &&
@@ -1079,46 +1118,6 @@ export function isAttributeNode(node: ts.ExpressionStatement): boolean {
return BUILDIN_STYLE_NAMES.has(name);
}
function validateFirstNode(node: ts.Statement): boolean {
const isEntryComponent: boolean =
componentCollection.entryComponent === componentCollection.currentClassName;
if (isEntryComponent && validateEntryComponent(node) ||
!isEntryComponent && validateCustomComponent(node)) {
return true;
}
return false;
}
function validateEntryComponent(node: ts.Statement): boolean {
if (ts.isExpressionStatement(node) && BUILDIN_CONTAINER_COMPONENT.has(getName(node))) {
return true;
}
return false;
}
function validateCustomComponent(node: ts.Statement): boolean {
if (ts.isIfStatement(node) ||
ts.isExpressionStatement(node) && (INNER_COMPONENT_NAMES.has(getName(node)) ||
componentCollection.customComponents.has(getName(node)))) {
return true;
}
return false;
}
function validateBlockNode(node: ts.Statement): boolean {
if (ts.isBlock(node)) {
return true;
}
return false;
}
function validateSecondNode(node: ts.Statement): boolean {
if (ts.isExpressionStatement(node) && isAttributeNode(node)) {
return true;
}
return false;
}
enum ComponentType {
innerComponent,
customComponent,
@@ -1127,14 +1126,29 @@ enum ComponentType {
builderParamMethod
}
function isEtsComponent(node: ts.ExpressionStatement): boolean {
let isEtsComponent: boolean = false;
let temp: any = node.expression;
while (temp) {
if (ts.isEtsComponentExpression(temp)) {
isEtsComponent = true;
}
temp = temp.expression;
}
return isEtsComponent;
}
function getComponentType(node: ts.ExpressionStatement, log: LogInfo[],
name: string): ComponentType {
if (INNER_COMPONENT_NAMES.has(name)) {
return ComponentType.innerComponent;
if (isEtsComponent(node)) {
if (componentCollection.customComponents.has(name)) {
return ComponentType.customComponent;
} else {
return ComponentType.innerComponent;
}
} else if (componentCollection.customComponents.has(name)) {
return ComponentType.customComponent;
} else if (name === COMPONENT_FOREACH || name === COMPONENT_LAZYFOREACH) {
appComponentCollection.add(name);
return ComponentType.forEachComponent;
} else if (CUSTOM_BUILDER_METHOD.has(name)) {
return ComponentType.customBuilderMethod;
@@ -1151,20 +1165,6 @@ function getComponentType(node: ts.ExpressionStatement, log: LogInfo[],
return null;
}
function validateExtendParameterCount(temp: any, identifierNode: ts.Identifier, propName: string,
log: LogInfo[]): void {
const parameterCount: number =
[...EXTEND_ATTRIBUTE.get(identifierNode.escapedText.toString())].filter(item =>
item.attribute === propName)[0].parameterCount;
if (temp.arguments && temp.arguments.length !== parameterCount) {
log.push({
type: LogType.ERROR,
message: `The '${propName}' is expected ${parameterCount} arguments, but got ${temp.arguments.length}.`,
pos: temp.getStart()
});
}
}
export function validateStateStyleSyntax(temp: any, log: LogInfo[]): void {
log.push({
type: LogType.ERROR,
+4 -6
View File
@@ -31,8 +31,6 @@ import {
OBSERVED_PROPERTY_SIMPLE,
COMPONENT_BUILD_FUNCTION,
BASE_COMPONENT_NAME,
ATTRIBUTE_ANIMATETO,
GLOBAL_CONTEXT,
CREATE_CONSTRUCTOR_PARAMS,
COMPONENT_CONSTRUCTOR_UPDATE_PARAMS,
COMPONENT_CONSTRUCTOR_DELETE_PARAMS,
@@ -86,12 +84,12 @@ import {
hasDecorator
} from './utils';
export function processComponentClass(node: ts.ClassDeclaration, context: ts.TransformationContext,
export function processComponentClass(node: ts.StructDeclaration, context: ts.TransformationContext,
log: LogInfo[], program: ts.Program): ts.ClassDeclaration {
validateInheritClass(node, log);
const memberNode: ts.ClassElement[] =
processMembers(node.members, node.name, context, log, program, checkPreview(node));
return ts.factory.updateClassDeclaration(node, undefined, node.modifiers, node.name,
return ts.factory.createClassDeclaration(undefined, node.modifiers, node.name,
node.typeParameters, updateHeritageClauses(node), memberNode);
}
@@ -335,7 +333,7 @@ function getGeometryReaderFunctionBlock(node: ts.ArrowFunction | ts.FunctionExpr
return processComponentBlock(blockNode, false, log);
}
function updateHeritageClauses(node: ts.ClassDeclaration): ts.NodeArray<ts.HeritageClause> {
function updateHeritageClauses(node: ts.StructDeclaration): ts.NodeArray<ts.HeritageClause> {
const result:ts.HeritageClause[] = [];
const heritageClause:ts.HeritageClause = ts.factory.createHeritageClause(
ts.SyntaxKind.ExtendsKeyword,
@@ -482,7 +480,7 @@ function validateBuildMethodCount(buildCount: BuildCount, parentComponentName: t
}
}
function validateInheritClass(node: ts.ClassDeclaration, log: LogInfo[]): void {
function validateInheritClass(node: ts.StructDeclaration, log: LogInfo[]): void {
if (node.heritageClauses) {
log.push({
type: LogType.ERROR,
+21 -41
View File
@@ -20,9 +20,7 @@ import {
COMPONENT_CONSTRUCTOR_PARENT,
COMPONENT_CONSTRUCTOR_PARAMS,
COMPONENT_CONSTRUCTOR_UPDATE_PARAMS,
COMPONENT_WATCH_FUNCTION,
BASE_COMPONENT_NAME,
INTERFACE_NAME_SUFFIX
COMPONENT_WATCH_FUNCTION
} from './pre_define';
export function getInitConstructor(members: ts.NodeArray<ts.Node>): ts.ConstructorDeclaration {
@@ -32,12 +30,11 @@ export function getInitConstructor(members: ts.NodeArray<ts.Node>): ts.Construct
if (ctorNode) {
ctorNode = updateConstructor(ctorNode, [], [], true);
}
return ctorNode;
return initConstructorParams(ctorNode);
}
export function updateConstructor(ctorNode: ts.ConstructorDeclaration,
para: ts.ParameterDeclaration[], addStatements: ts.Statement[],
isSuper: boolean = false, isAdd: boolean = false, parentComponentName?: ts.Identifier):
para: ts.ParameterDeclaration[], addStatements: ts.Statement[], isSuper: boolean = false):
ts.ConstructorDeclaration {
let modifyPara: ts.ParameterDeclaration[];
if (para && para.length) {
@@ -58,46 +55,29 @@ export function updateConstructor(ctorNode: ts.ConstructorDeclaration,
}
}
if (ctorNode) {
let ctorPara: ts.ParameterDeclaration[] | ts.NodeArray<ts.ParameterDeclaration> =
modifyPara || ctorNode.parameters;
if (isAdd) {
ctorPara = addParamsType(ctorNode, modifyPara, parentComponentName);
}
ctorNode = ts.factory.updateConstructorDeclaration(ctorNode, ctorNode.decorators,
ctorNode.modifiers, ctorPara, ts.factory.createBlock(modifyBody || ctorNode.body.statements, true));
ctorNode.modifiers, modifyPara || ctorNode.parameters,
ts.factory.createBlock(modifyBody || ctorNode.body.statements, true));
}
return ctorNode;
}
function addParamsType(ctorNode: ts.ConstructorDeclaration, modifyPara: ts.ParameterDeclaration[],
parentComponentName: ts.Identifier): ts.ParameterDeclaration[] {
const tsPara: ts.ParameterDeclaration[] | ts.NodeArray<ts.ParameterDeclaration> =
modifyPara || ctorNode.parameters;
const newTSPara: ts.ParameterDeclaration[] = [];
tsPara.forEach((item) => {
let parameter: ts.ParameterDeclaration = item;
switch (item.getText()) {
case COMPONENT_CONSTRUCTOR_ID + '?':
parameter = ts.factory.updateParameterDeclaration(item, item.decorators, item.modifiers,
item.dotDotDotToken, item.name, item.questionToken,
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), item.initializer);
break;
case COMPONENT_CONSTRUCTOR_PARENT + '?':
parameter = ts.factory.createParameterDeclaration(item.decorators, item.modifiers,
item.dotDotDotToken, item.name, item.questionToken,
ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(BASE_COMPONENT_NAME), undefined),
item.initializer);
break;
case COMPONENT_CONSTRUCTOR_PARAMS + '?':
parameter = ts.factory.updateParameterDeclaration(item, item.decorators, item.modifiers,
item.dotDotDotToken, item.name, item.questionToken,
ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(
parentComponentName.getText() + INTERFACE_NAME_SUFFIX), undefined), item.initializer);
break;
}
newTSPara.push(parameter);
function initConstructorParams(node: ts.ConstructorDeclaration): ts.ConstructorDeclaration {
const paramNames: string[] = [COMPONENT_CONSTRUCTOR_ID, COMPONENT_CONSTRUCTOR_PARENT,
COMPONENT_CONSTRUCTOR_PARAMS];
const newParameters: ts.ParameterDeclaration[] = Array.from(node.parameters);
if (newParameters.length !== 0) {
// @ts-ignore
newParameters.splice(0, newParameters.length);
}
paramNames.forEach((paramName: string) => {
// @ts-ignore
newParameters.push(ts.factory.createParameterDeclaration(undefined, undefined, undefined,
ts.factory.createIdentifier(paramName), undefined, undefined, undefined));
});
return newTSPara;
return ts.factory.updateConstructorDeclaration(node, undefined, node.modifiers, newParameters,
node.body);
}
export function addConstructor(ctorNode: any, watchMap: Map<string, ts.Node>,
@@ -129,5 +109,5 @@ export function addConstructor(ctorNode: any, watchMap: Map<string, ts.Node>,
ts.factory.createThis(), ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS)),
undefined, [ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS)]));
return updateConstructor(updateConstructor(ctorNode, [], [callSuperStatement], true), [],
[updateWithValueParamsStatement, ...watchStatements], false, true, parentComponentName);
[updateWithValueParamsStatement, ...watchStatements], false);
}
+3
View File
@@ -178,6 +178,9 @@ function getCustomComponentName(newNode: ts.NewExpression): string {
}
function getCollectionSet(name: string, collection: Map<string, Set<string>>): Set<string> {
if (!collection) {
return new Set([]);
}
return collection.get(name) || new Set([]);
}
+1 -1
View File
@@ -89,7 +89,7 @@ export default function processImport(node: ts.ImportDeclaration | ts.ImportEqua
fs.readFileSync(fileResolvePath, { encoding: 'utf-8' }).replace(
new RegExp('\\b' + STRUCT + '\\b.+\\{', 'g'), item => {
return item.replace(new RegExp('\\b' + STRUCT + '\\b', 'g'), `${CLASS} `);
})), fileResolvePath, log);
})));
const sourceFile: ts.SourceFile = ts.createSourceFile(filePath, content,
ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
visitAllNode(sourceFile, defaultName, asName, path.dirname(fileResolvePath), log);
+45 -172
View File
@@ -23,7 +23,6 @@ import {
PAGE_ENTRY_FUNCTION_NAME,
COMPONENT_CONSTRUCTOR_UNDEFINED,
BUILD_ON,
COMPONENT_BUILD_FUNCTION,
COMPONENT_BUILDER_DECORATOR,
COMPONENT_EXTEND_DECORATOR,
COMPONENT_STYLES_DECORATOR,
@@ -35,7 +34,9 @@ import {
RESOURCE_NAME_PARAMS,
RESOURCE_RAWFILE,
ATTRIBUTE_ANIMATETO,
GLOBAL_CONTEXT
GLOBAL_CONTEXT,
CHECK_COMPONENT_EXTEND_DECORATOR,
INSTANCE
} from './pre_define';
import {
componentInfo,
@@ -45,18 +46,13 @@ import {
FileLog
} from './utils';
import {
getName,
isAttributeNode,
processComponentBlock,
bindComponentAttr,
appComponentCollection
bindComponentAttr
} from './process_component_build';
import {
BUILDIN_CONTAINER_COMPONENT,
BUILDIN_STYLE_NAMES,
CUSTOM_BUILDER_METHOD,
EXTEND_ATTRIBUTE,
JS_BIND_COMPONENTS,
INNER_STYLE_FUNCTION,
GLOBAL_STYLE_FUNCTION,
INTERFACE_NODE_SET
@@ -73,20 +69,18 @@ export function processUISyntax(program: ts.Program, ut = false): Function {
return (node: ts.SourceFile) => {
pagesDir = path.resolve(path.dirname(node.fileName));
if (process.env.compiler === BUILD_ON) {
if (!ut && (path.basename(node.fileName) === 'app.ets.ts' || !/\.ets\.ts$/.test(node.fileName))) {
if (!ut && (path.basename(node.fileName) === 'app.ets' || /\.ts$/.test(node.fileName))) {
node = ts.visitEachChild(node, processResourceNode, context);
return node;
}
collectComponents(node);
transformLog.sourceFile = node;
validateSourceFileNode(node);
node = createEntryNode(node, context);
node = ts.visitEachChild(node, processAllNodes, context);
GLOBAL_STYLE_FUNCTION.forEach((block, styleName) => {
BUILDIN_STYLE_NAMES.delete(styleName);
});
GLOBAL_STYLE_FUNCTION.clear();
const statements: ts.NodeArray<ts.Statement> = node.statements;
const statements: ts.Statement[] = Array.from(node.statements);
INTERFACE_NODE_SET.forEach(item => {
statements.unshift(item);
});
@@ -100,8 +94,7 @@ export function processUISyntax(program: ts.Program, ut = false): Function {
function processAllNodes(node: ts.Node): ts.Node {
if (ts.isImportDeclaration(node) || ts.isImportEqualsDeclaration(node)) {
processImport(node, pagesDir, transformLog.errors);
} else if (ts.isClassDeclaration(node) && node.name &&
componentCollection.customComponents.has(node.name.getText())) {
} else if (ts.isStructDeclaration(node)) {
componentCollection.currentClassName = node.name.getText();
node = processComponentClass(node, context, transformLog.errors, program);
componentCollection.currentClassName = null;
@@ -144,35 +137,9 @@ export function processUISyntax(program: ts.Program, ut = false): Function {
}
return ts.visitEachChild(node, processResourceNode, context);
}
function validateSourceFileNode(node: ts.SourceFile): void {
if (program) {
node = ts.visitEachChild(node, validateAllNodes, context);
}
}
function validateAllNodes(node: ts.Node): ts.Node {
if (ts.isMethodDeclaration(node) && node.name &&
node.name.getText() === COMPONENT_BUILD_FUNCTION && node.body && ts.isBlock(node.body)) {
const typeChecker: ts.TypeChecker = program.getTypeChecker();
validateBody(node.body, typeChecker);
return node;
}
return ts.visitEachChild(node, validateAllNodes, context);
}
};
}
function collectComponents(node: ts.SourceFile): void {
// @ts-ignore
if (node.identifiers && node.identifiers.size) {
// @ts-ignore
for (const key of node.identifiers.keys()) {
if (JS_BIND_COMPONENTS.has(key)) {
appComponentCollection.add(key);
}
}
}
}
function isResource(node: ts.Node): boolean {
return ts.isCallExpression(node) && ts.isIdentifier(node.expression) &&
(node.expression.escapedText.toString() === RESOURCE ||
@@ -285,29 +252,51 @@ function processAnimateTo(node: ts.CallExpression): ts.CallExpression {
function processExtend(node: ts.FunctionDeclaration, log: LogInfo[]): ts.FunctionDeclaration {
const componentName: string = isExtendFunction(node);
if (componentName) {
if (componentName && node.body && node.body.statements.length) {
const statementArray: ts.Statement[] = [];
bindComponentAttr(node.body.statements[0] as ts.ExpressionStatement,
const attrSet: ts.CallExpression = node.body.statements[0].expression;
const changeCompName: ts.ExpressionStatement = ts.factory.createExpressionStatement(processExtendBody(attrSet));
bindComponentAttr(changeCompName as ts.ExpressionStatement,
ts.factory.createIdentifier(componentName), statementArray, log);
let extendFunctionName: string;
if (node.name.getText().startsWith('__' + componentName + '__')) {
extendFunctionName = node.name.getText();
} else {
extendFunctionName = '__' + componentName + '__' + node.name.getText();
collectExtend(EXTEND_ATTRIBUTE, componentName, node.name.escapedText.toString());
}
return ts.factory.updateFunctionDeclaration(node, undefined, node.modifiers, node.asteriskToken,
node.name, node.typeParameters, node.parameters, node.type,
ts.factory.updateBlock(node.body, statementArray));
ts.factory.createIdentifier(extendFunctionName), node.typeParameters,
node.parameters, node.type, ts.factory.updateBlock(node.body, statementArray));
}
}
function processExtendBody(node: ts.Node): ts.Expression {
switch (node.kind) {
case ts.SyntaxKind.CallExpression:
return ts.factory.createCallExpression(processExtendBody(node.expression), undefined, node.arguments);
case ts.SyntaxKind.PropertyAccessExpression:
return ts.factory.createPropertyAccessExpression(processExtendBody(node.expression), node.name);
case ts.SyntaxKind.Identifier:
return ts.factory.createIdentifier(node.escapedText.toString().replace(INSTANCE, ''));
}
}
export function collectExtend(collectionSet: Map<string, Set<string>>, component: string, attribute: string): void {
if (collectionSet.has(component)) {
collectionSet.get(component).add(attribute);
} else {
collectionSet.set(component, new Set([attribute]));
}
}
function isExtendFunction(node: ts.FunctionDeclaration): string {
if (ts.isBlock(node.body) && node.body.statements && node.body.statements.length === 1 &&
ts.isExpressionStatement(node.body.statements[0]) &&
// @ts-ignore
ts.isCallExpression(node.body.statements[0].expression) && ts.isIdentifier(node.name)) {
const nameArray: string[] = node.name.getText().split('__');
if (nameArray.length === 3 && !nameArray[0] && EXTEND_ATTRIBUTE.has(nameArray[1])) {
const attributeArray: string[] =
[...EXTEND_ATTRIBUTE.get(nameArray[1])].map(item => item.attribute);
if (attributeArray.includes(nameArray[2])) {
return nameArray[1];
}
}
if (node.decorators && node.decorators[0].expression &&
node.decorators[0].expression.expression.escapedText.toString() === CHECK_COMPONENT_EXTEND_DECORATOR &&
node.decorators[0].expression.arguments) {
return node.decorators[0].expression.arguments[0].escapedText.toString();
} else {
return null;
}
}
@@ -325,122 +314,6 @@ function createEntryNode(node: ts.SourceFile, context: ts.TransformationContext)
}
}
function validateBody(node: ts.Block, typeChecker: ts.TypeChecker): void {
if (node.statements.length) {
node.statements.forEach((item, index, arr) => {
if (ts.isBlock(item)) {
validateBody(item, typeChecker);
}
if (index + 2 < arr.length && ts.isExpressionStatement(item) &&
isAttributeBlockNode(item, arr as ts.Statement[], index) &&
ts.isCallExpression(item.expression) && ts.isIdentifier(item.expression.expression)) {
const componentName: string = item.expression.expression.getText();
const type: ts.Type = typeChecker.getTypeAtLocation(item.expression);
let temp: any = arr[index + 2];
let name: string;
while (temp) {
if (ts.isCallExpression(temp)) {
if (ts.isPropertyAccessExpression(temp.expression)) {
const pos: number = temp.expression.name.getStart();
name = temp.expression.name.getText();
validateSymbol(isPropertyExist(typeChecker, pos, type, name, componentName),
temp.arguments, pos, typeChecker);
} else if (ts.isIdentifier(temp.expression)) {
const pos: number = temp.expression.getStart();
name = temp.expression.getText();
validateSymbol(isPropertyExist(typeChecker, pos, type, name, componentName),
temp.arguments, pos, typeChecker);
break;
}
}
temp = temp.expression;
}
}
});
}
}
function validateSymbol(type: ts.Symbol, args: ts.NodeArray<ts.Expression>,
argPos: number, typeChecker: ts.TypeChecker): void {
// @ts-ignore
if (type && type.valueDeclaration.parameters) {
// @ts-ignore
const parameters: ts.ParameterDeclaration[] = type.valueDeclaration.parameters;
const maxLength: number = parameters.length;
const minLength: number = getMinLength(parameters);
if (args.length < minLength || args.length > maxLength) {
let message:string;
if (maxLength !== minLength) {
message = `TS2554: Expected ${minLength}-${maxLength} arguments, but got ${args.length}.`;
} else {
message = `TS2554: Expected ${maxLength} arguments, but got ${args.length}.`;
}
transformLog.errors.push({
type: LogType.ERROR,
message: message,
pos: argPos
});
} else {
for (let i = 0; i < parameters.length; i++) {
validatePropertyType(parameters[i], args[i], typeChecker);
}
}
}
}
function getMinLength(parameters: ts.ParameterDeclaration[]): number {
let length: number = parameters.length;
parameters.forEach((item: ts.ParameterDeclaration) => {
if (item.questionToken !== undefined) {
length--;
}
});
return length;
}
function isPropertyExist(typeChecker: ts.TypeChecker, pos: number, type: ts.Type,
propertyName: string, componentName: string): ts.Symbol {
const symbol: ts.Symbol = typeChecker.getPropertyOfType(type, propertyName);
if (symbol) {
return symbol;
} else {
transformLog.errors.push({
type: LogType.ERROR,
message: `TS2339: Property '${propertyName}' does not exist on type '${componentName}Attribute'.`,
pos: pos
});
}
return null;
}
function validatePropertyType(param: ts.ParameterDeclaration, arg: ts.Expression,
typeChecker: ts.TypeChecker): void {
const argLocalType: ts.Type = typeChecker.getTypeAtLocation(arg);
const paramLocalType: ts.Type = typeChecker.getTypeAtLocation(param.type);
const argType: ts.Type = typeChecker.getBaseTypeOfLiteralType(typeChecker.getTypeAtLocation(arg));
// @ts-ignore
const intrinsicName: string = argType.intrinsicName;
const argTypeName: string = intrinsicName || typeChecker.typeToString(argLocalType);
// @ts-ignore
if (!typeChecker.isTypeAssignableTo(argLocalType, paramLocalType)) {
generateArgumentLog(arg, argTypeName, typeChecker.typeToString(paramLocalType));
}
}
function generateArgumentLog(arg: ts.Expression, argTypeName: string, paramTypeName: string): void {
transformLog.errors.push({
type: LogType.ERROR,
message: `TS2345: Argument of type '${argTypeName}' is not assignable to parameter of type '${paramTypeName}'.`,
pos: arg.getStart()
});
}
function isAttributeBlockNode(node: ts.ExpressionStatement, arr: ts.Statement[], index: number): boolean {
const attributeNode: ts.Node = arr[index + 2];
return BUILDIN_CONTAINER_COMPONENT.has(getName(node)) && ts.isBlock(arr[index + 1])
&& ts.isExpressionStatement(attributeNode) && isAttributeNode(attributeNode);
}
function createEntryFunction(name: string, context: ts.TransformationContext)
: ts.ExpressionStatement {
return context.factory.createExpressionStatement(context.factory.createCallExpression(
+1 -1
View File
@@ -52,7 +52,7 @@ module.exports = function resultProcess(source: string, map: any): void {
item.line = undefined;
item.column = undefined;
}
item.fileName = sourceFile.fileName.replace(/.ts$/, '');
item.fileName = sourceFile.fileName;
return item;
});
emitLogInfo(this, logInfos);
+3 -3
View File
@@ -112,11 +112,11 @@ class ComponentInfo {
export const componentInfo: ComponentInfo = new ComponentInfo();
export function hasDecorator(node: ts.MethodDeclaration | ts.FunctionDeclaration | ts.ClassDeclaration,
decortorName: string): boolean {
export function hasDecorator(node: ts.MethodDeclaration | ts.FunctionDeclaration |
ts.StructDeclaration | ts.ClassDeclaration, decortorName: string): boolean {
if (node.decorators && node.decorators.length) {
for (let i = 0; i < node.decorators.length; i++) {
if (node.decorators[i].getText() === decortorName) {
if (node.decorators[i].getText().replace(/\(.*\)$/, '').trim() === decortorName) {
return true;
}
}
+27 -105
View File
@@ -22,8 +22,6 @@ import {
COMPONENT_DECORATOR_PREVIEW,
COMPONENT_DECORATOR_COMPONENT,
COMPONENT_DECORATOR_CUSTOM_DIALOG,
STRUCT,
CLASS,
NATIVE_MODULE,
SYSTEM_PLUGIN,
OHOS_PLUGIN,
@@ -38,9 +36,6 @@ import {
COMPONENT_PROVIDE_DECORATOR,
COMPONENT_CONSUME_DECORATOR,
COMPONENT_OBJECT_LINK_DECORATOR,
COMPONENT_CONSTRUCTOR_ID,
COMPONENT_CONSTRUCTOR_PARENT,
COMPONENT_CONSTRUCTOR_PARAMS,
COMPONENT_OBSERVED_DECORATOR,
STYLES,
VALIDATE_MODULE,
@@ -65,7 +60,7 @@ import {
hasDecorator
} from './utils';
import { projectConfig } from '../main';
const parser = require('../syntax_parser/dist/exclude_comment.js');
import { collectExtend } from './process_ui_syntax';
export interface ComponentCollection {
entryComponent: string;
@@ -137,7 +132,7 @@ function checkComponentDecorator(source: string, filePath: string,
fileQuery: string): LogInfo[] | null {
const log: LogInfo[] = [];
const sourceFile: ts.SourceFile = ts.createSourceFile(filePath, source,
ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
ts.ScriptTarget.Latest, true, ts.ScriptKind.ETS);
if (sourceFile && sourceFile.statements && sourceFile.statements.length) {
const result: DecoratorResult = {
entryCount: 0,
@@ -151,26 +146,17 @@ function checkComponentDecorator(source: string, filePath: string,
if (ts.isEnumDeclaration(item) && item.name) {
enumCollection.add(item.name.getText());
}
if (isStruct(item)) {
if (index + 1 < arr.length && ts.isExpressionStatement(arr[index + 1]) &&
// @ts-ignore
arr[index + 1].expression && ts.isIdentifier(arr[index + 1].expression)) {
if (ts.isExportAssignment(item) && hasComponentDecorator(item)) {
checkDecorators(item, result, arr[index + 1] as ts.ExpressionStatement, log, sourceFile);
} else if (index > 0 && hasComponentDecorator(arr[index - 1])) {
checkDecorators(arr[index - 1] as ts.MissingDeclaration, result,
arr[index + 1] as ts.ExpressionStatement, log, sourceFile);
if (ts.isStructDeclaration(item)) {
if (item.name && ts.isIdentifier(item.name)) {
if (item.decorators && item.decorators.length) {
checkDecorators(item.decorators, result, item.name, log, sourceFile);
} else {
// @ts-ignore
const pos: number = item.expression.getStart();
const message: string = `A struct should use decorator '@Component'.`;
addLog(LogType.WARN, message, pos, log, sourceFile);
addLog(LogType.WARN, message, item.getStart(), log, sourceFile);
}
} else {
// @ts-ignore
const pos: number = item.expression.getStart();
const message: string = `A struct must have a name.`;
addLog(LogType.ERROR, message, pos, log, sourceFile);
addLog(LogType.ERROR, message, item.getStart(), log, sourceFile);
}
}
if (ts.isMissingDeclaration(item)) {
@@ -245,32 +231,16 @@ export function isCustomDialogClass(node: ts.Node): boolean {
return false;
}
function isStruct(node: ts.Node): boolean {
if ((ts.isExpressionStatement(node) || ts.isExportAssignment(node)) &&
node.expression && ts.isIdentifier(node.expression) && node.expression.getText() === STRUCT) {
return true;
}
return false;
}
function hasComponentDecorator(node: ts.Node): boolean {
if ((ts.isMissingDeclaration(node) || ts.isExportAssignment(node)) &&
node.decorators && node.decorators.length) {
return true;
}
return false;
}
interface DecoratorResult {
entryCount: number;
previewCount: number;
}
function checkDecorators(node: ts.MissingDeclaration | ts.ExportAssignment, result: DecoratorResult,
component: ts.ExpressionStatement, log: LogInfo[], sourceFile: ts.SourceFile): void {
function checkDecorators(decorators: ts.NodeArray<ts.Decorator>, result: DecoratorResult,
component: ts.Identifier, log: LogInfo[], sourceFile: ts.SourceFile): void {
let hasComponentDecorator: boolean = false;
const componentName: string = component.getText();
node.decorators.forEach((element) => {
decorators.forEach((element) => {
const name: string = element.getText().replace(/\([^\(\)]*\)/, '').trim();
if (INNER_COMPONENT_DECORATORS.has(name)) {
componentCollection.customComponents.add(componentName);
@@ -316,14 +286,14 @@ function checkDecorators(node: ts.MissingDeclaration | ts.ExportAssignment, resu
function checkUISyntax(filePath: string, allComponentNames: Set<string>, content: string,
log: LogInfo[]): void {
const sourceFile: ts.SourceFile = ts.createSourceFile(filePath, content,
ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
ts.ScriptTarget.Latest, true, ts.ScriptKind.ETS);
visitAllNode(sourceFile, sourceFile, allComponentNames, log);
}
function visitAllNode(node: ts.Node, sourceFileNode: ts.SourceFile, allComponentNames: Set<string>,
log: LogInfo[]) {
checkAllNode(node, allComponentNames, sourceFileNode, log);
if (ts.isClassDeclaration(node) && node.name && ts.isIdentifier(node.name)) {
if (ts.isStructDeclaration(node) && node.name && ts.isIdentifier(node.name)) {
collectComponentProps(node);
}
if (ts.isMethodDeclaration(node) && hasDecorator(node, COMPONENT_BUILDER_DECORATOR)) {
@@ -335,7 +305,7 @@ function visitAllNode(node: ts.Node, sourceFileNode: ts.SourceFile, allComponent
function checkAllNode(node: ts.Node, allComponentNames: Set<string>, sourceFileNode: ts.SourceFile,
log: LogInfo[]): void {
if (ts.isExpressionStatement(node) && node.expression && ts.isIdentifier(node.expression) &&
allComponentNames.has(node.expression.escapedText.toString())) {
allComponentNames.has(node.expression.escapedText.toString())) {
const pos: number = node.expression.getStart();
const message: string =
`The component name must be followed by parentheses, like '${node.expression.getText()}()'.`;
@@ -629,7 +599,7 @@ function isNonspecificChildIfStatement(node: ts.Node, specificChildSet: Set<stri
return false;
}
function collectComponentProps(node: ts.ClassDeclaration): void {
function collectComponentProps(node: ts.StructDeclaration): void {
const componentName: string = node.name.getText();
const ComponentSet: IComponentSet = getComponentSet(node);
propertyCollection.set(componentName, ComponentSet.propertys);
@@ -644,7 +614,7 @@ function collectComponentProps(node: ts.ClassDeclaration): void {
objectLinkCollection.set(componentName, ComponentSet.objectLinks);
}
export function getComponentSet(node: ts.ClassDeclaration): IComponentSet {
export function getComponentSet(node: ts.StructDeclaration): IComponentSet {
const propertys: Set<string> = new Set();
const states: Set<string> = new Set();
const links: Set<string> = new Set();
@@ -663,7 +633,7 @@ export function getComponentSet(node: ts.ClassDeclaration): IComponentSet {
};
}
function traversalComponentProps(node: ts.ClassDeclaration, propertys: Set<string>,
function traversalComponentProps(node: ts.StructDeclaration, propertys: Set<string>,
regulars: Set<string>, states: Set<string>, links: Set<string>, props: Set<string>,
storageProps: Set<string>, storageLinks: Set<string>, provides: Set<string>,
consumes: Set<string>, objectLinks: Set<string>): void {
@@ -736,14 +706,7 @@ export interface ReplaceResult {
export function sourceReplace(source: string, sourcePath: string): ReplaceResult {
let content: string = source;
const log: LogInfo[] = [];
// replace struct->class
content = content.replace(
new RegExp('\\b' + STRUCT + '\\b.+\\{', 'g'), item => {
item = item.replace(new RegExp('\\b' + STRUCT + '\\b', 'g'), `${CLASS} `);
return `${item} constructor(${COMPONENT_CONSTRUCTOR_ID}?, ${COMPONENT_CONSTRUCTOR_PARENT}?, ${COMPONENT_CONSTRUCTOR_PARAMS}?) {}`;
});
content = preprocessExtend(content, sourcePath, log);
content = preprocessExtend(content);
// process @system.
content = processSystemApi(content);
@@ -753,57 +716,16 @@ export function sourceReplace(source: string, sourcePath: string): ReplaceResult
};
}
export function preprocessExtend(content: string, sourcePath: string, log: LogInfo[]): string {
let syntaxCheckContent: string;
let result: any;
try {
result = parser.parse(content);
syntaxCheckContent = result.content;
for (let i = 0; i < result.collect_extend.component.length; i++) {
collectExtend(
result.collect_extend.component[i],
result.collect_extend.functionName[i],
result.collect_extend.parameters[i]
);
export function preprocessExtend(content: string, extendCollection?: Set<string>): string {
const REG_EXTEND: RegExp = /@Extend(\s+)([^\.\s]+)\.([^\(]+)\(/gm;
return content.replace(REG_EXTEND, (item, item1, item2, item3) => {
collectExtend(EXTEND_ATTRIBUTE, item2, '__' + item2 + '__' + item3);
collectExtend(EXTEND_ATTRIBUTE, item2, item3);
if (extendCollection) {
extendCollection.add(item3);
}
} catch (err) {
result = err;
log.push({
type: LogType.ERROR,
message: parser.SyntaxError.buildMessage(err.expected, err.found),
line: err.location.start.line,
column: err.location.start.column,
fileName: sourcePath
});
syntaxCheckContent = content;
}
if (result.error_otherParsers) {
for (let i = 0; i < result.error_otherParsers.length; i++) {
log.push({
type: LogType.ERROR,
message: result.error_otherParsers[i].errMessage,
line: result.error_otherParsers[i].errPosition.line,
column: result.error_otherParsers[i].errPosition.column,
fileName: sourcePath
});
}
}
return syntaxCheckContent;
}
function collectExtend(component: string, attribute: string, parameter: string): void {
let parameterCount: number;
if (parameter) {
parameterCount = parameter.split(',').length;
} else {
parameterCount = 0;
}
BUILDIN_STYLE_NAMES.add(attribute);
if (EXTEND_ATTRIBUTE.has(component)) {
EXTEND_ATTRIBUTE.get(component).add({ attribute, parameterCount });
} else {
EXTEND_ATTRIBUTE.set(component, new Set([{ attribute, parameterCount }]));
}
return `@Extend(${item2})${item1}function __${item2}__${item3}(`;
});
}
export function processSystemApi(content: string, isProcessWhiteList: boolean = false): string {
+7 -4
View File
@@ -38,11 +38,14 @@ function expectActual(name, filePath) {
process.env.compiler = BUILD_ON;
const afterProcess = sourceReplace(source);
validateUISyntax(source, afterProcess.content, `${name}.ts`);
const compilerOptions = ts.readConfigFile(
path.resolve(__dirname, '../tsconfig.json'), ts.sys.readFile).config.compilerOptions;
Object.assign(compilerOptions, {
"sourceMap": false,
});
const result = ts.transpileModule(afterProcess.content, {
compilerOptions: {
"target": ts.ScriptTarget.ES2017
},
fileName: `${name}.ts`,
compilerOptions: compilerOptions,
fileName: `${name}.ets`,
transformers: { before: [processUISyntax(null, true)] }
});
componentInfo.id = 0;
@@ -25,8 +25,7 @@ struct Parent {
Row() {
Child({ stateProperty: this.regularToState,
propProperty: this.stateToProp,
regularProperty: this.regularToRegular,
linkProperty: this.$stateToLink
regularProperty: this.regularToRegular, linkProperty: this.__stateToLink
})
}
}
@@ -91,8 +90,7 @@ exports.expectResult =
if (earlierCreatedChild_2 == undefined) {
View.create(new Child("2", this, { stateProperty: this.regularToState,
propProperty: this.stateToProp,
regularProperty: this.regularToRegular,
linkProperty: this.__stateToLink
regularProperty: this.regularToRegular, linkProperty: this.__stateToLink
}));
}
else {
+11 -3
View File
@@ -20,9 +20,17 @@ struct MyComponent {
}`
exports.expectResult =
`class MyComponent {
constructor(compilerAssignedUniqueChildId, parent, params) { }
build() {
`class MyComponent extends View {
constructor(compilerAssignedUniqueChildId, parent, params) {
super(compilerAssignedUniqueChildId, parent);
this.updateWithValueParams(params);
}
updateWithValueParams(params) {
}
aboutToBeDeleted() {
SubscriberManager.Get().delete(this.id());
}
render() {
}
}
`
+539
View File
@@ -1,6 +1,544 @@
{
"compileOnSave": false,
"compilerOptions": {
"ets": {
"render": {
"method": ["build", "pageTransition"],
"decorator": "Builder"
},
"components": [
"AbilityComponent",
"AlphabetIndexer",
"Animator",
"Badge",
"Blank",
"Button",
"Calendar",
"Camera",
"Canvas",
"Checkbox",
"CheckboxGroup",
"Circle",
"ColorPicker",
"ColorPickerDialog",
"Column",
"ColumnSplit",
"Counter",
"DataPanel",
"DatePicker",
"Divider",
"Ellipse",
"Flex",
"FormComponent",
"FrictionMotion",
"Gauge",
"GeometryView",
"Grid",
"GridItem",
"GridContainer",
"Hyperlink",
"Image",
"ImageAnimator",
"Line",
"List",
"ListItem",
"LoadingProgress",
"Marquee",
"Menu",
"Navigation",
"Navigator",
"Option",
"PageTransitionEnter",
"PageTransitionExit",
"Panel",
"Path",
"PatternLock",
"Piece",
"PluginComponent",
"Polygon",
"Polyline",
"Progress",
"QRCode",
"Radio",
"Rating",
"Rect",
"Refresh",
"Row",
"RowSplit",
"RichText",
"Scroll",
"ScrollBar",
"ScrollMotion",
"Search",
"Section",
"Select",
"Shape",
"Sheet",
"SideBarContainer",
"Slider",
"Span",
"Stack",
"Stepper",
"StepperItem",
"Swiper",
"TabContent",
"Tabs",
"Text",
"TextPicker",
"TextClock",
"TextArea",
"TextInput",
"TextTimer",
"Toggle",
"Video",
"Web",
"XComponent"
],
"extend": {
"decorator": "Extend",
"components": [
{
"name": "AbilityComponent",
"type": "AbilityComponentAttribute",
"instance": "AbilityComponentInstance"
},
{
"name": "AlphabetIndexer",
"type": "AlphabetIndexerAttribute",
"instance": "AlphabetIndexerInstance"
},
{
"name": "Animator",
"type": "AnimatorAttribute",
"instance": "AnimatorInstance"
},
{
"name": "Badge",
"type": "BadgeAttribute",
"instance": "BadgeInstance"
},
{
"name": "Blank",
"type": "BlankAttribute",
"instance": "BlankInstance"
},
{
"name": "Button",
"type": "ButtonAttribute",
"instance": "ButtonInstance"
},
{
"name": "Calendar",
"type": "CalendarAttribute",
"instance": "CalendarInstance"
},
{
"name": "Camera",
"type": "CameraAttribute",
"instance": "CameraInstance"
},
{
"name": "Canvas",
"type": "CanvasAttribute",
"instance": "CanvasInstance"
},
{
"name": "Checkbox",
"type": "CheckboxAttribute",
"instance": "CheckboxInstance"
},
{
"name": "CheckboxGroup",
"type": "CheckboxGroupAttribute",
"instance": "CheckboxGroupInstance"
},
{
"name": "Circle",
"type": "CircleAttribute",
"instance": "CircleInstance"
},
{
"name": "ColorPicker",
"type": "ColorPickerAttribute",
"instance": "ColorPickerInstance"
},
{
"name": "ColorPickerDialog",
"type": "ColorPickerDialogAttribute",
"instance": "ColorPickerDialogInstance"
},
{
"name": "Column",
"type": "ColumnAttribute",
"instance": "ColumnInstance"
},
{
"name": "ColumnSplit",
"type": "ColumnSplitAttribute",
"instance": "ColumnSplitInstance"
},
{
"name": "Counter",
"type": "CounterAttribute",
"instance": "CounterInstance"
},
{
"name": "DataPanel",
"type": "DataPanelAttribute",
"instance": "DataPanelInstance"
},
{
"name": "DatePicker",
"type": "DatePickerAttribute",
"instance": "DatePickerInstance"
},
{
"name": "Divider",
"type": "DividerAttribute",
"instance": "DividerInstance"
},
{
"name": "Ellipse",
"type": "EllipseAttribute",
"instance": "EllipseInstance"
},
{
"name": "Flex",
"type": "FlexAttribute",
"instance": "FlexInstance"
},
{
"name": "FormComponent",
"type": "FormComponentAttribute",
"instance": "FormComponentInstance"
},
{
"name": "FrictionMotion",
"type": "FrictionMotionAttribute",
"instance": "FrictionMotionInstance"
},
{
"name": "Gauge",
"type": "GaugeAttribute",
"instance": "GaugeInstance"
},
{
"name": "GeometryView",
"type": "GeometryViewAttribute",
"instance": "GeometryViewInstance"
},
{
"name": "Grid",
"type": "GridAttribute",
"instance": "GridInstance"
},
{
"name": "GridItem",
"type": "GridItemAttribute",
"instance": "GridItemInstance"
},
{
"name": "GridContainer",
"type": "GridContainerAttribute",
"instance": "GridContainerInstance"
},
{
"name": "Hyperlink",
"type": "HyperlinkAttribute",
"instance": "HyperlinkInstance"
},
{
"name": "Image",
"type": "ImageAttribute",
"instance": "ImageInstance"
},
{
"name": "ImageAnimator",
"type": "ImageAnimatorAttribute",
"instance": "ImageAnimatorInstance"
},
{
"name": "Line",
"type": "LineAttribute",
"instance": "LineInstance"
},
{
"name": "List",
"type": "ListAttribute",
"instance": "ListInstance"
},
{
"name": "ListItem",
"type": "ListItemAttribute",
"instance": "ListItemInstance"
},
{
"name": "LoadingProgress",
"type": "LoadingProgressAttribute",
"instance": "LoadingProgressInstance"
},
{
"name": "Marquee",
"type": "MarqueeAttribute",
"instance": "MarqueeInstance"
},
{
"name": "Menu",
"type": "MenuAttribute",
"instance": "MenuInstance"
},
{
"name": "Navigation",
"type": "NavigationAttribute",
"instance": "NavigationInstance"
},
{
"name": "Navigator",
"type": "NavigatorAttribute",
"instance": "NavigatorInstance"
},
{
"name": "Option",
"type": "OptionAttribute",
"instance": "OptionInstance"
},
{
"name": "PageTransitionEnter",
"type": "PageTransitionEnterAttribute",
"instance": "PageTransitionEnterInstance"
},
{
"name": "PageTransitionExit",
"type": "PageTransitionExitAttribute",
"instance": "PageTransitionExitInstance"
},
{
"name": "Panel",
"type": "PanelAttribute",
"instance": "PanelInstance"
},
{
"name": "Path",
"type": "PathAttribute",
"instance": "PathInstance"
},
{
"name": "PatternLock",
"type": "PatternLockAttribute",
"instance": "PatternLockInstance"
},
{
"name": "Piece",
"type": "PieceAttribute",
"instance": "PieceInstance"
},
{
"name": "PluginComponent",
"type": "PluginComponentAttribute",
"instance": "PluginComponentInstance"
},
{
"name": "Polygon",
"type": "PolygonAttribute",
"instance": "PolygonInstance"
},
{
"name": "Polyline",
"type": "PolylineAttribute",
"instance": "PolylineInstance"
},
{
"name": "Progress",
"type": "ProgressAttribute",
"instance": "ProgressInstance"
},
{
"name": "QRCode",
"type": "QRCodeAttribute",
"instance": "QRCodeInstance"
},
{
"name": "Radio",
"type": "RadioAttribute",
"instance": "RadioInstance"
},
{
"name": "Rating",
"type": "RatingAttribute",
"instance": "RatingInstance"
},
{
"name": "Rect",
"type": "RectAttribute",
"instance": "RectInstance"
},
{
"name": "Refresh",
"type": "RefreshAttribute",
"instance": "RefreshInstance"
},
{
"name": "Row",
"type": "RowAttribute",
"instance": "RowInstance"
},
{
"name": "RowSplit",
"type": "RowSplitAttribute",
"instance": "RowSplitInstance"
},
{
"name": "RichText",
"type": "RichTextAttribute",
"instance": "RichTextInstance"
},
{
"name": "Scroll",
"type": "ScrollAttribute",
"instance": "ScrollInstance"
},
{
"name": "ScrollBar",
"type": "ScrollBarAttribute",
"instance": "ScrollBarInstance"
},
{
"name": "ScrollMotion",
"type": "ScrollMotionAttribute",
"instance": "ScrollMotionInstance"
},
{
"name": "Search",
"type": "SearchAttribute",
"instance": "SearchInstance"
},
{
"name": "Section",
"type": "SectionAttribute",
"instance": "SectionInstance"
},
{
"name": "Select",
"type": "SelectAttribute",
"instance": "SelectInstance"
},
{
"name": "Shape",
"type": "ShapeAttribute",
"instance": "ShapeInstance"
},
{
"name": "Sheet",
"type": "SheetAttribute",
"instance": "SheetInstance"
},
{
"name": "SideBarContainer",
"type": "SideBarContainerAttribute",
"instance": "SideBarContainerInstance"
},
{
"name": "Slider",
"type": "SliderAttribute",
"instance": "SliderInstance"
},
{
"name": "Span",
"type": "SpanAttribute",
"instance": "SpanInstance"
},
{
"name": "Stack",
"type": "StackAttribute",
"instance": "StackInstance"
},
{
"name": "Stepper",
"type": "StepperAttribute",
"instance": "StepperInstance"
},
{
"name": "StepperItem",
"type": "StepperItemAttribute",
"instance": "StepperItemInstance"
},
{
"name": "Swiper",
"type": "SwiperAttribute",
"instance": "SwiperInstance"
},
{
"name": "TabContent",
"type": "TabContentAttribute",
"instance": "TabContentInstance"
},
{
"name": "Tabs",
"type": "TabsAttribute",
"instance": "TabsInstance"
},
{
"name": "Text",
"type": "TextAttribute",
"instance": "TextInstance"
},
{
"name": "TextPicker",
"type": "TextPickerAttribute",
"instance": "TextPickerInstance"
},
{
"name": "TextClock",
"type": "TextClockAttribute",
"instance": "TextClockInstance"
},
{
"name": "TextArea",
"type": "TextAreaAttribute",
"instance": "TextAreaInstance"
},
{
"name": "TextInput",
"type": "TextInputAttribute",
"instance": "TextInputInstance"
},
{
"name": "TextTimer",
"type": "TextTimerAttribute",
"instance": "TextTimerInstance"
},
{
"name": "Toggle",
"type": "ToggleAttribute",
"instance": "ToggleInstance"
},
{
"name": "Video",
"type": "VideoAttribute",
"instance": "VideoInstance"
},
{
"name": "Web",
"type": "WebAttribute",
"instance": "WebInstance"
},
{
"name": "XComponent",
"type": "XComponentAttribute",
"instance": "XComponentInstance"
},
]
},
"styles": {
"decorator": "Styles",
"component": {
"name": "Common",
"type": "T",
"instance": "CommonInstance"
},
"property": "stateStyles"
},
},
"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
@@ -11,6 +549,7 @@
"experimentalDecorators": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"module": "commonjs",
"target": "es2017",
+4 -1
View File
@@ -40,6 +40,9 @@ function initConfig(config) {
const projectPath = path.resolve(projectConfig.projectPath);
Object.assign(config, {
entry: projectConfig.entryObj,
cache: {
type: "filesystem"
},
watch: watchMode,
watchOptions: {
aggregateTimeout: 10,
@@ -67,8 +70,8 @@ function initConfig(config) {
{
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.ets$/],
onlyCompileBundledFiles: true,
transpileOnly: true,
configFile: path.resolve(__dirname, 'tsconfig.json'),
getCustomTransformers(program) {
return {