Merge branch 'master' of gitee.com:openharmony/developtools_ace-ets2bundle into shz_Swiper_ets_indicatorStyle_0222

This commit is contained in:
Yao.inhome
2022-02-22 07:48:09 +00:00
committed by Gitee
34 changed files with 799 additions and 366 deletions
+32 -1
View File
@@ -17,10 +17,24 @@ const ts = require('typescript')
const path = require('path')
const fs = require('fs')
const addTSInterfaceSet = ['ForEach', 'LazyForEach', 'TapGesture', 'LongPressGesture', 'LongPressGesture',
'PanGesture', 'SwipeGesture', 'PinchGesture', 'RotationGesture', 'GestureGroup','PageTransitionEnter',
'PageTransitionExit'];
const addTSAttributeSet = ['AlphabetIndexer', 'Animator', 'Badge', 'Blank', 'Button', 'Calendar', 'Canvas',
'Checkbox', 'CheckboxGroup', 'Circle', 'Column', 'ColumnSplit', 'Counter', 'DataPanel', 'DatePicker',
'Divider', 'Ellipse', 'Flex', 'FormComponent', 'Gauge', 'Grid', 'GridItem', 'GridContainer', 'Image',
'ImageAnimator', 'Line', 'List', 'ListItem', 'LoadingProgress', 'Marquee', 'Navigation', 'Navigator',
'Panel', 'Path', 'PatternLock', 'Piece', 'PluginComponent', 'Polygon', 'Polyline', 'Progress',
'QRCode', 'Radio', 'Rating', 'Rect', 'Refresh', 'Row', 'RowSplit', 'Scroll', 'ScrollBar', 'Search',
'Select', 'Shape', 'Sheet', 'Slider', 'Span', 'Stack', 'Stepper', 'StepperItem', 'Swiper',
'TabContent', 'Tabs', 'Text', 'TextArea', 'TextClock', 'TextInput', 'TextPicker', 'TextTimer',
'Toggle', 'Video', 'Web', 'XComponent', 'RichText'];
generateTargetFile(process.argv[2], process.argv[3]);
function generateTargetFile(filePath, output) {
const files = [];
const globalTsFile = path.resolve(filePath, '../../global.d.ts');
const middleTsFile = path.resolve(filePath, 'middle_class.d.ts');
if (fs.existsSync(globalTsFile)) {
files.push(globalTsFile);
}
@@ -47,7 +61,7 @@ function generateTargetFile(filePath, output) {
const fileName = path.resolve(output, path.basename(item));
if (item === globalTsFile) {
content = license + '\n\n' + processsFile(content, fileName, true);
} else {
} else if (path.resolve(item) !== middleTsFile) {
content = license + '\n\n' + processsFile(content, fileName, false);
}
fs.writeFile(fileName, content, err => {
@@ -127,6 +141,18 @@ function processComponent(node, newStatements) {
node = ts.factory.updateInterfaceDeclaration(node, node.decorators, node.modifiers,
node.name, node.typeParameters, [heritageClause], node.members);
}
if (addTSInterfaceSet.includes(componentName)) {
node = ts.factory.updateInterfaceDeclaration(node, node.decorators, node.modifiers, node.name,
node.typeParameters, [ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword,
[ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier('TS' + componentName + 'Interface'),
undefined)])], node.members);
}
}
if (isClass(node) && addTSAttributeSet.includes(node.name.getText().replace(/Attribute$/, ''))) {
node = ts.factory.updateClassDeclaration(node, node.decorators, node.modifiers, node.name,
node.typeParameters, [ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword,
[ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier('TS' + node.name.getText()),
undefined)])], node.members);
}
newStatements.push(node);
}
@@ -164,6 +190,11 @@ function isInterface(node) {
/Interface$/.test(node.name.getText());
}
function isClass(node) {
return ts.isClassDeclaration(node) && node.name && ts.isIdentifier(node.name) &&
/Attribute$/.test(node.name.getText());
}
function isSignNode(node) {
return (ts.isCallSignatureDeclaration(node) || ts.isConstructSignatureDeclaration(node)) &&
node.type && ts.isTypeReferenceNode(node.type) && node.type.typeName && ts.isIdentifier(node.type.typeName) &&
+1
View File
@@ -1,4 +1,5 @@
{
"name": "Button",
"single": true,
"attrs": ["type", "stateEffect", "fontColor", "fontSize", "fontWeight", "fontStyle", "fontFamily"]
}
+1 -1
View File
@@ -5,6 +5,6 @@
"columnsTemplate", "rowsTemplate", "columnsGap", "rowsGap", "scrollBar", "scrollBarWidth",
"scrollBarColor", "editMode", "maxCount", "minCount", "cellLength", "onItemDragStart",
"onItemDragMove", "onItemDragEnter", "onItemDragMove", "onItemDrop", "layoutDirection", "direction",
"supportAnimation", "onItemDragLeave"
"supportAnimation", "onItemDragLeave", "multiSelectable"
]
}
+1 -1
View File
@@ -2,5 +2,5 @@
"name": "GridItem",
"parents": ["Grid"],
"single": true,
"attrs": ["rowStart", "rowEnd", "columnStart", "columnEnd", "forceRebuild"]
"attrs": ["rowStart", "rowEnd", "columnStart", "columnEnd", "forceRebuild", "selectable", "onSelect"]
}
+2 -1
View File
@@ -4,6 +4,7 @@
"attrs": [
"listDirection", "scrollBar", "edgeEffect", "divider", "editMode", "cachedCount",
"chainAnimation", "onScroll", "onReachStart", "onReachEnd", "onScrollStop", "onItemDelete",
"onItemMove", "onItemDragStart", "onItemDragEnter", "onItemDragMove", "onItemDragLeave", "onItemDrop"
"onItemMove", "onItemDragStart", "onItemDragEnter", "onItemDragMove", "onItemDragLeave", "onItemDrop",
"multiSelectable"
]
}
+1 -1
View File
@@ -2,5 +2,5 @@
"name": "ListItem",
"parents": ["List"],
"single": true,
"attrs": ["sticky", "editable"]
"attrs": ["sticky", "editable", "selectable", "onSelect"]
}
+7
View File
@@ -0,0 +1,7 @@
{
"name": "RichText",
"single": true,
"attrs": [
"onStart", "onComplete"
]
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "SideBarContainer",
"attrs": [
"showControlButton", "onChange"
"showControlButton", "onChange", "sideBarWidth", "maxSideBarWidth", "maxSideBarWidth"
]
}
+2 -2
View File
@@ -2,7 +2,7 @@
"name": "Slider",
"atomic": true,
"attrs": [
"blockColor", "trackColor", "selectedColor", "minLabel", "maxLabel", "showSteps", "showTips",
"blockColor", "trackColor", "selectedColor", "minLabel", "maxLabel", "showSteps", "showTips", "trackThickness",
"onChange"
]
}
}
+2 -1
View File
@@ -2,6 +2,7 @@
"name": "Swiper",
"attrs": [
"index", "autoPlay", "interval", "indicator", "loop", "duration", "vertical", "itemSpace",
"cachedCount", "displayMode", "displayCount", "effectMode", "disableSwipe", "onChange", "indicatorStyle"
"cachedCount", "displayMode", "displayCount", "effectMode", "disableSwipe", "curve", "onChange",
"indicatorStyle"
]
}
+2 -1
View File
@@ -1,5 +1,6 @@
{
"name": "TabContent",
"parents": ["Tabs"],
"attrs": ["tabBar"]
"attrs": ["tabBar"],
"single": true
}
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "TextClock",
"attrs": [
"format", "onDateChange", "status", "fontColor",
"format", "onDateChange", "fontColor",
"fontSize", "fontStyle", "fontWeight", "fontFamily"
]
}
}
+8 -1
View File
@@ -1,5 +1,12 @@
{
"name": "Web",
"atomic": true,
"attrs": ["onPageFinish", "onRequestFocus", "javaScriptEnabled", "fileAccessEnabled"]
"attrs": [
"password", "cacheMode", "tableData", "wideViewModeAccess", "overviewModeAccess", "textZoomAtio", "databaseAccess",
"onRefreshAccessedHistory", "onUrlLoadIntercept", "onSslErrorReceive", "onRenderExited", "onFileSelectorShow",
"onPageEnd", "onPageBegin", "onProgressChange", "onTitleReceive", "onGeolocationHide", "onGeolocationShow",
"onRequestSelected", "javaScriptAccess", "fileAccess", "onAlert", "onBeforeUnload", "onlineImageAccess",
"domStorageAccess", "imageAccess", "mixedMode", "zoomAccess", "geolocationAccess", "javaScriptProxy",
"onConfirm", "onConsole", "onErrorReceive", "onHttpErrorReceive", "onDownloadStart"
]
}
+2 -1
View File
@@ -73,6 +73,7 @@ function loadEntryObj(projectConfig) {
const jsonString = fs.readFileSync(projectConfig.manifestFilePath).toString();
manifest = JSON.parse(jsonString);
} else if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) {
process.env.compileMode = 'moduleJson';
buildManifest(manifest, projectConfig.aceModuleJsonPath);
} else {
throw Error('\u001b[31m ERROR: the manifest file ' + projectConfig.manifestFilePath +
@@ -115,7 +116,7 @@ function buildManifest(manifest, aceConfigPath) {
function getPages(configJson) {
const pages = []
const modulePagePath = path.resolve(projectConfig.aceProfilePath,
`${configJson.module.pages.replace(/\@profile\:/, '')}.json`);
`${configJson.module.pages.replace(/\$profile\:/, '')}.json`);
if (fs.existsSync(modulePagePath)) {
const pagesConfig = JSON.parse(fs.readFileSync(modulePagePath, 'utf-8'));
if (pagesConfig && pagesConfig.src) {
+1 -1
View File
@@ -57,7 +57,7 @@ function handlePluginCompileComponent(jsonData) {
const newSource = ts.factory.updateSourceFile(sourceNode, previewStatements);
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
const result = printer.printNode(ts.EmitHint.Unspecified, newSource, newSource);
receivedMsg.data.script = result;
receivedMsg.data.script = ts.transpileModule(result, {}).outputText;
if (pluginSocket.readyState === WebSocket.OPEN){
responseToPlugin(receivedMsg);
}
+7 -7
View File
@@ -92,7 +92,7 @@ export class ResultStates {
}
);
compilation.hooks.buildModule.tap("findModule", (module) => {
compilation.hooks.buildModule.tap('findModule', (module) => {
if (/node_modules/.test(module.context)) {
const modulePath: string =
path.resolve(module.resourceResolveData.descriptionFileRoot, MODULE_SHARE_PATH);
@@ -113,7 +113,7 @@ export class ResultStates {
compilation.hooks.processAssets.tap(
{
name: 'GLOBAL_COMMON_MODULE_CACHE',
stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS,
stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
},
(assets) => {
if (assets['commons.js']) {
@@ -133,7 +133,7 @@ export class ResultStates {
`globalThis["__common_module_cache__"][moduleId]: null;\n` +
`if (commonCachedModule) { return commonCachedModule.exports; }\n` +
source.replace('// Execute the module function',
`if (globalThis["__common_module_cache__"] && moduleId.indexOf("?name=") < 0 && ` +
`if (globalThis["__common_module_cache__"] && moduleId.indexOf("?name=") < 0 && ` +
`Object.keys(globalThis["__common_module_cache__"]).indexOf(moduleId) >= 0) {\n` +
` globalThis["__common_module_cache__"][moduleId] = module;\n}`);
});
@@ -157,12 +157,12 @@ export class ResultStates {
compiler.hooks.compilation.tap('Collect Components And Modules', compilation => {
compilation.hooks.additionalAssets.tapAsync('Collect Components And Modules', callback => {
compilation.assets['./component_collection.txt'] =
new RawSource(Array.from(appComponentCollection).join(","));
new RawSource(Array.from(appComponentCollection).join(','));
compilation.assets['./module_collection.txt'] =
new RawSource(moduleCollection.size === 0 ? 'NULL' : Array.from(moduleCollection).join(","));
new RawSource(moduleCollection.size === 0 ? 'NULL' : Array.from(moduleCollection).join(','));
callback();
});
})
});
}
}
@@ -257,7 +257,7 @@ export class ResultStates {
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)?'\./;
/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) ||
+6 -1
View File
@@ -78,17 +78,22 @@ export interface ExtendParamterInterfance {
export const EXTEND_ATTRIBUTE: Map<string, Set<ExtendParamterInterfance>> = 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',
'PanGestureOption', 'CustomDialogController', 'Storage', 'Scroller', 'SwiperController',
'TabsController', 'CalendarController', 'AbilityController', 'VideoController', 'WebController',
'XComponentController', 'CanvasRenderingContext2D', 'CanvasGradient', 'ImageBitmap', 'ImageData',
'Path2D', 'RenderingContextSettings', 'OffscreenCanvasRenderingContext2D', 'DatePickerDialog',
'TextPickerDialog', 'AlertDialog', 'ActionSheet', 'PatternLockController'
'TextPickerDialog', 'AlertDialog', 'ContextMenu', 'ActionSheet', 'PatternLockController'
]);
export const NEEDPOP_COMPONENT: Set<string> = new Set(['Blank', 'Search']);
export const CUSTOM_BUILDER_PROPERTIES: Set<string> = new Set(['bindPopup', 'bindMenu', 'bindContextMenu', 'title',
'menus', 'toolBar', 'tabBar']);
(function initComponent() {
Object.keys(COMPONENT_MAP).forEach((componentName) => {
INNER_COMPONENT_NAMES.add(componentName);
+6 -1
View File
@@ -17,6 +17,7 @@ import path from 'path';
export const NATIVE_MODULE: Set<string> = new Set(
['system.app', 'ohos.app', 'system.router', 'system.curves', 'ohos.curves', 'system.matrix4', 'ohos.matrix4']);
export const VALIDATE_MODULE: string[] = ['application', 'util', 'screen'];
export const SYSTEM_PLUGIN: string = 'system';
export const OHOS_PLUGIN: string = 'ohos';
@@ -182,14 +183,18 @@ export const GEOMETRY_VIEW: string = 'GeometryView';
export const MODULE_SHARE_PATH: string = 'src' + path.sep + 'ets' + path.sep + 'share';
export const BUILD_SHARE_PATH: string = '../share';
export const CHILD: string = 'child';
export const THIS: string = 'this';
export const STYLES: string = 'Styles';
export const VISUAL_STATE: string = 'visualState';
export const VIEW_STACK_PROCESSOR: string = 'ViewStackProcessor';
export const BIND_POPUP: string = 'bindPopup';
export const CHECKED: string = 'checked';
export const RADIO: string = 'Radio';
export const $$_VALUE: string = 'value';
export const $$_CHANGE_EVENT: string = 'changeEvent';
export const $$_THIS: string = '$$this';
export const $$_NEW_VALUE: string = 'newValue';
export const INTERFACE_NAME_SUFFIX:string = '_Params';
export const OBSERVED_PROPERTY_ABSTRACT:string = 'ObservedPropertyAbstract';
+9 -9
View File
@@ -52,25 +52,25 @@ function preProcess(source: string): string {
function parseVisual(resourcePath: string, content: string, log: LogInfo[]): string {
if (componentCollection.entryComponent && projectConfig.aceSuperVisualPath) {
const sourceFile: ts.SourceFile = ts.createSourceFile(resourcePath, content,
ts.ScriptTarget.Latest, true, ts.ScrpitKint.TS);
if (sourceFile.statments) {
sourceFile.statments.forEach(statment => {
content = parseStatment(statment, content, log, resourcePath);
ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
if (sourceFile.statements) {
sourceFile.statements.forEach(statement => {
content = parseStatement(statement, content, log, resourcePath);
});
}
}
return content;
}
function parseStatment(statement: ts.Statement, content: string, log: LogInfo[],
function parseStatement(statement: ts.Statement, content: string, log: LogInfo[],
resourcePath: string): string {
if (statement.kind === ts.SyntaxKind.ClassDeclaration &&
statement.name && statement.name.getText() === componentCollection.entryComponent) {
const visualPath: string = findVisualFile(resourcePath);
if (visualPath && fs.existsSync(visualPath) && statement.members) {
statement.members.forEach(member => {
if (member.kind && member === ts.SyntaxKind.MethodDeclaration) {
content = parseMember(member, content, log, visualPath)
if (member.kind && member.kind === ts.SyntaxKind.MethodDeclaration) {
content = parseMember(member, content, log, visualPath);
}
});
}
@@ -108,7 +108,7 @@ function findVisualFile(filePath: string): string {
function getVisualContent(visualPath: string, log: LogInfo[], pos: number): string {
const parseContent: any = genETS(fs.readFileSync(visualPath, 'utf-8'));
if (parseContent && parseContent.errorType && parseContent.errorType != '') {
if (parseContent && parseContent.errorType && parseContent.errorType !== '') {
log.push({
type: LogType.ERROR,
message: parseContent.message,
@@ -118,4 +118,4 @@ function getVisualContent(visualPath: string, log: LogInfo[], pos: number): stri
return parseContent ? parseContent.ets : null;
}
module.exports = preProcess;
module.exports = preProcess;
+221 -45
View File
@@ -45,7 +45,6 @@ import {
COMPONENT_TRANSITION_NAME,
COMPONENT_DEBUGLINE_FUNCTION,
ATTRIBUTE_STATESTYLES,
CHILD,
THIS,
VISUAL_STATE,
VIEW_STACK_PROCESSOR,
@@ -53,7 +52,12 @@ import {
$$_VALUE,
$$_CHANGE_EVENT,
$$_THIS,
$$_NEW_VALUE
$$_NEW_VALUE,
CHECKED,
RADIO,
BUILDER_ATTR_NAME,
BUILDER_ATTR_BIND,
CUSTOM_DIALOG_CONTROLLER_BUILDER
} from './pre_define';
import {
INNER_COMPONENT_NAMES,
@@ -67,7 +71,8 @@ import {
NEEDPOP_COMPONENT,
INNER_STYLE_FUNCTION,
GLOBAL_STYLE_FUNCTION,
COMMON_ATTRS
COMMON_ATTRS,
CUSTOM_BUILDER_PROPERTIES
} from './component_map';
import { componentCollection } from './validate_ui_syntax';
import { processCustomComponent } from './process_custom_component';
@@ -169,15 +174,17 @@ export function processComponentChild(node: ts.Block | ts.SourceFile, newStateme
break;
case ComponentType.customComponent:
if (index + 1 < array.length && ts.isBlock(array[index + 1])) {
item = processBlockChange(item,
array[index + 1] as ts.Block, log)
if (processExpressionStatementChange(item, array[index + 1] as ts.Block, log)) {
item = processExpressionStatementChange(item, array[index + 1] as ts.Block, log);
}
}
processCustomComponent(item, newStatements, log);
processCustomComponent(item as ts.ExpressionStatement, newStatements, log);
break;
case ComponentType.forEachComponent:
processForEachComponent(item, newStatements, log);
break;
case ComponentType.customBuilderMethod || ComponentType.builderParamMethod:
case ComponentType.customBuilderMethod:
case ComponentType.builderParamMethod:
newStatements.push(item);
break;
}
@@ -195,28 +202,47 @@ export function processComponentChild(node: ts.Block | ts.SourceFile, newStateme
}
}
function processBlockChange(node: ts.ExpressionStatement, nextNode: ts.Block,
log: LogInfo[]): ts.block {
function processExpressionStatementChange(node: ts.ExpressionStatement, nextNode: ts.Block,
log: LogInfo[]): ts.ExpressionStatement {
let name: string;
// @ts-ignore
if (node.expression.expression && ts.isIdentifier(node.expression.expression)) {
name = node.expression.expression.escapedText.toString();
}
if (builderParamObjectCollection.get(name) &&
builderParamObjectCollection.get(name).size === 1) {
return processBlockToExpression(node, nextNode, log, name);
} else {
log.push({
type: LogType.ERROR,
message: `In the trailing lambda case, '${name}' must have one and only one property decorated with `
+ `@BuilderParam, and its @BuilderParam expects no parameter.`,
pos: node.getStart()
});
}
}
function processBlockToExpression(node: ts.ExpressionStatement, nextNode: ts.Block,
log: LogInfo[], name: string): ts.ExpressionStatement {
const childParam: string = [...builderParamObjectCollection.get(name)].slice(-1)[0];
const newBlock: ts.Block = processComponentBlock(nextNode, false, log);
const arrowNode: ts.ArrowFunction = ts.factory.createArrowFunction(undefined, undefined,
[], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), newBlock);
const newPropertyAssignment:ts.PropertyAssignment = ts.factory.createPropertyAssignment(
ts.factory.createIdentifier(CHILD), arrowNode);
ts.factory.createIdentifier(childParam), arrowNode);
// @ts-ignore
let argumentsArray: ts.ObjectLiteralExpression[] = node.express.arguments;
if (arguments && arguments.length < 1) {
argumentsArray = [ts.factory.createObjectLiteralExpression([newPropertyAssignment], true)]
let argumentsArray: ts.ObjectLiteralExpression[] = node.expression.arguments;
if (argumentsArray && !argumentsArray.length) {
argumentsArray = [ts.factory.createObjectLiteralExpression([newPropertyAssignment], true)];
} else {
// @ts-ignore
argumentsArray = [ts.factory.createObjectLiteralExpression(
// @ts-ignore
node.express.arguments[0].properties.concat([newPropertyAssignment]), true)]
node.expression.arguments[0].properties.concat([newPropertyAssignment]), true)];
}
// @ts-ignore
node = ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(node.expression,
node = ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(
// @ts-ignore
node.expression.expression, node.expression.expression,typeArguments, argumentsArray))
node.expression, node.expression.expression, node.expression.expression.typeArguments,
argumentsArray));
return node;
}
@@ -491,21 +517,31 @@ interface AnimationInfo {
export function bindComponentAttr(node: ts.ExpressionStatement, identifierNode: ts.Identifier,
newStatements: ts.Statement[], log: LogInfo[], reverse: boolean = true,
isStylesAttr: boolean = false): void {
isStylesAttr: boolean = false, isGlobalStyles: boolean = false): void {
let temp: any = node.expression;
const statements: ts.Statement[] = [];
const lastStatement: AnimationInfo = { statement: null, kind: false };
while (temp && ts.isCallExpression(temp) && temp.expression) {
if (temp.expression && (validatePropertyAccessExpressionWithCustomBuilder(temp.expression) ||
validateIdentifierWithCustomBuilder(temp.expression))) {
let propertyName: string = '';
if (ts.isIdentifier(temp.expression)) {
propertyName = temp.expression.escapedText.toString();
} else if (ts.isPropertyAccessExpression(temp.expression)) {
propertyName = temp.expression.name.escapedText.toString();
}
temp = propertyName === BIND_POPUP ? processBindPopupBuilder(temp) : processCustomBuilderProperty(temp);
}
if (ts.isPropertyAccessExpression(temp.expression) &&
temp.expression.name && ts.isIdentifier(temp.expression.name)) {
addComponentAttr(temp, temp.expression.name, lastStatement, statements, identifierNode, log,
isStylesAttr);
isStylesAttr, isGlobalStyles);
temp = temp.expression.expression;
} else if (ts.isIdentifier(temp.expression)) {
if (!INNER_COMPONENT_NAMES.has(temp.expression.getText()) &&
!GESTURE_TYPE_NAMES.has(temp.expression.getText())) {
addComponentAttr(temp, temp.expression, lastStatement, statements, identifierNode, log,
isStylesAttr);
isStylesAttr, isGlobalStyles);
}
break;
}
@@ -518,7 +554,131 @@ export function bindComponentAttr(node: ts.ExpressionStatement, identifierNode:
}
}
function createArrowFunctionFor$$ ($$varExp: ts.Expression): ts.ArrowFunction {
function processCustomBuilderProperty(node: ts.CallExpression): ts.CallExpression {
const newArguments: ts.Expression[] = [];
node.arguments.forEach((argument: ts.Expression | ts.Identifier, index: number) => {
if (index === 0 && isBuilderChangeNode(argument)) {
newArguments.push(parseBuilderNode(argument));
} else {
newArguments.push(argument);
}
});
node = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, newArguments);
return node;
}
function isBuilderChangeNode(argument: ts.Node): boolean {
return (ts.isPropertyAccessExpression(argument) && argument.name && ts.isIdentifier(argument.name)
&& CUSTOM_BUILDER_METHOD.has(argument.name.getText())) ||
(ts.isCallExpression(argument) && argument.expression && argument.expression.name &&
ts.isIdentifier(argument.expression.name) &&
CUSTOM_BUILDER_METHOD.has(argument.expression.name.getText())) || (ts.isIdentifier(argument) &&
argument.escapedText && CUSTOM_BUILDER_METHOD.has(argument.escapedText.toString()));
}
function parseBuilderNode(node: ts.Node): ts.ObjectLiteralExpression {
if (isPropertyAccessExpressionNode(node)) {
return processPropertyBuilder(node as ts.PropertyAccessExpression);
} else if (ts.isIdentifier(node) && CUSTOM_BUILDER_METHOD.has(node.escapedText.toString())) {
return processIdentifierBuilder(node);
} else if (ts.isCallExpression(node)) {
return getParsedBuilderAttrArgumentWithParams(node);
}
}
function isPropertyAccessExpressionNode(node: ts.Node): boolean {
return ts.isPropertyAccessExpression(node) && node.expression &&
node.expression.kind === ts.SyntaxKind.ThisKeyword && node.name && ts.isIdentifier(node.name) &&
CUSTOM_BUILDER_METHOD.has(node.name.escapedText.toString());
}
function processBindPopupBuilder(node: ts.CallExpression): ts.CallExpression {
const newArguments: ts.Expression[] = [];
node.arguments.forEach((argument: ts.ObjectLiteralExpression, index: number) => {
if (index === 1) {
// @ts-ignore
newArguments.push(processBindPopupBuilderProperty(argument));
} else {
newArguments.push(argument);
}
});
node = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, newArguments);
return node;
}
function processBindPopupBuilderProperty(node: ts.ObjectLiteralExpression): ts.ObjectLiteralExpression {
const newProperties: ts.PropertyAssignment[] = [];
node.properties.forEach((property: ts.PropertyAssignment, index: number) => {
if (index === 0) {
if (property.name && ts.isIdentifier(property.name) &&
property.name.escapedText.toString() === CUSTOM_DIALOG_CONTROLLER_BUILDER) {
newProperties.push(ts.factory.updatePropertyAssignment(property, property.name,
parseBuilderNode(property.initializer)));
} else {
newProperties.push(property);
}
} else {
newProperties.push(property);
}
});
return ts.factory.updateObjectLiteralExpression(node, newProperties);
}
function processPropertyBuilder(node: ts.PropertyAccessExpression): ts.ObjectLiteralExpression {
return ts.factory.createObjectLiteralExpression([
ts.factory.createPropertyAssignment(
ts.factory.createIdentifier(BUILDER_ATTR_NAME),
ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(
node,
ts.factory.createIdentifier(BUILDER_ATTR_BIND)
),
undefined,
[ts.factory.createThis()]
)
)
]);
}
function processIdentifierBuilder(node: ts.Identifier): ts.ObjectLiteralExpression {
return ts.factory.createObjectLiteralExpression([
ts.factory.createPropertyAssignment(
ts.factory.createIdentifier(BUILDER_ATTR_NAME),
node
)
]);
}
function getParsedBuilderAttrArgumentWithParams(node: ts.CallExpression):
ts.ObjectLiteralExpression {
return ts.factory.createObjectLiteralExpression([
ts.factory.createPropertyAssignment(
ts.factory.createIdentifier(BUILDER_ATTR_NAME),
ts.factory.createArrowFunction(
undefined,
undefined,
[],
undefined,
ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
ts.factory.createBlock(
[ts.factory.createExpressionStatement(node)],
true
)
)
)
]);
}
function validatePropertyAccessExpressionWithCustomBuilder(node: ts.Node): boolean {
return ts.isPropertyAccessExpression(node) && node.name &&
ts.isIdentifier(node.name) && CUSTOM_BUILDER_PROPERTIES.has(node.name.escapedText.toString());
}
function validateIdentifierWithCustomBuilder(node: ts.Node): boolean {
return ts.isIdentifier(node) && CUSTOM_BUILDER_PROPERTIES.has(node.escapedText.toString());
}
function createArrowFunctionFor$$($$varExp: ts.Expression): ts.ArrowFunction {
return ts.factory.createArrowFunction(
undefined, undefined,
[ts.factory.createParameterDeclaration(
@@ -541,8 +701,8 @@ function createArrowFunctionFor$$ ($$varExp: ts.Expression): ts.ArrowFunction {
function updateArgumentFor$$(argument: any): ts.Expression {
if (ts.isElementAccessExpression(argument)) {
return ts.factory.updateElementAccessExpression
(argument, updateArgumentFor$$(argument.expression), argument.argumentExpression);
return ts.factory.updateElementAccessExpression(
argument, updateArgumentFor$$(argument.expression), argument.argumentExpression);
} else if (ts.isIdentifier(argument)) {
props.push(argument.getText());
if (argument.getText() === $$_THIS) {
@@ -551,14 +711,14 @@ function updateArgumentFor$$(argument: any): ts.Expression {
return ts.factory.createIdentifier(argument.getText().replace(/\$\$/, ''));
}
} else if (ts.isPropertyAccessExpression(argument)) {
return ts.factory.updatePropertyAccessExpression
(argument, updateArgumentFor$$(argument.expression), argument.name);
return ts.factory.updatePropertyAccessExpression(
argument, updateArgumentFor$$(argument.expression), argument.name);
}
}
function addComponentAttr(temp: any, node: ts.Identifier, lastStatement: any,
statements: ts.Statement[], identifierNode: ts.Identifier, log: LogInfo[],
isStylesAttr: boolean): void {
isStylesAttr: boolean, isGlobalStyles: boolean): void {
const propName: string = node.getText();
if (propName === ATTRIBUTE_ANIMATION) {
if (!lastStatement.statement) {
@@ -595,15 +755,18 @@ function addComponentAttr(temp: any, node: ts.Identifier, lastStatement: any,
} else if (GLOBAL_STYLE_FUNCTION.has(propName) || INNER_STYLE_FUNCTION.has(propName)) {
const styleBlock: ts.Block =
GLOBAL_STYLE_FUNCTION.get(propName) || INNER_STYLE_FUNCTION.get(propName);
bindComponentAttr(styleBlock.statements[0] as ts.ExpressionStatement, identifierNode,
statements, log, false, true);
if (GLOBAL_STYLE_FUNCTION.has(propName)) {
bindComponentAttr(styleBlock.statements[0] as ts.ExpressionStatement, identifierNode,
statements, log, false, true, true);
} else {
bindComponentAttr(styleBlock.statements[0] as ts.ExpressionStatement, identifierNode,
statements, log, false, true, false);
}
lastStatement.kind = true;
} else if (propName === BIND_POPUP && temp.arguments.length === 2 &&
temp.arguments[0].getText().match(/^\$\$(.|\n)+/)) {
} else if (!isStylesAttr && [BIND_POPUP, CHECKED].includes(propName) &&
temp.arguments.length && temp.arguments[0] && temp.arguments[0].getText().match(/^\$\$(.|\n)+/)) {
const argumentsArr: ts.Expression[] = [];
const varExp: ts.Expression = updateArgumentFor$$(temp.arguments[0]);
argumentsArr.push(generateObjectFor$$(varExp));
argumentsArr.push(temp.arguments[1]);
classifyArgumentsNum(temp.arguments, argumentsArr, propName, identifierNode);
statements.push(ts.factory.createExpressionStatement(
createFunction(identifierNode, node, argumentsArr)));
lastStatement.kind = true;
@@ -612,8 +775,10 @@ function addComponentAttr(temp: any, node: ts.Identifier, lastStatement: any,
if (!COMMON_ATTRS.has(propName)) {
validateStateStyleSyntax(temp, log);
}
for (let i=0; i<temp.arguments.length; i++) {
temp.arguments[i] = traverseStylesAttr(temp.arguments[i]);
if (isGlobalStyles) {
for (let i = 0; i < temp.arguments.length; i++) {
temp.arguments[i] = traverseStylesAttr(temp.arguments[i]);
}
}
}
statements.push(ts.factory.createExpressionStatement(
@@ -622,6 +787,17 @@ function addComponentAttr(temp: any, node: ts.Identifier, lastStatement: any,
}
}
function classifyArgumentsNum(args: any, argumentsArr: ts.Expression[], propName: string,
identifierNode: ts.Identifier): void {
if (propName === BIND_POPUP && args.length === 2) {
const varExp: ts.Expression = updateArgumentFor$$(args[0]);
argumentsArr.push(generateObjectFor$$(varExp), args[1]);
} else if (propName === CHECKED && args.length === 1 && identifierNode.getText() === RADIO) {
const varExp: ts.Expression = updateArgumentFor$$(args[0]);
argumentsArr.push(varExp, createArrowFunctionFor$$(varExp));
}
}
function traverseStylesAttr(node: ts.Node): ts.Node {
if (ts.isStringLiteral(node)) {
node = ts.factory.createStringLiteral(node.text);
@@ -679,15 +855,15 @@ function traverseStateStylesAttr(temp: any, statements: ts.Statement[],
} else if (ts.isObjectLiteralExpression(item.initializer) &&
item.initializer.properties.length === 1 &&
ts.isPropertyAssignment(item.initializer.properties[0])) {
bindComponentAttr(ts.factory.createExpressionStatement
(item.initializer.properties[0].initializer), identifierNode, statements, log, false, true);
bindComponentAttr(ts.factory.createExpressionStatement(
item.initializer.properties[0].initializer), identifierNode, statements, log, false, true);
} else {
validateStateStyleSyntax(temp, log);
}
if (item.name) {
statements.push(createViewStackProcessor(item, false));
}
})
});
}
function isExtendFunctionNode(identifierNode: ts.Identifier, propName: string): boolean {
@@ -808,8 +984,8 @@ export function isAttributeNode(node: ts.ExpressionStatement): boolean {
function validateFirstNode(node: ts.Statement): boolean {
const isEntryComponent: boolean =
componentCollection.entryComponent === componentCollection.currentClassName;
if ((isEntryComponent && validateEntryComponent(node)) ||
(!isEntryComponent && validateCustomComponent(node))) {
if (isEntryComponent && validateEntryComponent(node) ||
!isEntryComponent && validateCustomComponent(node)) {
return true;
}
return false;
@@ -824,8 +1000,8 @@ function validateEntryComponent(node: ts.Statement): boolean {
function validateCustomComponent(node: ts.Statement): boolean {
if (ts.isIfStatement(node) ||
(ts.isExpressionStatement(node) && (INNER_COMPONENT_NAMES.has(getName(node)) ||
componentCollection.customComponents.has(getName(node))))) {
ts.isExpressionStatement(node) && (INNER_COMPONENT_NAMES.has(getName(node)) ||
componentCollection.customComponents.has(getName(node)))) {
return true;
}
return false;
@@ -864,10 +1040,10 @@ function getComponentType(node: ts.ExpressionStatement, log: LogInfo[],
return ComponentType.forEachComponent;
} else if (CUSTOM_BUILDER_METHOD.has(name)) {
return ComponentType.customBuilderMethod;
} else if (builderParamObjectCollection.get(componentCollection.currentClassName) &&
} else if (builderParamObjectCollection.get(componentCollection.currentClassName) &&
builderParamObjectCollection.get(componentCollection.currentClassName).has(name)) {
return ComponentType.builderParamMethod;
}else if (!isAttributeNode(node)) {
} else if (!isAttributeNode(node)) {
log.push({
type: LogType.ERROR,
message: `'${node.getText()}' does not meet UI component syntax.`,
+94 -85
View File
@@ -16,6 +16,19 @@
import ts from 'typescript';
import {
COMPONENT_STATE_DECORATOR,
COMPONENT_PROVIDE_DECORATOR,
COMPONENT_LINK_DECORATOR,
COMPONENT_PROP_DECORATOR,
COMPONENT_STORAGE_LINK_DECORATOR,
COMPONENT_STORAGE_PROP_DECORATOR,
COMPONENT_OBJECT_LINK_DECORATOR,
COMPONENT_CONSUME_DECORATOR,
SYNCHED_PROPERTY_NESED_OBJECT,
SYNCHED_PROPERTY_SIMPLE_TWO_WAY,
SYNCHED_PROPERTY_SIMPLE_ONE_WAY,
OBSERVED_PROPERTY_OBJECT,
OBSERVED_PROPERTY_SIMPLE,
COMPONENT_BUILD_FUNCTION,
BASE_COMPONENT_NAME,
ATTRIBUTE_ANIMATETO,
@@ -34,16 +47,16 @@ import {
COMPONENT_TRANSITION_FUNCTION,
COMPONENT_CREATE_FUNCTION,
GEOMETRY_VIEW,
BUILDER_ATTR_NAME,
BUILDER_ATTR_BIND,
COMPONENT_STYLES_DECORATOR,
STYLES,
CUSTOM_COMPONENT_EARLIER_CREATE_CHILD
INTERFACE_NAME_SUFFIX,
OBSERVED_PROPERTY_ABSTRACT
} from './pre_define';
import {
BUILDIN_STYLE_NAMES,
CUSTOM_BUILDER_METHOD,
INNER_STYLE_FUNCTION,
INTERFACE_NODE_SET,
STYLES_ATTRIBUTE
} from './component_map';
import {
@@ -60,7 +73,8 @@ import {
UpdateResult,
stateObjectCollection,
curPropMap,
decoratorParamSet
decoratorParamSet,
isSimpleType
} from './process_component_member';
import {
processComponentBuild,
@@ -109,11 +123,14 @@ function processMembers(members: ts.NodeArray<ts.ClassElement>, parentComponentN
const deleteParamsStatements: ts.PropertyDeclaration[] = [];
const checkController: ControllerType =
{ hasController: !componentCollection.customDialogs.has(parentComponentName.getText()) };
const interfaceNode = ts.factory.createInterfaceDeclaration(undefined, undefined,
parentComponentName.getText() + INTERFACE_NAME_SUFFIX, undefined, undefined, []);
members.forEach((item: ts.ClassElement) => {
let updateItem: ts.ClassElement;
if (ts.isPropertyDeclaration(item)) {
addPropertyMember(item, newMembers, program);
const result: UpdateResult = processMemberVariableDecorators(parentComponentName, item,
ctorNode, watchMap, checkController, log, program, context, hasPreview);
ctorNode, watchMap, checkController, log, program, context, hasPreview, interfaceNode);
if (result.isItemUpdate()) {
updateItem = result.getProperity();
} else {
@@ -146,14 +163,74 @@ function processMembers(members: ts.NodeArray<ts.ClassElement>, parentComponentN
newMembers.push(updateItem);
}
});
INTERFACE_NODE_SET.add(interfaceNode);
validateBuildMethodCount(buildCount, parentComponentName, log);
validateHasController(parentComponentName, checkController, log);
newMembers.unshift(addDeleteParamsFunc(deleteParamsStatements));
newMembers.unshift(addUpdateParamsFunc(updateParamsStatements));
newMembers.unshift(addConstructor(ctorNode, watchMap));
newMembers.unshift(addUpdateParamsFunc(updateParamsStatements, parentComponentName));
newMembers.unshift(addConstructor(ctorNode, watchMap, parentComponentName));
return newMembers;
}
function addPropertyMember(item: ts.ClassElement, newMembers: ts.ClassElement[],
program: ts.Program):void {
const propertyItem: ts.PropertyDeclaration = item as ts.PropertyDeclaration;
let decoratorName: string;
let updatePropertyItem: ts.PropertyDeclaration;
const type: ts.TypeNode = propertyItem.type;
if (!propertyItem.decorators || propertyItem.decorators.length === 0) {
updatePropertyItem = createPropertyDeclaration(propertyItem, type, true);
newMembers.push(updatePropertyItem);
} else if (propertyItem.decorators) {
for (let i = 0; i < propertyItem.decorators.length; i++) {
let newType: ts.TypeNode;
decoratorName = propertyItem.decorators[i].getText().replace(/\(.*\)$/, '').trim();
switch (decoratorName) {
case COMPONENT_STATE_DECORATOR:
case COMPONENT_PROVIDE_DECORATOR:
newType = ts.factory.createTypeReferenceNode(isSimpleType(type, program) ?
OBSERVED_PROPERTY_SIMPLE : OBSERVED_PROPERTY_OBJECT, [type]);
break;
case COMPONENT_LINK_DECORATOR:
case COMPONENT_CONSUME_DECORATOR:
newType = ts.factory.createTypeReferenceNode(isSimpleType(type, program) ?
SYNCHED_PROPERTY_SIMPLE_TWO_WAY : SYNCHED_PROPERTY_SIMPLE_ONE_WAY, [type]);
break;
case COMPONENT_PROP_DECORATOR:
newType = ts.factory.createTypeReferenceNode(SYNCHED_PROPERTY_SIMPLE_ONE_WAY, [type]);
break;
case COMPONENT_OBJECT_LINK_DECORATOR:
newType = ts.factory.createTypeReferenceNode(SYNCHED_PROPERTY_NESED_OBJECT, [type]);
break;
case COMPONENT_STORAGE_PROP_DECORATOR:
case COMPONENT_STORAGE_LINK_DECORATOR:
newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [type]);
break;
}
updatePropertyItem = createPropertyDeclaration(propertyItem, newType, false);
if (updatePropertyItem) {
newMembers.push(updatePropertyItem);
}
}
}
}
function createPropertyDeclaration(propertyItem: ts.PropertyDeclaration, newType: ts.TypeNode | undefined,
normalVar: boolean): ts.PropertyDeclaration {
if (typeof newType === undefined) {
return undefined;
}
let prefix: string = '';
if (!normalVar) {
prefix = '__';
}
const privateM: ts.ModifierToken<ts.SyntaxKind.PrivateKeyword> =
ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword);
return ts.factory.updatePropertyDeclaration(propertyItem, undefined,
propertyItem.modifiers || [privateM], prefix + propertyItem.name.getText(),
propertyItem.questionToken, newType, undefined);
}
function processComponentMethod(node: ts.MethodDeclaration, parentComponentName: ts.Identifier,
context: ts.TransformationContext, log: LogInfo[], buildCount: BuildCount): ts.MethodDeclaration {
let updateItem: ts.MethodDeclaration = node;
@@ -212,9 +289,6 @@ function processBuildMember(node: ts.MethodDeclaration, context: ts.Transformati
const buildNode: ts.MethodDeclaration = processComponentBuild(node, log);
return ts.visitNode(buildNode, visitBuild);
function visitBuild(node: ts.Node): ts.Node {
if (isCustomComponentNode(node)) {
return node;
}
if (isGeometryView(node)) {
node = processGeometryView(node as ts.ExpressionStatement, log);
}
@@ -229,80 +303,10 @@ function processBuildMember(node: ts.MethodDeclaration, context: ts.Transformati
ts.factory.createIdentifier(FOREACH_OBSERVED_OBJECT),
ts.factory.createIdentifier(FOREACH_GET_RAW_OBJECT)), undefined, [node]);
}
if ((ts.isIdentifier(node) || ts.isPropertyAccessExpression(node)) &&
validateBuilderFunctionNode(node)) {
return getParsedBuilderAttrArgument(node);
}
return ts.visitEachChild(node, visitBuild, context);
}
}
function validateBuilderFunctionNode(node: ts.PropertyAccessExpression | ts.Identifier): boolean {
if (((ts.isPropertyAccessExpression(node) && node.expression && node.name &&
node.expression.kind === ts.SyntaxKind.ThisKeyword && ts.isIdentifier(node.name) &&
CUSTOM_BUILDER_METHOD.has(node.name.escapedText.toString())) ||
ts.isIdentifier(node) && CUSTOM_BUILDER_METHOD.has(node.escapedText.toString())) &&
!((ts.isPropertyAccessExpression(node) && validateBuilderParam(node)) ||
(ts.isIdentifier(node) && node.parent && ts.isPropertyAccessExpression(node.parent) &&
validateBuilderParam(node.parent)))) {
return true;
} else {
return false;
}
}
function validateBuilderParam(node: ts.PropertyAccessExpression): boolean {
if (node.parent && ts.isCallExpression(node.parent) && node.parent.expression === node) {
return true;
} else {
return false;
}
}
function getParsedBuilderAttrArgument(node: ts.PropertyAccessExpression | ts.Identifier):
ts.ObjectLiteralExpression {
let newObjectNode: ts.ObjectLiteralExpression = null;
if (ts.isPropertyAccessExpression(node)) {
newObjectNode = ts.factory.createObjectLiteralExpression([
ts.factory.createPropertyAssignment(
ts.factory.createIdentifier(BUILDER_ATTR_NAME),
ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(
node,
ts.factory.createIdentifier(BUILDER_ATTR_BIND)
),
undefined,
[ts.factory.createThis()]
)
)
]);
} else if (ts.isIdentifier(node)) {
newObjectNode = ts.factory.createObjectLiteralExpression([
ts.factory.createPropertyAssignment(
ts.factory.createIdentifier(BUILDER_ATTR_NAME),
node
)
])
}
return newObjectNode;
}
function isCustomComponentNode(node:ts.NewExpression | ts.ExpressionStatement): boolean {
if ((ts.isNewExpression(node) && ts.isIdentifier(node.expression) && node.expression.escapedText
&& componentCollection.customComponents.has(node.expression.escapedText.toString())) ||
// @ts-ignore
(ts.isExpressionStatement(node) && node.expression && node.expression.expression &&
// @ts-ignore
node.expression.expression.expression && node.expression.expression.expression.escapedText &&
// @ts-ignore
node.expression.expression.expression.escapedText.toString().startsWith(
CUSTOM_COMPONENT_EARLIER_CREATE_CHILD))) {
return true;
}else {
return false;
}
}
function isGeometryView(node: ts.Node): boolean {
if (ts.isExpressionStatement(node) && ts.isCallExpression(node.expression)) {
const call: ts.CallExpression = node.expression;
@@ -436,8 +440,9 @@ function processAnimateTo(node: ts.CallExpression): ts.CallExpression {
node.typeArguments, node.arguments);
}
function addUpdateParamsFunc(statements: ts.Statement[]): ts.MethodDeclaration {
return createParamsInitBlock(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, statements);
function addUpdateParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier):
ts.MethodDeclaration {
return createParamsInitBlock(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, statements, parentComponentName);
}
function addDeleteParamsFunc(statements: ts.PropertyDeclaration[]): ts.MethodDeclaration {
@@ -467,13 +472,17 @@ function addDeleteParamsFunc(statements: ts.PropertyDeclaration[]): ts.MethodDec
return deleteParamsMethod;
}
function createParamsInitBlock(express: string, statements: ts.Statement[]): ts.MethodDeclaration {
function createParamsInitBlock(express: string, statements: ts.Statement[],
parentComponentName?: ts.Identifier): ts.MethodDeclaration {
const methodDeclaration: ts.MethodDeclaration = ts.factory.createMethodDeclaration(undefined,
undefined, undefined, ts.factory.createIdentifier(express), undefined, undefined,
[ts.factory.createParameterDeclaration(undefined, undefined, undefined,
express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined :
ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS), undefined, undefined, undefined)],
undefined, ts.factory.createBlock(statements, true));
ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS), undefined,
express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined :
ts.factory.createTypeReferenceNode(
ts.factory.createIdentifier(parentComponentName.getText() + INTERFACE_NAME_SUFFIX), undefined),
undefined)], undefined, ts.factory.createBlock(statements, true));
return methodDeclaration;
}
+46 -8
View File
@@ -20,7 +20,9 @@ import {
COMPONENT_CONSTRUCTOR_PARENT,
COMPONENT_CONSTRUCTOR_PARAMS,
COMPONENT_CONSTRUCTOR_UPDATE_PARAMS,
COMPONENT_WATCH_FUNCTION
COMPONENT_WATCH_FUNCTION,
BASE_COMPONENT_NAME,
INTERFACE_NAME_SUFFIX
} from './pre_define';
export function getInitConstructor(members: ts.NodeArray<ts.Node>): ts.ConstructorDeclaration {
@@ -35,7 +37,8 @@ export function getInitConstructor(members: ts.NodeArray<ts.Node>): ts.Construct
export function updateConstructor(ctorNode: ts.ConstructorDeclaration,
para: ts.ParameterDeclaration[], addStatements: ts.Statement[],
isSuper: boolean = false): ts.ConstructorDeclaration {
isSuper: boolean = false, isAdd: boolean = false, parentComponentName?: ts.Identifier):
ts.ConstructorDeclaration {
let modifyPara: ts.ParameterDeclaration[];
if (para && para.length) {
modifyPara = Array.from(ctorNode.parameters);
@@ -55,15 +58,50 @@ 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, modifyPara || ctorNode.parameters,
ts.factory.createBlock(modifyBody || ctorNode.body.statements, true));
ctorNode.modifiers, ctorPara, ts.factory.createBlock(modifyBody || ctorNode.body.statements, true));
}
return ctorNode;
}
export function addConstructor(ctorNode: any, watchMap: Map<string, ts.Node>)
: ts.ConstructorDeclaration {
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);
});
return newTSPara;
}
export function addConstructor(ctorNode: any, watchMap: Map<string, ts.Node>,
parentComponentName: ts.Identifier): ts.ConstructorDeclaration {
const watchStatements: ts.ExpressionStatement[] = [];
watchMap.forEach((value, key) => {
const watchNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(
@@ -77,7 +115,7 @@ export function addConstructor(ctorNode: any, watchMap: Map<string, ts.Node>)
ts.factory.createStringLiteral(key),
ts.isStringLiteral(value) ?
ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
ts.factory.createIdentifier(value.text)) : value as ts.PropertyAccessExpression
ts.factory.createIdentifier(value.text)) : value as ts.PropertyAccessExpression
]
));
watchStatements.push(watchNode);
@@ -91,5 +129,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);
[updateWithValueParamsStatement, ...watchStatements], false, true, parentComponentName);
}
+34 -27
View File
@@ -104,7 +104,7 @@ export const setUpdateParamsDecorators: Set<string> =
]);
export const immutableDecorators: Set<string> =
new Set([COMPONENT_STORAGE_PROP_DECORATOR, COMPONENT_OBJECT_LINK_DECORATOR]);
new Set([COMPONENT_STORAGE_PROP_DECORATOR, COMPONENT_OBJECT_LINK_DECORATOR, COMPONENT_BUILDERPARAM_DECORATOR]);
export const simpleTypes: Set<ts.SyntaxKind> = new Set([ts.SyntaxKind.StringKeyword,
ts.SyntaxKind.NumberKeyword, ts.SyntaxKind.BooleanKeyword, ts.SyntaxKind.EnumDeclaration]);
@@ -197,8 +197,8 @@ export const curPropMap: Map<string, string> = new Map();
export function processMemberVariableDecorators(parentName: ts.Identifier,
item: ts.PropertyDeclaration, ctorNode: ts.ConstructorDeclaration, watchMap: Map<string, ts.Node>,
checkController: ControllerType, log: LogInfo[], program: ts.Program,
context: ts.TransformationContext, hasPreview: boolean): UpdateResult {
checkController: ControllerType, log: LogInfo[], program: ts.Program, context: ts.TransformationContext,
hasPreview: boolean, interfaceNode: ts.InterfaceDeclaration): UpdateResult {
const updateResult: UpdateResult = new UpdateResult();
const name: ts.Identifier = item.name as ts.Identifier;
if (!item.decorators || !item.decorators.length) {
@@ -206,14 +206,15 @@ export function processMemberVariableDecorators(parentName: ts.Identifier,
updateResult.setProperity(undefined);
updateResult.setUpdateParams(createUpdateParams(name, COMPONENT_NON_DECORATOR));
updateResult.setCtor(updateConstructor(ctorNode, [], [
createVariableInitStatement(item, COMPONENT_NON_DECORATOR, log, program, context, hasPreview)]));
createVariableInitStatement(item, COMPONENT_NON_DECORATOR, log, program, context, hasPreview,
interfaceNode)]));
updateResult.setControllerSet(createControllerSet(item, parentName, name, checkController));
} else if (!item.type) {
validatePropertyNonType(name, log);
return updateResult;
} else {
processPropertyNodeDecorator(parentName, item, updateResult, ctorNode, name, watchMap,
log, program, context, hasPreview);
log, program, context, hasPreview, interfaceNode);
}
return updateResult;
}
@@ -239,7 +240,8 @@ function createControllerSet(node: ts.PropertyDeclaration, componentName: ts.Ide
function processPropertyNodeDecorator(parentName: ts.Identifier, node: ts.PropertyDeclaration,
updateResult: UpdateResult, ctorNode: ts.ConstructorDeclaration, name: ts.Identifier,
watchMap: Map<string, ts.Node>, log: LogInfo[], program: ts.Program,
context: ts.TransformationContext, hasPreview: boolean): void {
context: ts.TransformationContext, hasPreview: boolean, interfaceNode: ts.InterfaceDeclaration):
void {
let stateManagementDecoratorCount: number = 0;
for (let i = 0; i < node.decorators.length; i++) {
const decoratorName: string = node.decorators[i].getText().replace(/\(.*\)$/, '').trim();
@@ -277,7 +279,8 @@ function processPropertyNodeDecorator(parentName: ts.Identifier, node: ts.Proper
processWatch(node, node.decorators[i], watchMap, log);
} else if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName)) {
stateManagementDecoratorCount += 1;
processStateDecorators(node, decoratorName, updateResult, ctorNode, log, program, context, hasPreview);
processStateDecorators(node, decoratorName, updateResult, ctorNode, log, program, context,
hasPreview, interfaceNode);
}
}
if (stateManagementDecoratorCount > 1) {
@@ -288,25 +291,28 @@ function processPropertyNodeDecorator(parentName: ts.Identifier, node: ts.Proper
function processStateDecorators(node: ts.PropertyDeclaration, decorator: string,
updateResult: UpdateResult, ctorNode: ts.ConstructorDeclaration, log: LogInfo[],
program: ts.Program, context: ts.TransformationContext, hasPreview:boolean): void {
program: ts.Program, context: ts.TransformationContext, hasPreview:boolean,
interfaceNode: ts.InterfaceDeclaration): void {
const name: ts.Identifier = node.name as ts.Identifier;
updateResult.setProperity(undefined);
const updateState: ts.Statement[] = [];
const variableInitStatement: ts.Statement =
createVariableInitStatement(node, decorator, log, program, context, hasPreview);
createVariableInitStatement(node, decorator, log, program, context, hasPreview, interfaceNode);
if (variableInitStatement) {
updateState.push(variableInitStatement);
}
addAddProvidedVar(node, name, decorator, updateState);
updateResult.setCtor(updateConstructor(ctorNode, [], [...updateState], false));
updateResult.setVariableGet(createGetAccessor(name, CREATE_GET_METHOD));
if (decorator !== COMPONENT_BUILDERPARAM_DECORATOR) {
updateResult.setVariableGet(createGetAccessor(name, CREATE_GET_METHOD));
updateResult.setDeleteParams(true);
}
if (!immutableDecorators.has(decorator)) {
updateResult.setVariableSet(createSetAccessor(name, CREATE_SET_METHOD));
updateResult.setVariableSet(createSetAccessor(name, CREATE_SET_METHOD, node.type));
}
if (setUpdateParamsDecorators.has(decorator)) {
updateResult.setUpdateParams(createUpdateParams(name, decorator));
}
updateResult.setDeleteParams(true);
}
function processWatch(node: ts.PropertyDeclaration, decorator: ts.Decorator,
@@ -344,8 +350,8 @@ function processWatch(node: ts.PropertyDeclaration, decorator: ts.Decorator,
}
function createVariableInitStatement(node: ts.PropertyDeclaration, decorator: string,
log: LogInfo[], program: ts.Program, context: ts.TransformationContext, hasPreview: boolean):
ts.Statement {
log: LogInfo[], program: ts.Program, context: ts.TransformationContext, hasPreview: boolean,
interfaceNode: ts.InterfaceDeclaration): ts.Statement {
const name: ts.Identifier = node.name as ts.Identifier;
let type: ts.TypeNode;
let updateState: ts.ExpressionStatement;
@@ -382,6 +388,12 @@ function createVariableInitStatement(node: ts.PropertyDeclaration, decorator: st
updateState = updateConsumeProperty(node, name);
break;
}
const members = interfaceNode.members;
members.push(ts.factory.createPropertySignature(undefined, name,
ts.factory.createToken(ts.SyntaxKind.QuestionToken), type));
interfaceNode = ts.factory.updateInterfaceDeclaration(interfaceNode, undefined,
interfaceNode.modifiers, interfaceNode.name, interfaceNode.typeParameters,
interfaceNode.heritageClauses, members);
return updateState;
}
@@ -417,9 +429,9 @@ function createUpdateParams(name: ts.Identifier, decorator: string): ts.Statemen
builderParamObjectCollection.set(componentCollection.currentClassName, new Set([]));
}
builderParamObjectCollection.get(componentCollection.currentClassName)
.add(name.escapedText.toString())
.add(name.escapedText.toString());
}
updateParamsNode = createUpdateParamsWithoutIf(name, 1);
updateParamsNode = createUpdateParamsWithoutIf(name);
break;
}
return updateParamsNode;
@@ -435,15 +447,9 @@ function createUpdateParamsWithIf(name: ts.Identifier): ts.IfStatement {
createUpdateParamsWithoutIf(name)], true), undefined);
}
function createUpdateParamsWithoutIf(name: ts.Identifier, isAdd: number = 0): ts.ExpressionStatement {
let textName: string;
if (isAdd) {
textName = `__${name.getText()}`;
} else {
textName = name.getText();
}
function createUpdateParamsWithoutIf(name: ts.Identifier): ts.ExpressionStatement {
return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
createPropertyAccessExpressionWithThis(textName),
createPropertyAccessExpressionWithThis(name.getText()),
ts.factory.createToken(ts.SyntaxKind.EqualsToken),
createPropertyAccessExpressionWithParams(name.getText())));
}
@@ -711,11 +717,12 @@ function createGetAccessor(item: ts.Identifier, express: string): ts.GetAccessor
return getAccessorStatement;
}
function createSetAccessor(item: ts.Identifier, express: string): ts.SetAccessorDeclaration {
function createSetAccessor(item: ts.Identifier, express: string, type: ts.TypeNode):
ts.SetAccessorDeclaration {
const setAccessorStatement: ts.SetAccessorDeclaration =
ts.factory.createSetAccessorDeclaration(undefined, undefined, item,
[ts.factory.createParameterDeclaration(undefined, undefined, undefined,
ts.factory.createIdentifier(CREATE_NEWVALUE_IDENTIFIER), undefined, undefined,
ts.factory.createIdentifier(CREATE_NEWVALUE_IDENTIFIER), undefined, type,
undefined)], ts.factory.createBlock([ts.factory.createExpressionStatement(
ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
createPropertyAccessExpressionWithThis(`__${item.getText()}`),
@@ -732,7 +739,7 @@ function isForbiddenUseStateType(typeNode: ts.TypeNode): boolean {
return false;
}
function isSimpleType(typeNode: ts.TypeNode, program: ts.Program): boolean {
export function isSimpleType(typeNode: ts.TypeNode, program: ts.Program): boolean {
let checker: ts.TypeChecker;
if (program) {
checker = program.getTypeChecker();
+72 -10
View File
@@ -52,6 +52,7 @@ import {
createViewCreate,
createCustomComponentNewExpression
} from './process_component_member';
import { builderParamObjectCollection } from './process_component_member';
import {
LogType,
LogInfo,
@@ -72,10 +73,50 @@ const decoractorMap: Map<string, Map<string, Set<string>>> = new Map(
export function processCustomComponent(node: ts.ExpressionStatement, newStatements: ts.Statement[],
log: LogInfo[]): void {
if (ts.isCallExpression(node.expression)) {
addCustomComponent(node, newStatements, createCustomComponentNewExpression(node.expression), log);
let ischangeNode: boolean = false;
let customComponentNewExpression: ts.NewExpression = createCustomComponentNewExpression(
node.expression);
let argumentsArray: ts.PropertyAssignment[];
if (isHasChild(node.expression)) {
// @ts-ignore
argumentsArray = node.expression.arguments[0].properties.slice();
argumentsArray.forEach((item: ts.PropertyAssignment, index: number) => {
if (isToChange(item, node.expression as ts.CallExpression)) {
ischangeNode = true;
const propertyAssignmentNode: ts.PropertyAssignment = ts.factory.updatePropertyAssignment(
item, item.name, changeNodeFromCallToArrow(item.initializer as ts.CallExpression));
argumentsArray.splice(index, 1, propertyAssignmentNode);
}
});
if (ischangeNode) {
const newNode: ts.ExpressionStatement = ts.factory.updateExpressionStatement(node,
ts.factory.createNewExpression(node.expression.expression, node.expression.typeArguments,
[ts.factory.createObjectLiteralExpression(argumentsArray, true)]));
customComponentNewExpression = createCustomComponentNewExpression(
newNode.expression as ts.CallExpression);
}
}
addCustomComponent(node, newStatements, customComponentNewExpression, log);
}
}
function isHasChild(node: ts.CallExpression): boolean {
return node.arguments && node.arguments[0] && ts.isObjectLiteralExpression(node.arguments[0]) &&
node.arguments[0].properties && node.arguments[0].properties.length;
}
function isToChange(item: ts.PropertyAssignment, node: ts.CallExpression): boolean {
const builderParamName: Set<string> = builderParamObjectCollection.get(node.expression.getText());
return item.initializer && ts.isCallExpression(item.initializer) && builderParamName &&
builderParamName.has(item.name.getText());
}
function changeNodeFromCallToArrow(node: ts.CallExpression): ts.ArrowFunction {
return ts.factory.createArrowFunction(undefined, undefined, [], undefined,
ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
ts.factory.createBlock([ts.factory.createExpressionStatement(node)], true));
}
function addCustomComponent(node: ts.ExpressionStatement, newStatements: ts.Statement[],
newNode: ts.NewExpression, log: LogInfo[]): void {
if (ts.isNewExpression(newNode)) {
@@ -89,7 +130,7 @@ function addCustomComponent(node: ts.ExpressionStatement, newStatements: ts.Stat
function addCustomComponentStatements(node: ts.ExpressionStatement, newStatements: ts.Statement[],
newNode: ts.NewExpression, name: string, props: ts.ObjectLiteralElementLike[]): void {
const id: string = componentInfo.id.toString();
newStatements.push(createFindChildById(id), createCustomComponentIfStatement(id,
newStatements.push(createFindChildById(id, name), createCustomComponentIfStatement(id,
ts.factory.updateExpressionStatement(node, createViewCreate(newNode)),
ts.factory.createObjectLiteralExpression(props, true), name));
}
@@ -105,13 +146,16 @@ function validateCustomComponentPrams(node: ts.ExpressionStatement, name: string
ts.isObjectLiteralExpression(nodeArguments[0])) {
const nodeArgument: ts.ObjectLiteralExpression = nodeArguments[0] as ts.ObjectLiteralExpression;
nodeArgument.properties.forEach(item => {
if (item.name && item.name.escapedText) {
// @ts-ignore
if (item.name && ts.isIdentifier(item.name)) {
curChildProps.add(item.name.escapedText.toString());
}
if (isThisProperty(item, propertySet)) {
validateStateManagement(item, name, log);
if (isNonThisProperty(item, linkSet)) {
if (isToChange(item as ts.PropertyAssignment, node.expression as ts.CallExpression)) {
item = ts.factory.updatePropertyAssignment(item as ts.PropertyAssignment,
item.name, changeNodeFromCallToArrow(item.initializer));
}
props.push(item);
}
} else {
@@ -119,6 +163,7 @@ function validateCustomComponentPrams(node: ts.ExpressionStatement, name: string
}
});
}
validateMandatoryToAssignmentViaParam(node, name, curChildProps, log);
validateMandatoryToInitViaParam(node, name, curChildProps, log);
}
@@ -272,13 +317,14 @@ function getPropertyDecoratorKind(propertyName: string, customComponentName: str
}
}
function createFindChildById(id: string): ts.VariableStatement {
function createFindChildById(id: string, name: string): ts.VariableStatement {
return ts.factory.createVariableStatement(undefined, ts.factory.createVariableDeclarationList(
[ts.factory.createVariableDeclaration(ts.factory.createIdentifier(
`${CUSTOM_COMPONENT_EARLIER_CREATE_CHILD}${id}`), undefined, undefined,
ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
ts.factory.createIdentifier(`${CUSTOM_COMPONENT_FUNCTION_FIND_CHILD_BY_ID}`)), undefined,
[ts.factory.createStringLiteral(id)]))], ts.NodeFlags.Let));
`${CUSTOM_COMPONENT_EARLIER_CREATE_CHILD}${id}`), undefined, ts.factory.createTypeReferenceNode(
ts.factory.createIdentifier(name)), ts.factory.createAsExpression(ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ts.factory.createIdentifier(
`${CUSTOM_COMPONENT_FUNCTION_FIND_CHILD_BY_ID}`)), undefined, [ts.factory.createStringLiteral(id)]),
ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(name))))], ts.NodeFlags.Let));
}
function createCustomComponentIfStatement(id: string, node: ts.ExpressionStatement,
@@ -346,11 +392,27 @@ function validateNonExistentProperty(node: ts.ObjectLiteralElementLike,
customComponentName: string, log: LogInfo[]): void {
log.push({
type: LogType.ERROR,
message: `Property '${node.name.getText()}' does not exist on type '${customComponentName}'.`,
message: `Property '${node.name.escapedText.toString()}' does not exist on type '${customComponentName}'.`,
pos: node.name.getStart()
});
}
function validateMandatoryToAssignmentViaParam(node: ts.ExpressionStatement, customComponentName: string,
curChildProps: Set<string>, log: LogInfo[]): void {
if (builderParamObjectCollection.get(customComponentName) &&
builderParamObjectCollection.get(customComponentName).size) {
builderParamObjectCollection.get(customComponentName).forEach((item) => {
if (!curChildProps.has(item)) {
log.push({
type: LogType.ERROR,
message: `The property decorated with @BuilderParam '${item}' must be assigned a value .`,
pos: node.getStart()
});
}
});
}
}
function validateMandatoryToInitViaParam(node: ts.ExpressionStatement, customComponentName: string,
curChildProps: Set<string>, log: LogInfo[]): void {
const mandatoryToInitViaParamSet: Set<string> = new Set([
+13 -6
View File
@@ -56,7 +56,8 @@ import {
EXTEND_ATTRIBUTE,
JS_BIND_COMPONENTS,
INNER_STYLE_FUNCTION,
GLOBAL_STYLE_FUNCTION
GLOBAL_STYLE_FUNCTION,
INTERFACE_NODE_SET
} from './component_map';
import { resources } from '../main';
@@ -81,8 +82,14 @@ export function processUISyntax(program: ts.Program, ut = false): Function {
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;
INTERFACE_NODE_SET.forEach(item => {
statements.unshift(item);
});
node = ts.factory.updateSourceFile(node, statements);
INTERFACE_NODE_SET.clear();
return node;
} else {
return node;
@@ -98,7 +105,7 @@ export function processUISyntax(program: ts.Program, ut = false): Function {
componentCollection.currentClassName = null;
INNER_STYLE_FUNCTION.forEach((block, styleName) => {
BUILDIN_STYLE_NAMES.delete(styleName);
})
});
INNER_STYLE_FUNCTION.clear();
} else if (ts.isFunctionDeclaration(node)) {
if (hasDecorator(node, COMPONENT_EXTEND_DECORATOR)) {
@@ -154,7 +161,7 @@ function collectComponents(node: ts.SourceFile): void {
// @ts-ignore
if (node.identifiers && node.identifiers.size) {
// @ts-ignore
for (let key of node.identifiers.keys()) {
for (const key of node.identifiers.keys()) {
if (JS_BIND_COMPONENTS.has(key)) {
appComponentCollection.add(key);
}
@@ -186,7 +193,7 @@ function processResourceData(node: ts.CallExpression): ts.Node {
return node;
}
function createResourceParam(resourceValue: number, resourceType: number,argsArr: ts.Expression[]):
function createResourceParam(resourceValue: number, resourceType: number, argsArr: ts.Expression[]):
ts.ObjectLiteralExpression {
const resourceParams: ts.ObjectLiteralExpression = ts.factory.createObjectLiteralExpression(
[
@@ -384,7 +391,7 @@ function isPropertyExist(typeChecker: ts.TypeChecker, pos: number, type: ts.Type
} else {
transformLog.errors.push({
type: LogType.ERROR,
message: `TS2339: Property '${propertyName}' does not exist on type '${componentName}'.`,
message: `TS2339: Property '${propertyName}' does not exist on type '${componentName}Attribute'.`,
pos: pos
});
}
-1
View File
@@ -14,7 +14,6 @@
*/
import ts from 'typescript';
import path from 'path';
import { BUILD_OFF } from './pre_define';
import {
+3 -3
View File
@@ -159,10 +159,10 @@ export function createFunction(node: ts.Identifier, attrNode: ts.Identifier,
}
export function circularFile(inputPath: string, outputPath: string): void {
if ((!inputPath) || (!outputPath)) {
if (!inputPath || !outputPath) {
return;
}
fs.readdir(inputPath, function (err, files) {
fs.readdir(inputPath, function(err, files) {
if (!files) {
return;
}
@@ -205,4 +205,4 @@ function mkDir(path_: string): void {
mkDir(parent);
}
fs.mkdirSync(path_);
}
}
+53 -33
View File
@@ -41,9 +41,10 @@ import {
COMPONENT_CONSTRUCTOR_ID,
COMPONENT_CONSTRUCTOR_PARENT,
COMPONENT_CONSTRUCTOR_PARAMS,
COMPONENT_EXTEND_DECORATOR,
COMPONENT_OBSERVED_DECORATOR,
STYLES
STYLES,
VALIDATE_MODULE,
COMPONENT_BUILDER_DECORATOR
} from './pre_define';
import {
INNER_COMPONENT_NAMES,
@@ -53,7 +54,8 @@ import {
BUILDIN_STYLE_NAMES,
EXTEND_ATTRIBUTE,
GLOBAL_STYLE_FUNCTION,
STYLES_ATTRIBUTE
STYLES_ATTRIBUTE,
CUSTOM_BUILDER_METHOD
} from './component_map';
import {
LogType,
@@ -183,19 +185,20 @@ function checkComponentDecorator(source: string, filePath: string,
}
if (ts.isFunctionDeclaration(item) && item.decorators && item.decorators.length === 1 &&
item.decorators[0].expression && item.decorators[0].expression.getText() === STYLES) {
STYLES_ATTRIBUTE.add(item.name.getText())
STYLES_ATTRIBUTE.add(item.name.getText());
GLOBAL_STYLE_FUNCTION.set(item.name.getText(), item.body);
BUILDIN_STYLE_NAMES.add(item.name.getText());
}
});
validateEntryAndPreviewCount(result, fileQuery, sourceFile.fileName, projectConfig.isPreview, log);
validateEntryAndPreviewCount(result, fileQuery, sourceFile.fileName, projectConfig.isPreview,
!!projectConfig.checkEntry, log);
}
return log.length ? log : null;
}
function validateEntryAndPreviewCount(result: DecoratorResult, fileQuery: string,
fileName: string, isPreview: boolean, log: LogInfo[]): void {
fileName: string, isPreview: boolean, checkEntry: boolean, log: LogInfo[]): void {
if (result.previewCount > 10 && fileQuery === '?entry') {
log.push({
type: LogType.ERROR,
@@ -210,7 +213,7 @@ function validateEntryAndPreviewCount(result: DecoratorResult, fileQuery: string
fileName: fileName
});
}
if (isPreview && result.previewCount < 1 && result.entryCount !== 1 &&
if (isPreview && !checkEntry && result.previewCount < 1 && result.entryCount !== 1 &&
fileQuery === '?entry') {
log.push({
type: LogType.ERROR,
@@ -218,7 +221,7 @@ function validateEntryAndPreviewCount(result: DecoratorResult, fileQuery: string
+ `decorator, or at least one '@Preview' decorator.`,
fileName: fileName
});
} else if (!isPreview && result.entryCount !== 1 && fileQuery === '?entry') {
} else if ((!isPreview || isPreview && checkEntry) && result.entryCount !== 1 && fileQuery === '?entry') {
log.push({
type: LogType.ERROR,
message: `A page configured in 'config.json' must have one and only one '@Entry' `
@@ -323,6 +326,9 @@ function visitAllNode(node: ts.Node, sourceFileNode: ts.SourceFile, allComponent
if (ts.isClassDeclaration(node) && node.name && ts.isIdentifier(node.name)) {
collectComponentProps(node);
}
if (ts.isMethodDeclaration(node) && hasDecorator(node, COMPONENT_BUILDER_DECORATOR)) {
CUSTOM_BUILDER_METHOD.add(node.name.getText());
}
node.getChildren().forEach((item: ts.Node) => visitAllNode(item, sourceFileNode, allComponentNames, log));
}
@@ -744,7 +750,7 @@ export function sourceReplace(source: string, sourcePath: string): ReplaceResult
return {
content: content,
log: log
}
};
}
export function preprocessExtend(content: string, sourcePath: string, log: LogInfo[]): string {
@@ -772,7 +778,7 @@ export function preprocessExtend(content: string, sourcePath: string, log: LogIn
syntaxCheckContent = content;
}
if (result.error_otherParsers) {
for(let i = 0; i < result.error_otherParsers.length; i++) {
for (let i = 0; i < result.error_otherParsers.length; i++) {
log.push({
type: LogType.ERROR,
message: result.error_otherParsers[i].errMessage,
@@ -811,39 +817,53 @@ export function processSystemApi(content: string, isProcessWhiteList: boolean =
}
const REG_LIB_SO: RegExp =
/import\s+(.+)\s+from\s+['"]lib(\S+)\.so['"]|import\s+(.+)\s*=\s*require\(\s*['"]lib(\S+)\.so['"]\s*\)/g;
return content.replace(REG_LIB_SO, (_, item1, item2, item3, item4) => {
const systemValueCollection: Set<string> = new Set();
const newContent: string = content.replace(REG_LIB_SO, (_, item1, item2, item3, item4) => {
const libSoValue: string = item1 || item3;
const libSoKey: string = item2 || item4;
return `var ${libSoValue} = globalThis.requireNapi("${libSoKey}", true);`;
}).replace(REG_SYSTEM, (item, item1, item2, item3, item4, item5, item6, item7) => {
let moduleType: string = item2 || item5;
let systemKey: string = item3 || item6;
let systemValue: string = item1 || item4;
if (!isProcessWhiteList && validateWhiteListModule(moduleType, systemKey)) {
return item;
} else if (isProcessWhiteList) {
systemValue = item2;
moduleType = item4;
systemKey = item5;
}
moduleCollection.add(`${moduleType}.${systemKey}`);
if (NATIVE_MODULE.has(`${moduleType}.${systemKey}`)) {
item = `var ${systemValue} = globalThis.requireNativeModule('${moduleType}.${systemKey}')`;
} else if (moduleType === SYSTEM_PLUGIN) {
item = `var ${systemValue} = isSystemplugin('${systemKey}', '${SYSTEM_PLUGIN}') ? ` +
}).replace(REG_SYSTEM, (item, item1, item2, item3, item4, item5, item6, item7) => {
let moduleType: string = item2 || item5;
let systemKey: string = item3 || item6;
let systemValue: string = item1 || item4;
if (!isProcessWhiteList && validateWhiteListModule(moduleType, systemKey)) {
return item;
} else if (isProcessWhiteList) {
systemValue = item2;
moduleType = item4;
systemKey = item5;
systemValueCollection.add(systemValue);
}
moduleCollection.add(`${moduleType}.${systemKey}`);
if (NATIVE_MODULE.has(`${moduleType}.${systemKey}`)) {
item = `var ${systemValue} = globalThis.requireNativeModule('${moduleType}.${systemKey}')`;
} else if (moduleType === SYSTEM_PLUGIN) {
item = `var ${systemValue} = isSystemplugin('${systemKey}', '${SYSTEM_PLUGIN}') ? ` +
`globalThis.systemplugin.${systemKey} : globalThis.requireNapi('${systemKey}')`;
} else if (moduleType === OHOS_PLUGIN) {
item = `var ${systemValue} = globalThis.requireNapi('${systemKey}') || ` +
} else if (moduleType === OHOS_PLUGIN) {
item = `var ${systemValue} = globalThis.requireNapi('${systemKey}') || ` +
`(isSystemplugin('${systemKey}', '${OHOS_PLUGIN}') ? ` +
`globalThis.ohosplugin.${systemKey} : isSystemplugin('${systemKey}', '${SYSTEM_PLUGIN}') ` +
`? globalThis.systemplugin.${systemKey} : undefined)`;
}
return item;
});
}
return item;
});
return processInnerModule(newContent, systemValueCollection);
}
function processInnerModule(content: string, systemValueCollection: Set<string>): string {
systemValueCollection.forEach(element => {
const target: string = element.trim() + '.default';
while (content.includes(target)) {
content = content.replace(target, element.trim());
}
});
return content;
}
const VALIDATE_MODULE_REG: RegExp = new RegExp('^(' + VALIDATE_MODULE.join('|') + ')');
function validateWhiteListModule(moduleType: string, systemKey: string): boolean {
return moduleType === 'ohos' && /^application\./g.test(systemKey);
return moduleType === 'ohos' && VALIDATE_MODULE_REG.test(systemKey);
}
export function resetComponentCollection() {
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
exports.source = `
@Entry
@Component
struct Banner {
@Builder textBuilder() {
Text("文本")
.fontSize(30)
}
@Builder NavigationTitle(label:string) {
Column() {
Text(label)
.width(10)
.bindMenu(this.textBuilder)
}
}
build() {
Column() {
Text("111")
.bindMenu(this.NavigationTitle("111"))
}
}
}
`
exports.expectResult =
`class Banner extends View {
constructor(compilerAssignedUniqueChildId, parent, params) {
super(compilerAssignedUniqueChildId, parent);
this.updateWithValueParams(params);
}
updateWithValueParams(params) {
}
aboutToBeDeleted() {
SubscriberManager.Get().delete(this.id());
}
textBuilder() {
Text.create("文本");
Text.fontSize(30);
Text.pop();
}
NavigationTitle(label) {
Column.create();
Text.create(label);
Text.width(10);
Text.bindMenu({ builder: this.textBuilder.bind(this) });
Text.pop();
Column.pop();
}
render() {
Column.create();
Text.create("111");
Text.bindMenu({ builder: () => {
this.NavigationTitle("111");
} });
Text.pop();
Column.pop();
}
}
loadDocument(new Banner("1", undefined, {}));
`
+18 -25
View File
@@ -29,10 +29,10 @@ struct CustomContainer {
}
}
@Builder function specificParam(label1: string, label2: string) {
@Builder function specificParam() {
Column() {
Text(label1)
Text(label2)
Text("label1")
Text("label2")
}
}
@@ -47,7 +47,7 @@ struct CustomContainerUser {
.width(50)
Text("content2")
}
specificParam("content3", "content4")
specificParam()
}
}
}
@@ -57,8 +57,8 @@ exports.expectResult =
`class CustomContainer extends View {
constructor(compilerAssignedUniqueChildId, parent, params) {
super(compilerAssignedUniqueChildId, parent);
this.header = ""
this.footer = ""
this.header = "";
this.footer = "";
this.updateWithValueParams(params);
}
updateWithValueParams(params) {
@@ -68,18 +68,11 @@ exports.expectResult =
if (params.footer !== undefined) {
this.footer = params.footer;
}
this.__child = params.child;
this.child = params.child;
}
aboutToBeDeleted() {
this.__child.aboutToBeDeleted();
SubscriberManager.Get().delete(this.id());
}
get child(){
return this.__child.get();
}
set child(newValue) {
this.__child.set(newValue)
}
render() {
Column.create();
Text.create(this.header);
@@ -90,15 +83,15 @@ exports.expectResult =
Column.pop();
}
}
function specificParam(label1, label2) {
function specificParam() {
Column.create();
Text.create(label1);
Text.create("label1");
Text.pop();
Text.create(label1);
Text.create("label2");
Text.pop();
Column.pop();
}
class CustomContainerUser {
class CustomContainerUser extends View {
constructor(compilerAssignedUniqueChildId, parent, params) {
super(compilerAssignedUniqueChildId, parent);
this.updateWithValueParams(params);
@@ -117,12 +110,12 @@ class CustomContainerUser {
child: () => {
Column.create();
Text.create("content1");
Text.width(50)
Text.width(50);
Text.pop();
Text.create("content2");
Text.pop();
Column.pop();
specificParam("content3", "content4)
specificParam();
}
}));
}
@@ -132,18 +125,18 @@ class CustomContainerUser {
child: () => {
Column.create();
Text.create("content1");
Text.width(50)
Text.width(50);
Text.pop();
Text.create("content2");
Text.pop();
Column.pop();
specificParam("content3", "content4)
}}
specificParam();
}
});
View.create(earlierCreatedChild_2);
}
Column.pop();
Column.pop();
}
}
loadDocument(new MyComponent("1", undefined, {}));
loadDocument(new CustomContainerUser("1", undefined, {}));
`
+28 -58
View File
@@ -14,35 +14,30 @@
*/
exports.source = `
@Component
struct CustomContainer {
header: string = "";
menuInfo: () => any;
footer: string = "";
@BuilderParam child: () => any;
build() {
Column() {
Text(this.header)
this.child()
Text(this.header)
Text(this.footer)
}
}
}
@Builder function specificParam(label1: string, label2: string) {
Column() {
Text(label1)
Text(label2)
}
}
@Entry
@Component
struct CustomContainerUser {
@Builder specificChild() {
@Builder specificChild(label:string) {
Column() {
Text("My content1")
Text("My content1")
Text(label)
}
}
@@ -51,12 +46,8 @@ struct CustomContainerUser {
CustomContainer({
header: "Header",
footer: "Footer",
child: this.specificChild
})
CustomContainer({
header: "Header",
footer: "Footer",
child: specificParam("content3", "content4")
menuInfo: this.specificChild("menuInfo"),
child: this.specificChild("child")
})
}
}
@@ -66,48 +57,37 @@ exports.expectResult =
`class CustomContainer extends View {
constructor(compilerAssignedUniqueChildId, parent, params) {
super(compilerAssignedUniqueChildId, parent);
this.header = ""
this.footer = ""
this.header = "";
this.menuInfo = undefined;
this.footer = "";
this.updateWithValueParams(params);
}
updateWithValueParams(params) {
if (params.header !== undefined) {
this.header = params.header;
}
if (params.menuInfo !== undefined) {
this.menuInfo = params.menuInfo;
}
if (params.footer !== undefined) {
this.footer = params.footer;
}
this.__child = params.child;
this.child = params.child;
}
aboutToBeDeleted() {
this.__child.aboutToBeDeleted();
SubscriberManager.Get().delete(this.id());
}
get child(){
return this.__child.get();
}
set child(newValue) {
this.__child.set(newValue)
}
render() {
Column.create();
this.child();
Text.create(this.header);
Text.pop();
this.child();
Text.create(this.footer);
Text.pop();
Column.pop();
}
}
function specificParam(label1, label2) {
Column.create();
Text.create(label1);
Text.pop();
Text.create(label1);
Text.pop();
Column.pop();
}
class CustomContainerUser {
class CustomContainerUser extends View {
constructor(compilerAssignedUniqueChildId, parent, params) {
super(compilerAssignedUniqueChildId, parent);
this.updateWithValueParams(params);
@@ -117,50 +97,40 @@ class CustomContainerUser {
aboutToBeDeleted() {
SubscriberManager.Get().delete(this.id());
}
specificChild() {
specificChild(label) {
Column.create();
Text.create("My content1");
Text.pop();
Text.create("My content2");
Text.create(label);
Text.pop();
Column.pop();
}
render() {
Column.create();
let earlierCreatedChild_2 = this.findChildById("2");
if (earlierCreatedChild_2 == undefined) {
View.create(new CustomContainer("2", this, {
header: "Header",
footer: "Footer",
child: this.specificChild
}));
}
else {
earlierCreatedChild_2.updateWithValueParams({
header: "Header",
footer: "Footer",
child: this.specificChild
});
View.create(earlierCreatedChild_2);
}
let earlierCreatedChild_3 = this.findChildById("3");
if (earlierCreatedChild_3 == undefined) {
View.create(new CustomContainer("3", this, {
header: "Header",
footer: "Footer",
child: specificParam("content3", "content4")
menuInfo: this.specificChild("menuInfo"),
child: () => {
this.specificChild("child");
}
}));
}
else {
earlierCreatedChild_3.updateWithValueParams({
header: "Header",
footer: "Footer",
child: specificParam("content3", "content4")
menuInfo: this.specificChild("menuInfo"),
child: () => {
this.specificChild("child");
}
});
View.create(earlierCreatedChild_3);
}
Column.pop();
Column.pop();
}
}
loadDocument(new MyComponent("1", undefined, {}));
loadDocument(new CustomContainerUser("1", undefined, {}));
`
@@ -33,9 +33,7 @@ struct MyAlertDialog {
}
build() {
Stack() {
DialogView({dialogShow: $dialogVis}).onClick(() => {
animateTo({}, () => {})
})
DialogView({dialogShow: $dialogVis})
}
}
}
@@ -108,15 +106,13 @@ class MyAlertDialog extends View {
}
render() {
Stack.create();
let earlierCreatedChild_2 = this.findChildById("2");
if (earlierCreatedChild_2 == undefined) {
View.create(new (DialogView({ dialogShow: this.__dialogVis }).onClick)(() => {
Context.animateTo({}, () => { });
}));
let earlierCreatedChild_3 = this.findChildById("3");
if (earlierCreatedChild_3 == undefined) {
View.create(new DialogView("3", this, { dialogShow: this.__dialogVis }));
}
else {
earlierCreatedChild_2.updateWithValueParams({});
View.create(earlierCreatedChild_2);
earlierCreatedChild_3.updateWithValueParams({});
View.create(earlierCreatedChild_3);
}
Stack.pop();
}
+8
View File
@@ -31,6 +31,8 @@ struct HomeComponent {
Text(this.value1)
Text(this.value2)
Text(this.value3)
Radio({value: "Radio", group: "1"})
.checked($$this.value4)
}
Row() {
Button() {
@@ -45,6 +47,8 @@ struct HomeComponent {
.fontSize(100)
.bindPopup($$value6.item1, {message: "This is $$ for Obj"})
Text(this.value3)
Radio({value: "Radio", group: "1"})
.checked($$value5[0])
}
.width(20)
}
@@ -91,6 +95,8 @@ class HomeComponent extends View {
Text.pop();
Text.create(this.value3);
Text.pop();
Radio.create({ value: "Radio", group: "1" });
Radio.checked(this.value4, newValue => { this.value4 = newValue; });
Row.pop();
Row.create();
Row.width(20);
@@ -109,6 +115,8 @@ class HomeComponent extends View {
Text.pop();
Text.create(this.value3);
Text.pop();
Radio.create({ value: "Radio", group: "1" });
Radio.checked(value5[0], newValue => { value5[0] = newValue; });
Row.pop();
Column.pop();
}
+35 -22
View File
@@ -46,27 +46,6 @@ function initConfig(config) {
poll: false,
ignored: /node_modules/
},
optimization: {
splitChunks: {
chunks(chunk) {
return !/^\.\/workers\//.test(chunk.name);
},
minSize: 0,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
name: "vendors",
},
commons: {
name: 'commons',
priority: -20,
minChunks: 2,
reuseExistingChunk: true
}
}
},
},
output: {
path: path.resolve(__dirname, projectConfig.buildPath),
filename: '[name].js',
@@ -121,7 +100,7 @@ function initConfig(config) {
path.join(projectPath, '../../../../../'),
'./node_modules',
path.join(__dirname, 'node_modules'),
path.join(__dirname, '../../api/common')
path.join(__dirname, '../../api')
]
},
stats: { preset: 'none' },
@@ -152,6 +131,12 @@ function setProjectConfig(envArgs) {
if (envArgs.aceManifestPath) {
projectConfig.manifestFilePath = envArgs.aceManifestPath;
}
if (envArgs.aceProfilePath) {
projectConfig.aceProfilePath = envArgs.aceProfilePath;
}
if (envArgs.aceModuleJsonPath) {
projectConfig.aceModuleJsonPath = envArgs.aceModuleJsonPath;
}
}
function setReleaseConfig(config) {
@@ -207,11 +192,38 @@ function setCopyPluginConfig(config) {
config.plugins.push(new CopyPlugin({ patterns: copyPluginPattrens }));
}
function setOptimizationConfig(config) {
if (process.env.compileMode !== 'moduleJson') {
config.optimization = {
splitChunks: {
chunks(chunk) {
return !/^\.\/workers\//.test(chunk.name);
},
minSize: 0,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
name: "vendors",
},
commons: {
name: 'commons',
priority: -20,
minChunks: 2,
reuseExistingChunk: true
}
}
}
}
}
}
module.exports = (env, argv) => {
const config = {};
setProjectConfig(env);
loadEntryObj(projectConfig);
initConfig(config);
setOptimizationConfig(config);
setCopyPluginConfig(config);
if (env.isPreview !== "true") {
@@ -230,6 +242,7 @@ module.exports = (env, argv) => {
}
} else {
projectConfig.isPreview = true;
projectConfig.checkEntry = env.checkEntry;
let port;
process.argv.forEach((val, index) => {
if(val.startsWith('port=')){