diff --git a/compiler/src/pre_define.ts b/compiler/src/pre_define.ts index 60c6935..0cbbb9f 100644 --- a/compiler/src/pre_define.ts +++ b/compiler/src/pre_define.ts @@ -288,7 +288,7 @@ export const RMELMTID: string = 'rmElmtId'; export const PURGEDEPENDENCYONELMTID: string = 'purgeDependencyOnElmtId'; export const SETPROPERTYUNCHANGED: string = 'SetPropertyUnchanged'; export const ABOUTTOBEDELETEDINTERNAL: string = 'aboutToBeDeletedInternal'; -export const UPDATEDIRTYELEMENTS: string ='updateDirtyElements'; +export const UPDATEDIRTYELEMENTS: string = 'updateDirtyElements'; export const BASICDECORATORS: Set = new Set([COMPONENT_STATE_DECORATOR, COMPONENT_PROP_DECORATOR, COMPONENT_LINK_DECORATOR]); export const ISINITIALRENDER: string = 'isInitialRender'; @@ -297,3 +297,9 @@ export const STARTGETACCESSRECORDINGFOR: string = 'StartGetAccessRecordingFor'; export const STOPGETACCESSRECORDING: string = 'StopGetAccessRecording'; export const VIEWSTACKPROCESSOR: string = 'ViewStackProcessor'; export const OBSERVECOMPONENTCREATION: string = 'observeComponentCreation'; +export const ISLAZYCREATE: string = 'isLazyCreate'; +export const DEEPRENDERFUNCTION: string = 'deepRenderFunction'; +export const ITEMCREATION: string = 'itemCreation'; +export const OBSERVEDSHALLOWRENDER: string = 'observedShallowRender'; +export const OBSERVEDDEEPRENDER:string = 'observedDeepRender'; +export const ItemComponents: string[] = ['ListItem', 'GridItem']; diff --git a/compiler/src/process_component_build.ts b/compiler/src/process_component_build.ts index f00dbfd..8c16d38 100644 --- a/compiler/src/process_component_build.ts +++ b/compiler/src/process_component_build.ts @@ -67,7 +67,13 @@ import { VIEWSTACKPROCESSOR, STOPGETACCESSRECORDING, STARTGETACCESSRECORDINGFOR, - OBSERVECOMPONENTCREATION + OBSERVECOMPONENTCREATION, + ISLAZYCREATE, + DEEPRENDERFUNCTION, + ITEMCREATION, + OBSERVEDSHALLOWRENDER, + OBSERVEDDEEPRENDER, + ItemComponents } from './pre_define'; import { INNER_COMPONENT_NAMES, @@ -387,32 +393,19 @@ function processInnerComponent(node: ts.ExpressionStatement, innerCompStatements newStatements.push(res.newNode); const nameResult: NameResult = { name: null }; validateEtsComponentNode(node.expression as ts.EtsComponentExpression, nameResult); - if (projectConfig.isPreview && nameResult.name && !NO_DEBUG_LINE_COMPONENT.has(nameResult.name)) { - let posOfNode: ts.LineAndCharacter; - let curFileName: string; - let line: number = 1; - let col: number = 1; - if (newsupplement.isAcceleratePreview) { - posOfNode = sourceNode.getLineAndCharacterOfPosition(getRealNodePos(node)); - curFileName = newsupplement.fileName; - if (posOfNode.line === 0) { - col = newsupplement.column - 15; - } - line = newsupplement.line; - } else { - posOfNode = transformLog.sourceFile.getLineAndCharacterOfPosition(getRealNodePos(node)); - curFileName = transformLog.sourceFile.fileName.replace(/\.ts$/, ''); - } - const projectPath: string = projectConfig.projectPath; - const debugInfo: string = - `${path.relative(projectPath, curFileName).replace(/\\+/g, '/')}` + - `(${posOfNode.line + line}:${posOfNode.character + col})`; - const debugNode: ts.ExpressionStatement = ts.factory.createExpressionStatement( - createFunction(ts.factory.createIdentifier(nameResult.name), - ts.factory.createIdentifier(COMPONENT_DEBUGLINE_FUNCTION), - ts.factory.createNodeArray([ts.factory.createStringLiteral(debugInfo)]))); - newStatements.push(debugNode); + if (compatibleSdkVersion === '9' && ItemComponents.includes(nameResult.name)) { + processItemComponent(node, nameResult, innerCompStatements, log); + } else { + processNormalComponent(node, nameResult, innerCompStatements, log); } +} + +function processNormalComponent(node: ts.ExpressionStatement, nameResult: NameResult, + innerCompStatements: ts.Statement[], log: LogInfo[]): void { + const newStatements: ts.Statement[] = []; + const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION); + newStatements.push(res.newNode); + processDebug(node, nameResult, newStatements); const etsComponentResult: EtsComponentResult = parseEtsComponentExpression(node); if (PROPERTIES_ADD_DOUBLE_DOLLAR.has(res.identifierNode.getText()) && etsComponentResult.etsComponentNode.arguments && etsComponentResult.etsComponentNode.arguments.length) { @@ -443,6 +436,34 @@ function processInnerComponent(node: ts.ExpressionStatement, innerCompStatements } } +function processDebug(node: ts.Statement, nameResult: NameResult, newStatements: ts.Statement[]): void { + if (projectConfig.isPreview && nameResult.name && !NO_DEBUG_LINE_COMPONENT.has(nameResult.name)) { + let posOfNode: ts.LineAndCharacter; + let curFileName: string; + let line: number = 1; + let col: number = 1; + if (newsupplement.isAcceleratePreview) { + posOfNode = sourceNode.getLineAndCharacterOfPosition(getRealNodePos(node)); + curFileName = newsupplement.fileName; + if (posOfNode.line === 0) { + col = newsupplement.column - 15; + } + line = newsupplement.line; + } else { + posOfNode = transformLog.sourceFile.getLineAndCharacterOfPosition(getRealNodePos(node)); + curFileName = transformLog.sourceFile.fileName.replace(/\.ts$/, ''); + } + const projectPath: string = projectConfig.projectPath; + const debugInfo: string = `${path.relative(projectPath, curFileName).replace(/\\+/g, '/')}` + + `(${posOfNode.line + line}:${posOfNode.character + col})`; + const debugNode: ts.ExpressionStatement = ts.factory.createExpressionStatement( + createFunction(ts.factory.createIdentifier(nameResult.name), + ts.factory.createIdentifier(COMPONENT_DEBUGLINE_FUNCTION), + ts.factory.createNodeArray([ts.factory.createStringLiteral(debugInfo)]))); + newStatements.push(debugNode); + } +} + function processInnerCompStatements( innerCompStatements: ts.Statement[], newStatements: ts.Statement[], @@ -505,7 +526,7 @@ function createInitRenderStatement(node: ts.Statement): ts.Statement { ), ts.factory.createBlock( [ - ts.isExpressionStatement(node) ? + ts.isExpressionStatement(node) ? createComponent(node, COMPONENT_POP_FUNCTION).newNode : createIfPop() ], true @@ -513,6 +534,250 @@ function createInitRenderStatement(node: ts.Statement): ts.Statement { ); } +function processItemComponent(node: ts.ExpressionStatement, nameResult: NameResult, innerCompStatements: ts.Statement[], + log: LogInfo[]): void { + const itemRenderInnerStatements: ts.Statement[] = []; + const deepItemRenderInnerStatements: ts.Statement[] = []; + const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION); + const itemCreateStatement: ts.Statement = createItemCreate(nameResult); + itemRenderInnerStatements.push(itemCreateStatement); + processDebug(node, nameResult, innerCompStatements); + const etsComponentResult: EtsComponentResult = parseEtsComponentExpression(node); + if (etsComponentResult.etsComponentNode.body && ts.isBlock(etsComponentResult.etsComponentNode.body)) { + if (etsComponentResult.hasAttr) { + bindComponentAttr(node, res.identifierNode, itemRenderInnerStatements, log); + } + processComponentChild(etsComponentResult.etsComponentNode.body, deepItemRenderInnerStatements, log); + } else { + bindComponentAttr(node, res.identifierNode, itemRenderInnerStatements, log); + } + innerCompStatements.push(createItemBlock(node, itemRenderInnerStatements, deepItemRenderInnerStatements)); +} + +function createItemCreate(nameResult: NameResult): ts.Statement { + return ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(nameResult.name), + ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)), undefined, + [ts.factory.createIdentifier(DEEPRENDERFUNCTION), ts.factory.createIdentifier(ISLAZYCREATE)])); +} + +function createItemBlock( + node: ts.ExpressionStatement, + itemRenderInnerStatements: ts.Statement[], + deepItemRenderInnerStatements: ts.Statement[] +): ts.Block { + const etsComponent: ts.EtsComponentExpression = getEtsComponentExpression(node); + let isLazyCreate: ts.BooleanLiteral = ts.factory.createTrue(); + if (etsComponent && etsComponent.arguments[0]) { + if (etsComponent.arguments[0] as ts.StringLiteral.text === 'false') { + isLazyCreate = ts.factory.createFalse(); + } + } + return ts.factory.createBlock( + [ + ts.factory.createVariableStatement( + undefined, + ts.factory.createVariableDeclarationList( + [ts.factory.createVariableDeclaration(ts.factory.createIdentifier(ISLAZYCREATE), + undefined, undefined, isLazyCreate)], + ts.NodeFlags.Const + ) + ), + createItemCreation(node, itemRenderInnerStatements), + createObservedShallowRender(node, itemRenderInnerStatements), + createObservedDeepRender(node, deepItemRenderInnerStatements), + createDeepRenderFunction(node, deepItemRenderInnerStatements), + ts.factory.createIfStatement( + ts.factory.createIdentifier(ISLAZYCREATE), + ts.factory.createBlock( + [ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createIdentifier(OBSERVEDSHALLOWRENDER), undefined, []))], true), + ts.factory.createBlock( + [ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createIdentifier(OBSERVEDDEEPRENDER), undefined, []))], true) + ) + ], + true + ); +} + +function createItemCreation( + node: ts.ExpressionStatement, + itemRenderInnerStatements: ts.Statement[] +): ts.VariableStatement { + return ts.factory.createVariableStatement( + undefined, + ts.factory.createVariableDeclarationList( + [ts.factory.createVariableDeclaration( + ts.factory.createIdentifier(ITEMCREATION), undefined, undefined, + ts.factory.createArrowFunction(undefined, undefined, + [ + ts.factory.createParameterDeclaration(undefined, undefined, undefined, + ts.factory.createIdentifier(ELMTID), undefined, undefined, undefined), + ts.factory.createParameterDeclaration(undefined, undefined, undefined, + ts.factory.createIdentifier(ISINITIALRENDER), undefined, undefined, undefined) + ], undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createBlock( + [ + createViewStackProcessorStatement(STARTGETACCESSRECORDINGFOR, ELMTID), + ...itemRenderInnerStatements, + ts.factory.createIfStatement( + ts.factory.createPrefixUnaryExpression( + ts.SyntaxKind.ExclamationToken, + ts.factory.createIdentifier(ISINITIALRENDER) + ), + ts.factory.createBlock( + [createComponent(node, COMPONENT_POP_FUNCTION).newNode], + true + ) + ), + createViewStackProcessorStatement(STOPGETACCESSRECORDING) + ], + true + ) + ) + )], + ts.NodeFlags.Const + ) + ); +} + +function createDeepRenderFunction( + node: ts.ExpressionStatement, + deepItemRenderInnerStatements: ts.Statement[] +): ts.VariableStatement { + return ts.factory.createVariableStatement( + undefined, + ts.factory.createVariableDeclarationList( + [ts.factory.createVariableDeclaration( + ts.factory.createIdentifier(DEEPRENDERFUNCTION), undefined, undefined, + ts.factory.createArrowFunction(undefined, undefined, + [ + ts.factory.createParameterDeclaration(undefined, undefined, undefined, + ts.factory.createIdentifier(ELMTID), undefined, undefined, undefined), + ts.factory.createParameterDeclaration(undefined, undefined, undefined, + ts.factory.createIdentifier(ISINITIALRENDER), undefined, undefined, undefined) + ], undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createBlock( + [ + ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createIdentifier(ITEMCREATION), undefined, + [ + ts.factory.createIdentifier(ELMTID), + ts.factory.createIdentifier(ISINITIALRENDER) + ] + )), + ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createThis(), + ts.factory.createIdentifier('updateFuncByElmtId') + ), + ts.factory.createIdentifier('set') + ), undefined, + [ts.factory.createIdentifier(ELMTID), ts.factory.createIdentifier(ITEMCREATION)] + )), + ...deepItemRenderInnerStatements, + createComponent(node, COMPONENT_POP_FUNCTION).newNode + ], + true + ) + ) + )], + ts.NodeFlags.Const + ) + ); +} + +function createObservedShallowRender( + node: ts.ExpressionStatement, + itemRenderInnerStatements: ts.Statement[] +): ts.VariableStatement { + return ts.factory.createVariableStatement(undefined, + ts.factory.createVariableDeclarationList( + [ts.factory.createVariableDeclaration( + ts.factory.createIdentifier(OBSERVEDSHALLOWRENDER), undefined, undefined, + ts.factory.createArrowFunction(undefined, undefined, [], undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createBlock( + [ + ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createThis(), + ts.factory.createIdentifier(OBSERVECOMPONENTCREATION) + ), undefined, + [ts.factory.createArrowFunction(undefined, undefined, + [ + ts.factory.createParameterDeclaration(undefined, undefined, undefined, + ts.factory.createIdentifier(ELMTID), undefined, undefined, undefined), + ts.factory.createParameterDeclaration(undefined, undefined, undefined, + ts.factory.createIdentifier(ISINITIALRENDER), undefined, undefined, undefined) + ], undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createBlock( + [createViewStackProcessorStatement(STARTGETACCESSRECORDINGFOR, ELMTID), + itemRenderInnerStatements[0], + ts.factory.createIfStatement( + ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.ExclamationToken, + ts.factory.createIdentifier(ISINITIALRENDER)), + ts.factory.createBlock( + [createComponent(node, COMPONENT_POP_FUNCTION).newNode], true)), + createViewStackProcessorStatement(STOPGETACCESSRECORDING)], true + ) + )] + )), + createComponent(node, COMPONENT_POP_FUNCTION).newNode + ], + true + ) + ) + )], + ts.NodeFlags.Const + ) + ); +} + +function createObservedDeepRender( + node: ts.ExpressionStatement, + deepItemRenderInnerStatements: ts.Statement[] +): ts.VariableStatement { + return ts.factory.createVariableStatement( + undefined, + ts.factory.createVariableDeclarationList( + [ts.factory.createVariableDeclaration( + ts.factory.createIdentifier(OBSERVEDDEEPRENDER), + undefined, + undefined, + ts.factory.createArrowFunction( + undefined, + undefined, + [], + undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createBlock( + [ + ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createThis(), + ts.factory.createIdentifier(OBSERVECOMPONENTCREATION) + ), + undefined, + [ts.factory.createIdentifier(ITEMCREATION)] + )), + ...deepItemRenderInnerStatements, + createComponent(node, COMPONENT_POP_FUNCTION).newNode + ], + true + ) + ) + )], + ts.NodeFlags.Const + ) + ); +} + function getRealNodePos(node: ts.Node): number { // @ts-ignore if (node.pos === -1 && node.expression) { @@ -609,7 +874,7 @@ function processIfStatement(node: ts.IfStatement, newStatements: ts.Statement[], if (compatibleSdkVersion === '8') { newStatements.push(ifCreate, newIfNode, ifPop); } else { - newStatements.push(createComponentCreationStatement(node, [ifCreate,newIfNode]),ifPop); + newStatements.push(createComponentCreationStatement(node, [ifCreate, newIfNode]), ifPop); } } diff --git a/compiler/test/utForPartialUpdate/inner_component_transform/render_component/item/GridItem.ts b/compiler/test/utForPartialUpdate/inner_component_transform/render_component/item/GridItem.ts new file mode 100644 index 0000000..30b25f1 --- /dev/null +++ b/compiler/test/utForPartialUpdate/inner_component_transform/render_component/item/GridItem.ts @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +exports.source = ` +@Entry +@Component +struct ParentView { + build() { + GridItem('true') { + Text('xx').width(100) + }.width(200).height(100) + } +} +` +exports.expectResult = +`class ParentView extends View { + constructor(parent, params) { + super(parent); + this.setInitiallyProvidedValue(params); + } + setInitiallyProvidedValue(params) { + } + setStateSourcePropertiesUnchanged() { + } + setOneWaySyncPropertiesUnchanged() { + } + setTwoWaySyncPropertiesUnchanged() { + } + purgeVariableDependenciesOnElmtId(rmElmtId) { + } + aboutToBeDeleted() { + SubscriberManager.Get().delete(this.id__()); + this.aboutToBeDeletedInternal(); + } + render() { + { + const isLazyCreate = true; + const itemCreation = (elmtId, isInitialRender) => { + ViewStackProcessor.StartGetAccessRecordingFor(elmtId); + GridItem.create(deepRenderFunction, isLazyCreate); + GridItem.width(200); + GridItem.height(100); + if (!isInitialRender) { + GridItem.pop(); + } + ViewStackProcessor.StopGetAccessRecording(); + }; + const observedShallowRender = () => { + this.observeComponentCreation((elmtId, isInitialRender) => { + ViewStackProcessor.StartGetAccessRecordingFor(elmtId); + GridItem.create(deepRenderFunction, isLazyCreate); + if (!isInitialRender) { + GridItem.pop(); + } + ViewStackProcessor.StopGetAccessRecording(); + }); + GridItem.pop(); + }; + const observedDeepRender = () => { + this.observeComponentCreation(itemCreation); + this.observeComponentCreation((elmtId, isInitialRender) => { + ViewStackProcessor.StartGetAccessRecordingFor(elmtId); + Text.create('xx'); + Text.width(100); + if (!isInitialRender) { + Text.pop(); + } + ViewStackProcessor.StopGetAccessRecording(); + }); + Text.pop(); + GridItem.pop(); + }; + const deepRenderFunction = (elmtId, isInitialRender) => { + itemCreation(elmtId, isInitialRender); + this.updateFuncByElmtId.set(elmtId, itemCreation); + this.observeComponentCreation((elmtId, isInitialRender) => { + ViewStackProcessor.StartGetAccessRecordingFor(elmtId); + Text.create('xx'); + Text.width(100); + if (!isInitialRender) { + Text.pop(); + } + ViewStackProcessor.StopGetAccessRecording(); + }); + Text.pop(); + GridItem.pop(); + }; + if (isLazyCreate) { + observedShallowRender(); + } + else { + observedDeepRender(); + } + } + } + rerender() { + this.updateDirtyElements(); + } +} +loadDocument(new ParentView("1", undefined, {})); +` \ No newline at end of file diff --git a/compiler/test/utForPartialUpdate/inner_component_transform/render_component/item/ListItem.ts b/compiler/test/utForPartialUpdate/inner_component_transform/render_component/item/ListItem.ts new file mode 100644 index 0000000..62638a5 --- /dev/null +++ b/compiler/test/utForPartialUpdate/inner_component_transform/render_component/item/ListItem.ts @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +exports.source = ` +@Entry +@Component +struct ParentView { + build() { + ListItem('true') { + Text('xx').width(100) + }.width(200).height(100) + } +} +` +exports.expectResult = +`class ParentView extends View { + constructor(parent, params) { + super(parent); + this.setInitiallyProvidedValue(params); + } + setInitiallyProvidedValue(params) { + } + setStateSourcePropertiesUnchanged() { + } + setOneWaySyncPropertiesUnchanged() { + } + setTwoWaySyncPropertiesUnchanged() { + } + purgeVariableDependenciesOnElmtId(rmElmtId) { + } + aboutToBeDeleted() { + SubscriberManager.Get().delete(this.id__()); + this.aboutToBeDeletedInternal(); + } + render() { + { + const isLazyCreate = true; + const itemCreation = (elmtId, isInitialRender) => { + ViewStackProcessor.StartGetAccessRecordingFor(elmtId); + ListItem.create(deepRenderFunction, isLazyCreate); + ListItem.width(200); + ListItem.height(100); + if (!isInitialRender) { + ListItem.pop(); + } + ViewStackProcessor.StopGetAccessRecording(); + }; + const observedShallowRender = () => { + this.observeComponentCreation((elmtId, isInitialRender) => { + ViewStackProcessor.StartGetAccessRecordingFor(elmtId); + ListItem.create(deepRenderFunction, isLazyCreate); + if (!isInitialRender) { + ListItem.pop(); + } + ViewStackProcessor.StopGetAccessRecording(); + }); + ListItem.pop(); + }; + const observedDeepRender = () => { + this.observeComponentCreation(itemCreation); + this.observeComponentCreation((elmtId, isInitialRender) => { + ViewStackProcessor.StartGetAccessRecordingFor(elmtId); + Text.create('xx'); + Text.width(100); + if (!isInitialRender) { + Text.pop(); + } + ViewStackProcessor.StopGetAccessRecording(); + }); + Text.pop(); + ListItem.pop(); + }; + const deepRenderFunction = (elmtId, isInitialRender) => { + itemCreation(elmtId, isInitialRender); + this.updateFuncByElmtId.set(elmtId, itemCreation); + this.observeComponentCreation((elmtId, isInitialRender) => { + ViewStackProcessor.StartGetAccessRecordingFor(elmtId); + Text.create('xx'); + Text.width(100); + if (!isInitialRender) { + Text.pop(); + } + ViewStackProcessor.StopGetAccessRecording(); + }); + Text.pop(); + ListItem.pop(); + }; + if (isLazyCreate) { + observedShallowRender(); + } + else { + observedDeepRender(); + } + } + } + rerender() { + this.updateDirtyElements(); + } +} +loadDocument(new ParentView("1", undefined, {})); +` \ No newline at end of file