diff --git a/BUILD.gn b/BUILD.gn index 2fb8d0eb93981fe0484f1dceaaa5890f68c50f8d..386ce73f2383987387a3dcacbc312ef5970c9a9f 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -144,14 +144,28 @@ ets_loader_sources = [ ] ohos_copy("ets_loader") { - deps = [ ":build_ets_loader_library" ] + deps = [ + ":build_ets_loader_library", + ":typescript", + ] sources = ets_loader_sources deps += [ ":build_ets_sysResource" ] - sources += [ ets_sysResource ] + sources += [ + ets_sysResource, + target_out_dir + "/third_party" + ] outputs = [ target_out_dir + "/$target_name/{{source_file_part}}" ] module_source_dir = target_out_dir + "/$target_name" module_install_name = "" + license_file = "//third_party/typescript/LICENSE" +} + +ohos_copy("typescript") { + sources = [ "//third_party/typescript/build_package" ] + outputs = [ target_out_dir + "/third_party" ] + module_install_name = "" + license_file = "//third_party/typescript/LICENSE" } ohos_copy("ets_loader_component_config") { @@ -270,6 +284,13 @@ ohos_copy("ets_loader_ark_codegen") { outputs = [ target_out_dir + "/ets_loader_ark/codegen" ] } +ohos_copy("typescript_ark") { + sources = [ "//third_party/typescript/build_package" ] + outputs = [ target_out_dir + "/third_party" ] + module_install_name = "" + license_file = "//third_party/third_party_typescript/LICENSE" +} + ohos_copy("ets_loader_node_modules") { deps = [ ":ets_loader_ark", @@ -279,6 +300,7 @@ ohos_copy("ets_loader_node_modules") { ":ets_loader_ark_lib", ":ets_loader_ark_server", ":ets_loader_ark_syntax", + ":typescript_ark", ] sources = [ "//developtools/ace-ets2bundle/compiler/node_modules" ] outputs = [ target_out_dir + "/ets_loader_ark/node_modules" ] diff --git a/compiler/babel.config.js b/compiler/babel.config.js index 1c8aa70516ca7db5bda81d75107c87ef219eea50..ed99ab39af3f8807fe5b91fa5256351c050a42fb 100644 --- a/compiler/babel.config.js +++ b/compiler/babel.config.js @@ -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', diff --git a/compiler/build_declarations_file.js b/compiler/build_declarations_file.js index 41d982b4f4413ee321dc9648eb14aa80d723a6db..c878c971d63dc3f2acf05fe245abd909a72ebe21 100644 --- a/compiler/build_declarations_file.js +++ b/compiler/build_declarations_file.js @@ -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) { diff --git a/compiler/package-lock.json b/compiler/package-lock.json index 66c7d41b73350759f9b78bd6aa64bd88dedc53c2..d752ccb3dbb10cd058cd9f2209afcb952a65231c 100644 --- a/compiler/package-lock.json +++ b/compiler/package-lock.json @@ -4073,9 +4073,7 @@ "dev": true }, "typescript": { - "version": "4.5.4", - "resolved": "https://registry.npmmirror.com/typescript/download/typescript-4.5.4.tgz", - "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==" + "version": "file:third_party/typescript" }, "uglify-js": { "version": "3.14.5", diff --git a/compiler/package.json b/compiler/package.json index cf6c7141f657872d6a55f49d6b2725950cdb8f18..d8bfadb0269293a05354e88ba358954449b08ebb 100644 --- a/compiler/package.json +++ b/compiler/package.json @@ -42,7 +42,7 @@ "log4js": "^6.3.0", "md5": "^2.3.0", "ts-loader": "^8.0.12", - "typescript": "^4.1.3", + "typescript": "file:./third_party/typescript", "webpack": "^5.48.0", "webpack-cli": "^4.2.0", "ws": "^8.3.0" diff --git a/compiler/src/compile_info.ts b/compiler/src/compile_info.ts index 4312b7f40d716dd014e1507e1705836965d5220f..a086d8a404e0ba92183f2b0bb7f9a253da8a5a7e 100644 --- a/compiler/src/compile_info.ts +++ b/compiler/src/compile_info.ts @@ -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]}`; diff --git a/compiler/src/component_map.ts b/compiler/src/component_map.ts index 615a675f923216b4b940906dc3878ff1f288e3ba..c7fe3d1b0f4e70179df6f35fd4b1bba116e7e609 100644 --- a/compiler/src/component_map.ts +++ b/compiler/src/component_map.ts @@ -75,13 +75,13 @@ export interface ExtendParamterInterfance { attribute: string, parameterCount: number } -export const EXTEND_ATTRIBUTE: Map> = new Map(); +export const EXTEND_ATTRIBUTE: Map> = new Map(); export const STYLES_ATTRIBUTE: Set = new Set(); export const INTERFACE_NODE_SET: Set = new Set(); export const JS_BIND_COMPONENTS: Set = 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', diff --git a/compiler/src/ets_checker.ts b/compiler/src/ets_checker.ts new file mode 100644 index 0000000000000000000000000000000000000000..41c66b31cd06a3b7b27189d117eba5a122bbbb4b --- /dev/null +++ b/compiler/src/ets_checker.ts @@ -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 (/(? 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/common', 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 = new Set(); +export const appComponentCollection: Set = new Set(); +export const decoratorParamsCollection: Set = new Set(); +export const extendCollection: Set = 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+(Circle|Ellipse|Rect|Path)/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; +} diff --git a/compiler/src/pre_define.ts b/compiler/src/pre_define.ts index 6935aeac10f6faf52329dce8a00a8d30f26f9554..ff3a07212f53cb89bf3a22194bf4db77a20401db 100644 --- a/compiler/src/pre_define.ts +++ b/compiler/src/pre_define.ts @@ -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 = 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 = new Set([COMPONENT_DECORATOR_ENTRY, COMPONENT_DECORATOR_PREVIEW, COMPONENT_DECORATOR_COMPONENT, COMPONENT_DECORATOR_CUSTOM_DIALOG]); export const INNER_COMPONENT_MEMBER_DECORATORS: Set = 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'; diff --git a/compiler/src/pre_process.ts b/compiler/src/pre_process.ts index 9f8eeeb16df2b8db940c6ad12f95a62f3721c6d0..5d501cabe4824ead93214ed2b7fbf84137379b89 100644 --- a/compiler/src/pre_process.ts +++ b/compiler/src/pre_process.ts @@ -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; } diff --git a/compiler/src/process_component_build.ts b/compiler/src/process_component_build.ts index d07fe1a5d9dc106612d867658adfd3684c991078..778ae704cd5dc31d95b75cad1be3a58bcb30bdaa 100644 --- a/compiler/src/process_component_build.ts +++ b/compiler/src/process_component_build.ts @@ -88,8 +88,6 @@ import { projectConfig } from '../main'; import { transformLog, contextGlobal } from './process_ui_syntax'; import { props } from './compile_info'; -export const appComponentCollection: Set = 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,31 @@ 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); + } + }); + return temp; +} + function classifyArgumentsNum(args: any, argumentsArr: ts.Expression[], propName: string, identifierNode: ts.Identifier): void { if (propName === BIND_POPUP && args.length === 2) { @@ -967,7 +1000,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 +1086,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 +1113,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 +1121,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 +1160,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, diff --git a/compiler/src/process_component_class.ts b/compiler/src/process_component_class.ts index 9de77666ad2fe0a196751878930b1521d4b89c84..dc177f35be45e5d7ea49c60a626ba3dfbdc19901 100644 --- a/compiler/src/process_component_class.ts +++ b/compiler/src/process_component_class.ts @@ -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 { +function updateHeritageClauses(node: ts.StructDeclaration): ts.NodeArray { 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, diff --git a/compiler/src/process_component_constructor.ts b/compiler/src/process_component_constructor.ts index 36f56baa33f1625bd7efaa4c19c954e28a904ca5..d75c50cf84fc8488ec06ff72e4321cd68affb2d4 100644 --- a/compiler/src/process_component_constructor.ts +++ b/compiler/src/process_component_constructor.ts @@ -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.ConstructorDeclaration { @@ -32,12 +30,11 @@ export function getInitConstructor(members: ts.NodeArray): 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 = - 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 = - 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, @@ -129,5 +109,5 @@ export function addConstructor(ctorNode: any, watchMap: Map, 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); } diff --git a/compiler/src/process_custom_component.ts b/compiler/src/process_custom_component.ts index 34ca61d68386fb3a641d2e86a99119f6425667a0..50109765b518b22bc9362abd7cd9bc38ccd39d1d 100644 --- a/compiler/src/process_custom_component.ts +++ b/compiler/src/process_custom_component.ts @@ -178,6 +178,9 @@ function getCustomComponentName(newNode: ts.NewExpression): string { } function getCollectionSet(name: string, collection: Map>): Set { + if (!collection) { + return new Set([]); + } return collection.get(name) || new Set([]); } diff --git a/compiler/src/process_import.ts b/compiler/src/process_import.ts index eb5bb1cebab0576584e10d9e4b86e0da12fe6469..6327b5c16e7fd37697c619368fac41294bdc3d9d 100644 --- a/compiler/src/process_import.ts +++ b/compiler/src/process_import.ts @@ -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); diff --git a/compiler/src/process_ui_syntax.ts b/compiler/src/process_ui_syntax.ts index e3221796c198461c2af668be4c13f3bd4de13940..7a4825d35028727de7def4b84ecb779af5c7a630 100644 --- a/compiler/src/process_ui_syntax.ts +++ b/compiler/src/process_ui_syntax.ts @@ -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 = 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>, 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, - 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( diff --git a/compiler/src/result_process.ts b/compiler/src/result_process.ts index 8e80ed3f6cb6e46c44b3ce4e41bfd37b7e15ba88..fe96bf2a04b217aaa0e9540ac2ae8797bdf3d8d7 100644 --- a/compiler/src/result_process.ts +++ b/compiler/src/result_process.ts @@ -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); diff --git a/compiler/src/utils.ts b/compiler/src/utils.ts index 7f083c3996e25155cb9f28c25c8061b05b8901bd..59e5b9b66b3e840ac6ba0a1cde0c376b97d4d28a 100644 --- a/compiler/src/utils.ts +++ b/compiler/src/utils.ts @@ -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; } } diff --git a/compiler/src/validate_ui_syntax.ts b/compiler/src/validate_ui_syntax.ts index 7efd1f804dd3d7730390264166eb15bae41eef46..f47383a0a18bfa124783872d572fbf032c8ef9d4 100644 --- a/compiler/src/validate_ui_syntax.ts +++ b/compiler/src/validate_ui_syntax.ts @@ -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, 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, 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, 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, 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 = new Set(); const states: Set = new Set(); const links: Set = new Set(); @@ -663,7 +633,7 @@ export function getComponentSet(node: ts.ClassDeclaration): IComponentSet { }; } -function traversalComponentProps(node: ts.ClassDeclaration, propertys: Set, +function traversalComponentProps(node: ts.StructDeclaration, propertys: Set, regulars: Set, states: Set, links: Set, props: Set, storageProps: Set, storageLinks: Set, provides: Set, consumes: Set, objectLinks: Set): 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 { + 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 { diff --git a/compiler/test/test.js b/compiler/test/test.js index 0a6506aa049f1c30b938579f647b273fe18e35e8..99f5e2417daef7c30dfdfd472f52f1b23821834a 100644 --- a/compiler/test/test.js +++ b/compiler/test/test.js @@ -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; diff --git a/compiler/test/ut/component/customComponent.ts b/compiler/test/ut/component/customComponent.ts index bdf19913bc88f4cef950109df91c2663342ab961..2ffe6bd3653c55fff380b8cd0e1280f60f851770 100644 --- a/compiler/test/ut/component/customComponent.ts +++ b/compiler/test/ut/component/customComponent.ts @@ -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 { diff --git a/compiler/test/ut/struct/struct_02.ts b/compiler/test/ut/struct/struct_02.ts index 175a1085d27a9c70852b6fe7277399ad305e9d3f..2ddd86ac96fd2fe8fa4ede4ebbcca03c7cd51e8d 100644 --- a/compiler/test/ut/struct/struct_02.ts +++ b/compiler/test/ut/struct/struct_02.ts @@ -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() { } } ` diff --git a/compiler/third_party/typescript b/compiler/third_party/typescript new file mode 120000 index 0000000000000000000000000000000000000000..50b1c7420ea30cba72c7bc4dca97114496972de3 --- /dev/null +++ b/compiler/third_party/typescript @@ -0,0 +1 @@ +../../../../third_party/typescript/build_package/typescript/ \ No newline at end of file diff --git a/compiler/tsconfig.json b/compiler/tsconfig.json index 822f29fa5e395235e355b680fbc867dba842c092..60078e0bab7068e07f2d45580e17e9a434052c48 100644 --- a/compiler/tsconfig.json +++ b/compiler/tsconfig.json @@ -1,6 +1,556 @@ { "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", + "SpringMotion", + "SpringProp", + "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": "SpringMotion", + "type": "SpringMotionAttribute", + "instance": "SpringMotionInstance" + }, + { + "name": "SpringProp", + "type": "SpringPropAttribute", + "instance": "SpringPropInstance" + }, + { + "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 +561,7 @@ "experimentalDecorators": true, "moduleResolution": "node", "resolveJsonModule": true, + "skipLibCheck": true, "sourceMap": true, "module": "commonjs", "target": "es2017", diff --git a/compiler/webpack.config.js b/compiler/webpack.config.js index 94a1ed29fbc69547552eadb81374a54214f3270a..405325fc7d22ba2bc4394a6fd02ce75f3ffb65b1 100644 --- a/compiler/webpack.config.js +++ b/compiler/webpack.config.js @@ -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 {