diff --git a/compiler/src/component_map.ts b/compiler/src/component_map.ts index 1ec4f56..a7a0f5b 100644 --- a/compiler/src/component_map.ts +++ b/compiler/src/component_map.ts @@ -47,6 +47,8 @@ export const GESTURE_ATTRS: Set = new Set([ 'gesture', 'parallelGesture', 'priorityGesture' ]); +export const ID_ATTRS: Map> = new Map(); + export const forbiddenUseStateType: Set = new Set(['Scroller', 'SwiperScroller', 'VideoController', 'WebController', 'CustomDialogController', 'SwiperController', 'TabsController', 'CalendarController', 'AbilityController', 'XComponentController', diff --git a/compiler/src/pre_define.ts b/compiler/src/pre_define.ts index 20dfabd..f4b4656 100644 --- a/compiler/src/pre_define.ts +++ b/compiler/src/pre_define.ts @@ -111,6 +111,7 @@ export const GLOBAL_CONTEXT: string = 'Context'; export const ATTRIBUTE_ANIMATION: string = 'animation'; export const ATTRIBUTE_ANIMATETO: string = 'animateTo'; export const ATTRIBUTE_STATESTYLES: string = 'stateStyles'; +export const ATTRIBUTE_ID: string = 'id'; export const COMPONENT_CONSTRUCTOR_ID: string = 'compilerAssignedUniqueChildId'; export const COMPONENT_CONSTRUCTOR_PARENT: string = 'parent'; diff --git a/compiler/src/process_component_build.ts b/compiler/src/process_component_build.ts index 3da05ce..0c4f37e 100644 --- a/compiler/src/process_component_build.ts +++ b/compiler/src/process_component_build.ts @@ -59,7 +59,8 @@ import { BIND_DRAG_SET, BIND_POPUP_SET, $$, - PROPERTIES_ADD_DOUBLE_DOLLAR + PROPERTIES_ADD_DOUBLE_DOLLAR, + ATTRIBUTE_ID } from './pre_define'; import { INNER_COMPONENT_NAMES, @@ -75,7 +76,8 @@ import { GLOBAL_STYLE_FUNCTION, COMMON_ATTRS, CUSTOM_BUILDER_PROPERTIES, - INNER_CUSTOM_BUILDER_METHOD + INNER_CUSTOM_BUILDER_METHOD, + ID_ATTRS } from './component_map'; import { componentCollection, @@ -244,7 +246,7 @@ export function processComponentChild(node: ts.Block | ts.SourceFile, newStateme } break; case ComponentType.forEachComponent: - processForEachComponent(item, newStatements, log); + processForEachComponent(item, newStatements, log, isInnerBuilder); break; case ComponentType.customBuilderMethod: if (INNER_CUSTOM_BUILDER_METHOD.has(name)) { @@ -258,7 +260,7 @@ export function processComponentChild(node: ts.Block | ts.SourceFile, newStateme break; } } else if (ts.isIfStatement(item)) { - processIfStatement(item, newStatements, log); + processIfStatement(item, newStatements, log, isInnerBuilder); } else if (!ts.isBlock(item)) { log.push({ type: LogType.ERROR, @@ -426,7 +428,7 @@ function getRealNodePos(node: ts.Node): number { } function processForEachComponent(node: ts.ExpressionStatement, newStatements: ts.Statement[], - log: LogInfo[]): void { + log: LogInfo[], isInnerBuilder: boolean = false): void { const popNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(createFunction( // @ts-ignore node.expression.expression as ts.Identifier, @@ -444,7 +446,7 @@ function processForEachComponent(node: ts.ExpressionStatement, newStatements: ts ts.factory.createIdentifier(FOREACH_GET_RAW_OBJECT)), undefined, [argumentsArray[0]]); } argumentsArray.splice(0, 1, arrayObserveredObject); - const newArrowNode: ts.ArrowFunction = processForEachBlock(node.expression, log); + const newArrowNode: ts.ArrowFunction = processForEachBlock(node.expression, log, isInnerBuilder); if (newArrowNode) { argumentsArray.splice(1, 1, newArrowNode); } @@ -462,7 +464,8 @@ function addForEachId(node: ts.ExpressionStatement): ts.ExpressionStatement { ...forEachComponent.arguments])); } -function processForEachBlock(node: ts.CallExpression, log: LogInfo[]): ts.ArrowFunction { +function processForEachBlock(node: ts.CallExpression, log: LogInfo[], + isInnerBuilder: boolean = false): ts.ArrowFunction { if (node.arguments.length > 1 && ts.isArrowFunction(node.arguments[1])) { const isLazy: boolean = node.expression.getText() === COMPONENT_LAZYFOREACH; const arrowNode: ts.ArrowFunction = node.arguments[1] as ts.ArrowFunction; @@ -484,7 +487,8 @@ function processForEachBlock(node: ts.CallExpression, log: LogInfo[]): ts.ArrowF } else { return ts.factory.updateArrowFunction( arrowNode, arrowNode.modifiers, arrowNode.typeParameters, arrowNode.parameters, - arrowNode.type, arrowNode.equalsGreaterThanToken, processComponentBlock(body, isLazy, log)); + arrowNode.type, arrowNode.equalsGreaterThanToken, + processComponentBlock(body, isLazy, log, false, isInnerBuilder)); } } return null; @@ -502,14 +506,15 @@ function createRenderingInProgress(isTrue: boolean): ts.ExpressionStatement { } function processIfStatement(node: ts.IfStatement, newStatements: ts.Statement[], - log: LogInfo[]): void { + log: LogInfo[], isInnerBuilder: boolean = false): void { const ifCreate: ts.ExpressionStatement = createIfCreate(); - const newIfNode: ts.IfStatement = processInnerIfStatement(node, 0, log); + const newIfNode: ts.IfStatement = processInnerIfStatement(node, 0, log, isInnerBuilder); const ifPop: ts.ExpressionStatement = createIfPop(); newStatements.push(ifCreate, newIfNode, ifPop); } -function processInnerIfStatement(node: ts.IfStatement, id: number, log: LogInfo[]): ts.IfStatement { +function processInnerIfStatement(node: ts.IfStatement, id: number, log: LogInfo[], + isInnerBuilder: boolean = false): ts.IfStatement { if (ts.isIdentifier(node.expression) && node.expression.originalKeywordKind === undefined && !node.expression.escapedText) { log.push({ @@ -520,15 +525,15 @@ function processInnerIfStatement(node: ts.IfStatement, id: number, log: LogInfo[ node = ts.factory.updateIfStatement(node, ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED), node.thenStatement, node.elseStatement); } - const newThenStatement: ts.Statement = processThenStatement(node.thenStatement, id, log); - const newElseStatement: ts.Statement = processElseStatement(node.elseStatement, id, log); + const newThenStatement: ts.Statement = processThenStatement(node.thenStatement, id, log, isInnerBuilder); + const newElseStatement: ts.Statement = processElseStatement(node.elseStatement, id, log, isInnerBuilder); const newIfNode: ts.IfStatement = ts.factory.updateIfStatement( node, node.expression, newThenStatement, newElseStatement); return newIfNode; } function processThenStatement(thenStatement: ts.Statement, id: number, - log: LogInfo[]): ts.Statement { + log: LogInfo[], isInnerBuilder: boolean = false): ts.Statement { if (ts.isExpressionStatement(thenStatement) && ts.isIdentifier(thenStatement.expression) && thenStatement.expression.originalKeywordKind === undefined && !thenStatement.expression.escapedText) { @@ -540,36 +545,36 @@ function processThenStatement(thenStatement: ts.Statement, id: number, } if (thenStatement) { if (ts.isBlock(thenStatement)) { - thenStatement = processIfBlock(thenStatement, id, log); + thenStatement = processIfBlock(thenStatement, id, log, isInnerBuilder); } else if (ts.isIfStatement(thenStatement)) { - thenStatement = processInnerIfStatement(thenStatement, 0, log); + thenStatement = processInnerIfStatement(thenStatement, 0, log, isInnerBuilder); thenStatement = ts.factory.createBlock( [createIfCreate(), createIfBranchId(id), thenStatement, createIfPop()], true); } else { thenStatement = ts.factory.createBlock([thenStatement], true); - thenStatement = processIfBlock(thenStatement as ts.Block, id, log); + thenStatement = processIfBlock(thenStatement as ts.Block, id, log, isInnerBuilder); } } return thenStatement; } function processElseStatement(elseStatement: ts.Statement, id: number, - log: LogInfo[]): ts.Statement { + log: LogInfo[], isInnerBuilder: boolean = false): ts.Statement { if (elseStatement) { if (ts.isBlock(elseStatement)) { elseStatement = processIfBlock(elseStatement, id + 1, log); } else if (ts.isIfStatement(elseStatement)) { - elseStatement = processInnerIfStatement(elseStatement, id + 1, log); + elseStatement = processInnerIfStatement(elseStatement, id + 1, log, isInnerBuilder); } else { elseStatement = ts.factory.createBlock([elseStatement], true); - elseStatement = processIfBlock(elseStatement as ts.Block, id + 1, log); + elseStatement = processIfBlock(elseStatement as ts.Block, id + 1, log, isInnerBuilder); } } return elseStatement; } -function processIfBlock(block: ts.Block, id: number, log: LogInfo[]): ts.Block { - return addIfBranchId(id, processComponentBlock(block, false, log)); +function processIfBlock(block: ts.Block, id: number, log: LogInfo[], isInnerBuilder: boolean = false): ts.Block { + return addIfBranchId(id, processComponentBlock(block, false, log, false, isInnerBuilder)); } function addIfBranchId(id: number, container: ts.Block): ts.Block { @@ -924,10 +929,36 @@ function updateArgumentFor$$(argument: any): ts.Expression { } } +function verifyComponentId(temp: any, node: ts.Identifier, propName: string, + log: LogInfo[]): void { + if (!newsupplement.isAcceleratePreview && propName === ATTRIBUTE_ID) { + const literalString: string = temp.arguments[0].text; + if (ID_ATTRS.has(literalString)) { + const errInfo: Map = ID_ATTRS.get(literalString); + log.push({ + type: LogType.ERROR, + message: `The current component id "${literalString}" is duplicate with ` + + `${errInfo.get('path')}:${errInfo.get('line')}:${errInfo.get('col')}.`, + pos: node.pos + }); + } else { + const posOfNode: ts.LineAndCharacter = transformLog.sourceFile + .getLineAndCharacterOfPosition(getRealNodePos(node)); + const curFileName: string = transformLog.sourceFile.fileName.replace(/\.ts$/, ''); + const rPath: string = path.resolve(projectConfig.projectPath, curFileName) + .replace(/\\+/g, '/'); + ID_ATTRS.set(literalString, new Map().set('path', rPath) + .set('line', posOfNode.line + 1) + .set('col', posOfNode.character + 1)); + } + } +} + function addComponentAttr(temp: any, node: ts.Identifier, lastStatement: any, statements: ts.Statement[], identifierNode: ts.Identifier, log: LogInfo[], isStylesAttr: boolean, isGlobalStyles: boolean): void { const propName: string = node.getText(); + verifyComponentId(temp, node, propName, log); if (propName === ATTRIBUTE_ANIMATION) { if (!lastStatement.statement) { if (!(temp.arguments.length === 1 && diff --git a/compiler/src/process_component_class.ts b/compiler/src/process_component_class.ts index 3dd3441..e76ec1a 100644 --- a/compiler/src/process_component_class.ts +++ b/compiler/src/process_component_class.ts @@ -56,7 +56,8 @@ import { COMPONENT_SET_AND_PROP, COMPONENT_CONSTRUCTOR_UNDEFINED, CUSTOM_COMPONENT, - COMPONENT_CONSTRUCTOR_PARENT + COMPONENT_CONSTRUCTOR_PARENT, + COMPONENT_IF_UNDEFINED } from './pre_define'; import { BUILDIN_STYLE_NAMES, @@ -304,7 +305,8 @@ function processComponentMethod(node: ts.MethodDeclaration, parentComponentName: CUSTOM_BUILDER_METHOD.add(name); INNER_CUSTOM_BUILDER_METHOD.add(name) node.parameters.push(ts.factory.createParameterDeclaration(undefined, undefined, undefined, - ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), undefined, undefined, ts.factory.createIdentifier("undefined"))); + ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), undefined, undefined, + ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED))); const builderNode: ts.MethodDeclaration = ts.factory.updateMethodDeclaration(node, undefined, node.modifiers, node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters, node.type, processComponentBlock(node.body, false, log, false, true)); diff --git a/compiler/src/process_component_member.ts b/compiler/src/process_component_member.ts index b59aa84..8c92b17 100644 --- a/compiler/src/process_component_member.ts +++ b/compiler/src/process_component_member.ts @@ -573,14 +573,15 @@ export function createViewCreate(node: ts.NewExpression | ts.Identifier): ts.Cal ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), ts.factory.createNodeArray([node])); } -export function createCustomComponentNewExpression(node: ts.CallExpression, name: string, isInnerBuilder: boolean = false) - : ts.NewExpression { +export function createCustomComponentNewExpression(node: ts.CallExpression, name: string, + isInnerBuilder: boolean = false): ts.NewExpression { const newNode: ts.NewExpression = ts.factory.createNewExpression(node.expression, node.typeArguments, node.arguments.length ? node.arguments : []); return addCustomComponentId(newNode, name, isInnerBuilder); } -function addCustomComponentId(node: ts.NewExpression, componentName: string, isInnerBuilder: boolean = false): ts.NewExpression { +function addCustomComponentId(node: ts.NewExpression, componentName: string, + isInnerBuilder: boolean = false): ts.NewExpression { for (const item of componentCollection.customComponents) { componentInfo.componentNames.add(item); } @@ -598,8 +599,7 @@ function addCustomComponentId(node: ts.NewExpression, componentName: string, isI ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), ts.factory.createToken(ts.SyntaxKind.QuestionToken), ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), - ts.factory.createToken(ts.SyntaxKind.ColonToken), - ts.factory.createThis() + ts.factory.createToken(ts.SyntaxKind.ColonToken), ts.factory.createThis() ) : ts.factory.createThis()); node = ts.factory.updateNewExpression(node, node.expression, node.typeArguments, argumentsArray); diff --git a/compiler/src/process_custom_component.ts b/compiler/src/process_custom_component.ts index be467a4..6fc9c2d 100644 --- a/compiler/src/process_custom_component.ts +++ b/compiler/src/process_custom_component.ts @@ -369,8 +369,7 @@ function createFindChildById(id: string, name: string, isInnerBuilder: boolean = ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), ts.factory.createToken(ts.SyntaxKind.QuestionToken), ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), - ts.factory.createToken(ts.SyntaxKind.ColonToken), - ts.factory.createThis() + ts.factory.createToken(ts.SyntaxKind.ColonToken), ts.factory.createThis() )) : 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)); diff --git a/compiler/test/ut/render_decorator/@builder/@builder.ts b/compiler/test/ut/render_decorator/@builder/@builder.ts index 479e8a8..e497807 100644 --- a/compiler/test/ut/render_decorator/@builder/@builder.ts +++ b/compiler/test/ut/render_decorator/@builder/@builder.ts @@ -185,12 +185,12 @@ class MyComponent extends View { set hideBar(newValue) { this.__hideBar.set(newValue); } - textBuilder() { + textBuilder(parent = undefined) { Text.create("文本"); Text.fontSize(30); Text.pop(); } - NavigationTitlePara(label) { + NavigationTitlePara(label, parent = undefined) { Column.create(); Text.create(label); Text.width(80); @@ -198,7 +198,7 @@ class MyComponent extends View { Text.pop(); Column.pop(); } - MenuBuilder() { + MenuBuilder(parent = undefined) { Flex.create({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }); Flex.width(100); Text.create('Test menu item 1'); diff --git a/compiler/test/ut/render_decorator/@builder/@builderWithLinkData.ts b/compiler/test/ut/render_decorator/@builder/@builderWithLinkData.ts index aebe676..0c3509f 100644 --- a/compiler/test/ut/render_decorator/@builder/@builderWithLinkData.ts +++ b/compiler/test/ut/render_decorator/@builder/@builderWithLinkData.ts @@ -82,10 +82,10 @@ class TestPage extends View { set value(newValue) { this.__value.set(newValue); } - TitleCompView() { - let earlierCreatedChild_2 = this.findChildById("2"); + TitleCompView(parent = undefined) { + let earlierCreatedChild_2 = (parent ? parent : this).findChildById("2"); if (earlierCreatedChild_2 == undefined) { - View.create(new TitleComp("2", this, { title: this.__value })); + View.create(new TitleComp("2", parent ? parent : this, { title: this.__value })); } else { earlierCreatedChild_2.updateWithValueParams({}); @@ -94,7 +94,7 @@ class TestPage extends View { } render() { Flex.create(); - this.TitleCompView(); + this.TitleCompView(this); Flex.pop(); } } diff --git a/compiler/test/ut/render_decorator/@builderParam/@builderParam.ts b/compiler/test/ut/render_decorator/@builderParam/@builderParam.ts index edff8d5..73421eb 100644 --- a/compiler/test/ut/render_decorator/@builderParam/@builderParam.ts +++ b/compiler/test/ut/render_decorator/@builderParam/@builderParam.ts @@ -121,8 +121,8 @@ class CustomContainer extends View { Column.create(); Text.create(this.header); Text.pop(); - this.content(); - this.callContent(); + this.content(this); + this.callContent(this); Text.create(this.footer); Text.pop(); Column.pop(); @@ -147,7 +147,7 @@ class CustomContainer2 extends View { Column.create(); Text.create(this.header); Text.pop(); - this.content(); + this.content(this); Column.pop(); } } @@ -172,14 +172,14 @@ class CustomContainerUser extends View { set text(newValue) { this.__text.set(newValue); } - specificParam() { + specificParam(parent = undefined) { Column.create(); Text.create("content"); Text.fontSize(50); Text.pop(); Column.pop(); } - callSpecificParam(label1, label2) { + callSpecificParam(label1, label2, parent = undefined) { Column.create(); Text.create(label1); Text.fontSize(50); @@ -200,7 +200,7 @@ class CustomContainerUser extends View { Column.onClick(() => { this.text = "changeHeader"; }); - specificParam("111", "22"); + specificParam("111", "22", this); Column.pop(); } })); @@ -213,7 +213,7 @@ class CustomContainerUser extends View { Column.onClick(() => { this.text = "changeHeader"; }); - specificParam("111", "22"); + specificParam("111", "22", this); Column.pop(); } }); @@ -249,7 +249,7 @@ class CustomContainerUser extends View { Column.onClick(() => { this.text = "changeHeader"; }); - this.callSpecificParam("111", '222'); + this.callSpecificParam("111", '222', this); Column.pop(); } })); @@ -262,7 +262,7 @@ class CustomContainerUser extends View { Column.onClick(() => { this.text = "changeHeader"; }); - this.callSpecificParam("111", '222'); + this.callSpecificParam("111", '222', this); Column.pop(); } });