diff --git a/compiler/main.js b/compiler/main.js index d9de016..cd83906 100644 --- a/compiler/main.js +++ b/compiler/main.js @@ -443,3 +443,4 @@ exports.loadModuleInfo = loadModuleInfo; exports.systemModules = systemModules; exports.checkAppResourcePath = checkAppResourcePath; exports.addSDKBuildDependencies = addSDKBuildDependencies; +exports.compatibleSdkVersion = '8'; \ No newline at end of file diff --git a/compiler/src/pre_define.ts b/compiler/src/pre_define.ts index 6dd695a..46da357 100644 --- a/compiler/src/pre_define.ts +++ b/compiler/src/pre_define.ts @@ -275,3 +275,19 @@ export const ES2ABC: string = 'es2abc'; export const GENERATE_ID = 'generateId'; export const _GENERATE_ID = '__generate__Id'; + +export const COMPONENT_CONSTRUCTOR_INITIAL_PARAMS: string = 'setInitiallyProvidedValue'; +export const COMPONENT_RERENDER_FUNCTION: string = 'rerender'; +export const SETONEWAYSYNCPROPERTIESUNCHANGED: string = 'setOneWaySyncPropertiesUnchanged'; +export const SETTWOWAYSYNCPROPERTIESUNCHANGED: string = 'setTwoWaySyncPropertiesUnchanged'; +export const COMPONENT_CONSTRUCTOR_SET_STATE_UNCHANGED: string = 'setStateSourcePropertiesUnchanged'; +export const COMPONENT_CONSTRUCTOR_PURGE_VARIABLE_DEP: string = 'purgeVariableDependenciesOnElmtId'; +export const MARKDEPENDENTELEMENTSDIRTY: string = 'markDependentElementsDirty'; +export const ABOUT_TO_BE_DELETE_FUNCTION_ID__: string = 'id__'; +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 BASICDECORATORS: Set = new Set([COMPONENT_STATE_DECORATOR, COMPONENT_PROP_DECORATOR, + COMPONENT_LINK_DECORATOR]); diff --git a/compiler/src/process_component_class.ts b/compiler/src/process_component_class.ts index 6cf0021..d9291a8 100644 --- a/compiler/src/process_component_class.ts +++ b/compiler/src/process_component_class.ts @@ -33,10 +33,14 @@ import { BASE_COMPONENT_NAME, CREATE_CONSTRUCTOR_PARAMS, COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, + COMPONENT_CONSTRUCTOR_INITIAL_PARAMS, + COMPONENT_CONSTRUCTOR_SET_STATE_UNCHANGED, + COMPONENT_CONSTRUCTOR_PURGE_VARIABLE_DEP, COMPONENT_CONSTRUCTOR_DELETE_PARAMS, COMPONENT_DECORATOR_PREVIEW, CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER, ABOUT_TO_BE_DELETE_FUNCTION_ID, + ABOUT_TO_BE_DELETE_FUNCTION_ID__, CREATE_CONSTRUCTOR_GET_FUNCTION, CREATE_CONSTRUCTOR_DELETE_FUNCTION, FOREACH_OBSERVED_OBJECT, @@ -58,7 +62,13 @@ import { CUSTOM_COMPONENT, COMPONENT_CONSTRUCTOR_PARENT, COMPONENT_IF_UNDEFINED, - INNER_COMPONENT_MEMBER_DECORATORS + INNER_COMPONENT_MEMBER_DECORATORS, + COMPONENT_RERENDER_FUNCTION, + SETONEWAYSYNCPROPERTIESUNCHANGED, + SETTWOWAYSYNCPROPERTIESUNCHANGED, + RMELMTID, + ABOUTTOBEDELETEDINTERNAL, + UPDATEDIRTYELEMENTS } from './pre_define'; import { BUILDIN_STYLE_NAMES, @@ -72,7 +82,8 @@ import { componentCollection, linkCollection, localStorageLinkCollection, - localStoragePropCollection + localStoragePropCollection, + propCollection } from './validate_ui_syntax'; import { addConstructor, @@ -96,6 +107,7 @@ import { LogInfo, hasDecorator } from './utils'; +import { compatibleSdkVersion } from '../main'; export function processComponentClass(node: ts.StructDeclaration, context: ts.TransformationContext, log: LogInfo[], program: ts.Program): ts.ClassDeclaration { @@ -130,6 +142,11 @@ function processMembers(members: ts.NodeArray, parentComponentN const newMembers: ts.ClassElement[] = []; const watchMap: Map = new Map(); const updateParamsStatements: ts.Statement[] = []; + const setStateUnchangedStatements: ts.Statement[] = []; + const setOneWayUnchangedStatements: ts.Statement[] = []; + const setTwoWayUnchangedStatements: ts.Statement[] = []; + const purgeVariableDepStatements: ts.Statement[] = []; + const rerenderStatements: ts.Statement[] = []; const deleteParamsStatements: ts.PropertyDeclaration[] = []; const checkController: ControllerType = { hasController: !componentCollection.customDialogs.has(parentComponentName.getText()) }; @@ -169,6 +186,8 @@ function processMembers(members: ts.NodeArray, parentComponentN newMembers.push(result.getControllerSet()); } } + processPropertyUnchanged(result, setStateUnchangedStatements, setOneWayUnchangedStatements, + setTwoWayUnchangedStatements, purgeVariableDepStatements, rerenderStatements); } if (ts.isMethodDeclaration(item) && item.name) { updateItem = @@ -182,7 +201,8 @@ function processMembers(members: ts.NodeArray, parentComponentN validateBuildMethodCount(buildCount, parentComponentName, log); validateHasController(parentComponentName, checkController, log); newMembers.unshift(addDeleteParamsFunc(deleteParamsStatements)); - newMembers.unshift(addUpdateParamsFunc(updateParamsStatements, parentComponentName)); + addIntoNewMembers(newMembers, parentComponentName, updateParamsStatements, setStateUnchangedStatements, + setOneWayUnchangedStatements, setTwoWayUnchangedStatements, purgeVariableDepStatements, rerenderStatements); newMembers.unshift(addConstructor(ctorNode, watchMap, parentComponentName)); return newMembers; } @@ -202,6 +222,58 @@ function validateDecorators(item: ts.ClassElement, log: LogInfo[]): void { } } +function processPropertyUnchanged( + result: UpdateResult, + setStateUnchangedStatements: ts.Statement[], + setOneWayUnchangedStatements: ts.Statement[], + setTwoWayUnchangedStatements: ts.Statement[], + purgeVariableDepStatements: ts.Statement[], + rerenderStatements: ts.Statement[] +): void { + if (compatibleSdkVersion === '9') { + if(result.getPropertyUnchanged()) { + const propertyUnchanged: ts.Statement = result.getPropertyUnchanged(); + if (result.getDecoratorName() === COMPONENT_STATE_DECORATOR) { + setStateUnchangedStatements.push(propertyUnchanged); + } else if (result.getDecoratorName() === COMPONENT_PROP_DECORATOR) { + setOneWayUnchangedStatements.push(propertyUnchanged); + } else if(result.getDecoratorName() === COMPONENT_LINK_DECORATOR) { + setTwoWayUnchangedStatements.push(propertyUnchanged); + } + } + if(result.getPurgeVariableDepStatement()) { + purgeVariableDepStatements.push(result.getPurgeVariableDepStatement()); + } + if(result.getRerenderStatement()) { + rerenderStatements.push(result.getRerenderStatement()); + } + } +} + +function addIntoNewMembers( + newMembers: ts.ClassElement[], + parentComponentName: ts.Identifier, + updateParamsStatements: ts.Statement[], + setStateUnchangedStatements: ts.Statement[], + setOneWayUnchangedStatements: ts.Statement[], + setTwoWayUnchangedStatements: ts.Statement[], + purgeVariableDepStatements: ts.Statement[], + rerenderStatements: ts.Statement[] +): void { + if (compatibleSdkVersion === '9') { + newMembers.unshift( + addInitialParamsFunc(updateParamsStatements, parentComponentName), + createStateUnchangedFunc(setStateUnchangedStatements), + createOneWaySyncUnchangedFunc(setOneWayUnchangedStatements), + createTwoWaySyncUnchangedFunc(setTwoWayUnchangedStatements), + addPurgeVariableDepFunc(purgeVariableDepStatements) + ); + newMembers.push(addRerenderFunc(rerenderStatements)); + } else { + newMembers.unshift(addUpdateParamsFunc(updateParamsStatements, parentComponentName)); + } +} + function addPropertyMember(item: ts.ClassElement, newMembers: ts.ClassElement[], program: ts.Program, parentComponentName: string, log: LogInfo[]): void { const propertyItem: ts.PropertyDeclaration = item as ts.PropertyDeclaration; @@ -475,6 +547,7 @@ function judgmentParentType(node: ts.Node): boolean { export function createReference(node: ts.PropertyAssignment, log: LogInfo[]): ts.PropertyAssignment { const linkParentComponent: string[] = getParentNode(node, linkCollection).slice(1); + const propParentComponent: string[] = getParentNode(node, propCollection).slice(1); const propertyName: ts.Identifier = node.name as ts.Identifier; let initText: string; const LINK_REG: RegExp = /^\$/g; @@ -492,6 +565,9 @@ export function createReference(node: ts.PropertyAssignment, log: LogInfo[]): ts pos: initExpression.getStart() }); } + } else if (compatibleSdkVersion === '9' && isMatchInitExpression(initExpression) && + propParentComponent.includes(propertyName.escapedText.toString())) { + initText = initExpression.name.escapedText.toString(); } if (initText) { node = addDoubleUnderline(node, propertyName, initText); @@ -539,15 +615,49 @@ function addUpdateParamsFunc(statements: ts.Statement[], parentComponentName: ts return createParamsInitBlock(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, statements, parentComponentName); } +function addInitialParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): ts.MethodDeclaration { + return createParamsInitBlock(COMPONENT_CONSTRUCTOR_INITIAL_PARAMS, statements, parentComponentName); +} + +function createStateUnchangedFunc(statements: ts.Statement[]): ts.MethodDeclaration { + return ts.factory.createMethodDeclaration(undefined, undefined, undefined, + ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_SET_STATE_UNCHANGED), undefined, undefined, [], undefined, + ts.factory.createBlock(statements, true)); +} + +// @Prop +function createOneWaySyncUnchangedFunc(statements: ts.Statement[]): ts.MethodDeclaration { + return ts.factory.createMethodDeclaration(undefined, undefined, undefined, + ts.factory.createIdentifier(SETONEWAYSYNCPROPERTIESUNCHANGED), undefined, undefined, [], + undefined, ts.factory.createBlock(statements, true)); +} + +// @Link +function createTwoWaySyncUnchangedFunc(statements: ts.Statement[]): ts.MethodDeclaration { + return ts.factory.createMethodDeclaration( + undefined, undefined, undefined, ts.factory.createIdentifier(SETTWOWAYSYNCPROPERTIESUNCHANGED), + undefined, undefined, [], undefined, ts.factory.createBlock(statements, true)); +} + +function addPurgeVariableDepFunc(statements: ts.Statement[]): ts.MethodDeclaration { + return ts.factory.createMethodDeclaration( + undefined, undefined, undefined, + ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PURGE_VARIABLE_DEP), + undefined, undefined, [ts.factory.createParameterDeclaration(undefined, undefined, undefined, + ts.factory.createIdentifier(RMELMTID), undefined, undefined, undefined)], undefined, + ts.factory.createBlock(statements, true)); +} + function addDeleteParamsFunc(statements: ts.PropertyDeclaration[]): ts.MethodDeclaration { const deleteStatements: ts.ExpressionStatement[] = []; statements.forEach((statement: ts.PropertyDeclaration) => { const name: ts.Identifier = statement.name as ts.Identifier; - const paramsStatement: ts.ExpressionStatement = ts.factory.createExpressionStatement( - ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createThis(), - ts.factory.createIdentifier(`__${name.escapedText.toString()}`)), - ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_DELETE_PARAMS)), undefined, [])); + let paramsStatement: ts.ExpressionStatement; + if (compatibleSdkVersion === '9' && !statement.decorators) { + paramsStatement = createParamsStatement(name); + } else { + paramsStatement = createParamsWithUnderlineStatement(name); + } deleteStatements.push(paramsStatement); }); const defaultStatement: ts.ExpressionStatement = @@ -558,14 +668,55 @@ function addDeleteParamsFunc(statements: ts.PropertyDeclaration[]): ts.MethodDec ts.factory.createIdentifier(CREATE_CONSTRUCTOR_GET_FUNCTION)), undefined, []), ts.factory.createIdentifier(CREATE_CONSTRUCTOR_DELETE_FUNCTION)), undefined, [ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( - ts.factory.createThis(), ts.factory.createIdentifier(ABOUT_TO_BE_DELETE_FUNCTION_ID)), + ts.factory.createThis(), ts.factory.createIdentifier( + compatibleSdkVersion === '8' ? + ABOUT_TO_BE_DELETE_FUNCTION_ID : ABOUT_TO_BE_DELETE_FUNCTION_ID__)), undefined, [])])); deleteStatements.push(defaultStatement); + if (compatibleSdkVersion === '9') { + const aboutToBeDeletedInternalStatement: ts.ExpressionStatement = createDeletedInternalStatement(); + deleteStatements.push(aboutToBeDeletedInternalStatement); + } const deleteParamsMethod: ts.MethodDeclaration = createParamsInitBlock(COMPONENT_CONSTRUCTOR_DELETE_PARAMS, deleteStatements); return deleteParamsMethod; } +function createParamsStatement(name: ts.Identifier): ts.ExpressionStatement { + return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createThis(), + ts.factory.createIdentifier(`${name.escapedText.toString()}`) + ), + ts.factory.createToken(ts.SyntaxKind.EqualsToken), + ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED) + )); +} + +function createParamsWithUnderlineStatement(name: ts.Identifier): ts.ExpressionStatement { + return ts.factory.createExpressionStatement( + ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createThis(), + ts.factory.createIdentifier(`__${name.escapedText.toString()}`)), + ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_DELETE_PARAMS)), undefined, [])); +} + +function createDeletedInternalStatement(): ts.ExpressionStatement { + return ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createThis(), + ts.factory.createIdentifier(ABOUTTOBEDELETEDINTERNAL)), undefined, [])); +} + +function addRerenderFunc(statements: ts.Statement[]): ts.MethodDeclaration { + let updateDirtyElementStatement: ts.Statement = ts.factory.createExpressionStatement( + ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( + ts.factory.createThis(), ts.factory.createIdentifier(UPDATEDIRTYELEMENTS)), undefined, [])); + statements.push(updateDirtyElementStatement); + return ts.factory.createMethodDeclaration(undefined, undefined, undefined, + ts.factory.createIdentifier(COMPONENT_RERENDER_FUNCTION), undefined, undefined, [], undefined, + ts.factory.createBlock(statements, true)); +} + function createParamsInitBlock(express: string, statements: ts.Statement[], parentComponentName?: ts.Identifier): ts.MethodDeclaration { const methodDeclaration: ts.MethodDeclaration = ts.factory.createMethodDeclaration(undefined, diff --git a/compiler/src/process_component_constructor.ts b/compiler/src/process_component_constructor.ts index 5b04845..53ffde2 100644 --- a/compiler/src/process_component_constructor.ts +++ b/compiler/src/process_component_constructor.ts @@ -20,6 +20,7 @@ import { COMPONENT_CONSTRUCTOR_PARENT, COMPONENT_CONSTRUCTOR_PARAMS, COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, + COMPONENT_CONSTRUCTOR_INITIAL_PARAMS, COMPONENT_WATCH_FUNCTION, BASE_COMPONENT_NAME, INTERFACE_NAME_SUFFIX, @@ -31,6 +32,8 @@ import { localStoragePropCollection } from './validate_ui_syntax'; +import { compatibleSdkVersion } from '../main'; + export function getInitConstructor(members: ts.NodeArray, parentComponentName: ts.Identifier ): ts.ConstructorDeclaration { let ctorNode: any = members.find(item => { @@ -83,9 +86,16 @@ function initConstructorParams(node: ts.ConstructorDeclaration, parentComponentN } const localStorageNum: number = localStorageLinkCollection.get(parentComponentName.getText()).size + localStoragePropCollection.get(parentComponentName.getText()).size; - const paramNames: Set = new Set([COMPONENT_CONSTRUCTOR_ID, COMPONENT_CONSTRUCTOR_PARENT, - COMPONENT_CONSTRUCTOR_PARAMS, localStorageNum ? COMPONENT_CONSTRUCTOR_LOCALSTORAGE : - COMPONENT_CONSTRUCTOR_PARAMS]); + const paramNames: Set = compatibleSdkVersion === "8" ? new Set([ + COMPONENT_CONSTRUCTOR_ID, + COMPONENT_CONSTRUCTOR_PARENT, + COMPONENT_CONSTRUCTOR_PARAMS, + localStorageNum ? COMPONENT_CONSTRUCTOR_LOCALSTORAGE : COMPONENT_CONSTRUCTOR_PARAMS + ]) : new Set([ + COMPONENT_CONSTRUCTOR_PARENT, + COMPONENT_CONSTRUCTOR_PARAMS, + localStorageNum ? COMPONENT_CONSTRUCTOR_LOCALSTORAGE : COMPONENT_CONSTRUCTOR_PARAMS + ]); const newParameters: ts.ParameterDeclaration[] = Array.from(node.parameters); if (newParameters.length !== 0) { // @ts-ignore @@ -154,19 +164,42 @@ export function addConstructor(ctorNode: any, watchMap: Map, )); watchStatements.push(watchNode); }); - const callSuperStatement: ts.Statement = ts.factory.createExpressionStatement( - ts.factory.createCallExpression(ts.factory.createSuper(), undefined, - localStorageNum ? - [ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_ID), - ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), - ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_LOCALSTORAGE)] : - [ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_ID), - ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT)] - )); - const updateWithValueParamsStatement: ts.Statement = ts.factory.createExpressionStatement( - ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( - ts.factory.createThis(), ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS)), - undefined, [ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS)])); + const callSuperStatement: ts.Statement = createCallSuperStatement(localStorageNum); + const updateWithValueParamsStatement: ts.Statement = createUPdWithValStatement(); return updateConstructor(updateConstructor(ctorNode, [], [callSuperStatement], true), [], [...watchStatements, updateWithValueParamsStatement], false, true, parentComponentName); } + +function createCallSuperStatement(localStorageNum: number): ts.Statement{ + if (compatibleSdkVersion === '8') { + return ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createSuper(), undefined, + localStorageNum ? [ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_ID), + ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), + ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_LOCALSTORAGE)] : + [ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_ID), + ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT)])); + } else { + return (ts.factory.createExpressionStatement( + ts.factory.createCallExpression(ts.factory.createSuper(), undefined, + localStorageNum ? [ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), + ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_LOCALSTORAGE)] : + [ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT)]))); + } +} + +// create updateWithValueParamsStatement +function createUPdWithValStatement(): ts.Statement { + return ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createThis(), + ts.factory.createIdentifier( + compatibleSdkVersion === '8' ? COMPONENT_CONSTRUCTOR_UPDATE_PARAMS : COMPONENT_CONSTRUCTOR_INITIAL_PARAMS + ) + ), + undefined, + [ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS)] + ) + ); +} \ No newline at end of file diff --git a/compiler/src/process_component_member.ts b/compiler/src/process_component_member.ts index e1461c5..8ee76b0 100644 --- a/compiler/src/process_component_member.ts +++ b/compiler/src/process_component_member.ts @@ -55,7 +55,12 @@ import { COMPONENT_LOCAL_STORAGE_PROP_DECORATOR, COMPONENT_CONSTRUCTOR_PARENT, EXTNAME_ETS, - _GENERATE_ID + _GENERATE_ID, + MARKDEPENDENTELEMENTSDIRTY, + RMELMTID, + PURGEDEPENDENCYONELMTID, + SETPROPERTYUNCHANGED, + BASICDECORATORS } from './pre_define'; import { forbiddenUseStateType, @@ -81,6 +86,8 @@ import { import { transformLog } from './process_ui_syntax'; import { globalProgram, projectConfig } from '../main'; +import { compatibleSdkVersion } from '../main'; + export type ControllerType = { hasController: boolean } @@ -129,6 +136,10 @@ export class UpdateResult { private updateParams: ts.Statement; private deleteParams: boolean = false; private controllerSet: ts.MethodDeclaration; + private propertyUnchanged: ts.Statement; + private purgeVariableDepStatement: ts.Statement; + private rerenderStatement: ts.Statement; + private decoratorName: string; public setProperity(updateItem: ts.PropertyDeclaration) { this.itemUpdate = true; @@ -164,6 +175,22 @@ export class UpdateResult { this.deleteParams = deleteParams; } + public setPropertyUnchanged(propertyUnchanged: ts.Statement) { + this.propertyUnchanged = propertyUnchanged; + } + + public setPurgeVariableDepStatement(purgeVariableDepStatement: ts.Statement) { + this.purgeVariableDepStatement = purgeVariableDepStatement; + } + + public setRerenderStatement(rerenderStatement: ts.Statement) { + this.rerenderStatement = rerenderStatement; + } + + public setDecoratorName(decoratorName: string) { + this.decoratorName = decoratorName; + } + public isItemUpdate(): boolean { return this.itemUpdate; } @@ -184,6 +211,18 @@ export class UpdateResult { return this.updateParams; } + public getPropertyUnchanged(): ts.Statement { + return this.propertyUnchanged; + } + + public getPurgeVariableDepStatement(): ts.Statement { + return this.purgeVariableDepStatement; + } + + public getRerenderStatement(): ts.Statement { + return this.rerenderStatement; + } + public getVariableGet(): ts.GetAccessorDeclaration { return this.variableGet; } @@ -192,6 +231,10 @@ export class UpdateResult { return this.variableSet; } + public getDecoratorName(): string { + return this.decoratorName; + } + public isDeleteParams(): boolean { return this.deleteParams; } @@ -213,6 +256,9 @@ export function processMemberVariableDecorators(parentName: ts.Identifier, createVariableInitStatement(item, COMPONENT_NON_DECORATOR, log, program, context, hasPreview, interfaceNode)])); updateResult.setControllerSet(createControllerSet(item, parentName, name, checkController)); + if (compatibleSdkVersion === '9') { + updateResult.setDeleteParams(true); + } } else if (!item.type) { validatePropertyNonType(name, log); return updateResult; @@ -317,6 +363,61 @@ function processStateDecorators(node: ts.PropertyDeclaration, decorator: string, if (setUpdateParamsDecorators.has(decorator)) { updateResult.setUpdateParams(createUpdateParams(name, decorator)); } + if (compatibleSdkVersion === '9' && BASICDECORATORS.has(decorator)) { + const variableWithUnderLink: string = '__' + name.escapedText.toString(); + updateResult.setPropertyUnchanged(createPropertyUnchangedStatement(variableWithUnderLink)); + updateResult.setDecoratorName(decorator); + updateResult.setPurgeVariableDepStatement(createPurgeVariableDepStatement(variableWithUnderLink)); + updateResult.setRerenderStatement(createRerenderStatement(variableWithUnderLink)); + } +} + +function createPropertyUnchangedStatement(variableWithUnderLink: string): ts.Statement { + return ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createThis(), + ts.factory.createIdentifier(variableWithUnderLink) + ), + ts.factory.createIdentifier(SETPROPERTYUNCHANGED) + ), + undefined, + [] + ) + ); +} + +function createPurgeVariableDepStatement(variableWithUnderLink: string): ts.Statement { + return ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createThis(), + ts.factory.createIdentifier(variableWithUnderLink) + ), + ts.factory.createIdentifier(PURGEDEPENDENCYONELMTID) + ), + undefined, + [ts.factory.createIdentifier(RMELMTID)] + ) + ); +} + +function createRerenderStatement(variableWithUnderLink: string): ts.Statement { + return ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createThis(), + ts.factory.createIdentifier(variableWithUnderLink) + ), + ts.factory.createIdentifier(MARKDEPENDENTELEMENTSDIRTY) + ), + undefined, + [ts.factory.createThis()] + ) + ); } function processWatch(node: ts.PropertyDeclaration, decorator: ts.Decorator, @@ -422,6 +523,10 @@ function createUpdateParams(name: ts.Identifier, decorator: string): ts.Statemen updateParamsNode = createUpdateParamsWithIf(name); break; case COMPONENT_PROP_DECORATOR: + if (compatibleSdkVersion === '8') { + updateParamsNode = createUpdateParamsWithoutIf(name); + } + break; case COMPONENT_BUILDERPARAM_DECORATOR: updateParamsNode = createUpdateParamsWithoutIf(name); break; diff --git a/compiler/test/test.js b/compiler/test/test.js index 0595536..4bb9b6f 100644 --- a/compiler/test/test.js +++ b/compiler/test/test.js @@ -35,6 +35,9 @@ const { NATIVE_MODULE, SYSTEM_PLUGIN } = require('../lib/pre_define'); +const { + compatibleSdkVersion +} = require('../main'); function expectActual(name, filePath) { const content = require(filePath); @@ -59,7 +62,8 @@ function expectActual(name, filePath) { } mocha.describe('compiler', () => { - const utPath = path.resolve(__dirname, './ut'); + const utPath = compatibleSdkVersion === '8' ? + path.resolve(__dirname, './ut') : path.resolve(__dirname, './utForPartialUpdate'); const utFiles = []; readFile(utPath, utFiles); utFiles.forEach((item) => { diff --git a/compiler/test/utForPartialUpdate/ui_state_management/inner_struct_state_management/@link/@link.ts b/compiler/test/utForPartialUpdate/ui_state_management/inner_struct_state_management/@link/@link.ts new file mode 100644 index 0000000..524dd45 --- /dev/null +++ b/compiler/test/utForPartialUpdate/ui_state_management/inner_struct_state_management/@link/@link.ts @@ -0,0 +1,125 @@ +/* + * 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 = ` +@Component +struct LinkComponent { + @Link counter: string + build() { + Text(this.counter) + } +} + +@Entry +@Component +struct ParentComponent { + @State value: string = 'first init content'; + build() { + Column() { + LinkComponent({counter: this.$value}) + } + } +} +` +exports.expectResult = +`class LinkComponent extends View { + constructor(parent, params) { + super(parent); + this.__counter = new SynchedPropertySimpleTwoWay(params.counter, this, "counter"); + this.setInitiallyProvidedValue(params); + } + setInitiallyProvidedValue(params) { + } + setStateSourcePropertiesUnchanged() { + } + setOneWaySyncPropertiesUnchanged() { + } + setTwoWaySyncPropertiesUnchanged() { + this.__counter.SetPropertyUnchanged(); + } + purgeVariableDependenciesOnElmtId(rmElmtId) { + this.__counter.purgeDependencyOnElmtId(rmElmtId); + } + aboutToBeDeleted() { + this.__counter.aboutToBeDeleted(); + SubscriberManager.Get().delete(this.id__()); + this.aboutToBeDeletedInternal(); + } + get counter() { + return this.__counter.get(); + } + set counter(newValue) { + this.__counter.set(newValue); + } + render() { + Text.create(this.counter); + Text.pop(); + } + rerender() { + this.__counter.markDependentElementsDirty(this); + this.updateDirtyElements(); + } +} +class ParentComponent extends View { + constructor(parent, params) { + super(parent); + this.__value = new ObservedPropertySimple('first init content', this, "value"); + this.setInitiallyProvidedValue(params); + } + setInitiallyProvidedValue(params) { + if (params.value !== undefined) { + this.value = params.value; + } + } + setStateSourcePropertiesUnchanged() { + this.__value.SetPropertyUnchanged(); + } + setOneWaySyncPropertiesUnchanged() { + } + setTwoWaySyncPropertiesUnchanged() { + } + purgeVariableDependenciesOnElmtId(rmElmtId) { + this.__value.purgeDependencyOnElmtId(rmElmtId); + } + aboutToBeDeleted() { + this.__value.aboutToBeDeleted(); + SubscriberManager.Get().delete(this.id__()); + this.aboutToBeDeletedInternal(); + } + get value() { + return this.__value.get(); + } + set value(newValue) { + this.__value.set(newValue); + } + render() { + Column.create(); + let earlierCreatedChild_2 = this.findChildById("2"); + if (earlierCreatedChild_2 == undefined) { + View.create(new LinkComponent("2", this, { counter: this.__value })); + } + else { + earlierCreatedChild_2.updateWithValueParams({}); + View.create(earlierCreatedChild_2); + } + Column.pop(); + } + rerender() { + this.__value.markDependentElementsDirty(this); + this.updateDirtyElements(); + } +} +loadDocument(new ParentComponent("1", undefined, {})); +` \ No newline at end of file diff --git a/compiler/test/utForPartialUpdate/ui_state_management/inner_struct_state_management/@prop/@prop.ts b/compiler/test/utForPartialUpdate/ui_state_management/inner_struct_state_management/@prop/@prop.ts new file mode 100644 index 0000000..a4992f8 --- /dev/null +++ b/compiler/test/utForPartialUpdate/ui_state_management/inner_struct_state_management/@prop/@prop.ts @@ -0,0 +1,127 @@ +/* + * 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 = ` +@Component +struct PropComponent { + @Prop counter: string + build() { + Text(this.counter) + } +} + +@Entry +@Component +struct ParentComponent { + @State value: string = 'first init content'; + build() { + Column() { + PropComponent({counter: this.value}) + } + } +} +` +exports.expectResult = +`class PropComponent extends View { + constructor(parent, params) { + super(parent); + this.__counter = new SynchedPropertySimpleOneWay(params.counter, this, "counter"); + this.setInitiallyProvidedValue(params); + } + setInitiallyProvidedValue(params) { + } + setStateSourcePropertiesUnchanged() { + } + setOneWaySyncPropertiesUnchanged() { + this.__counter.SetPropertyUnchanged(); + } + setTwoWaySyncPropertiesUnchanged() { + } + purgeVariableDependenciesOnElmtId(rmElmtId) { + this.__counter.purgeDependencyOnElmtId(rmElmtId); + } + aboutToBeDeleted() { + this.__counter.aboutToBeDeleted(); + SubscriberManager.Get().delete(this.id__()); + this.aboutToBeDeletedInternal(); + } + get counter() { + return this.__counter.get(); + } + set counter(newValue) { + this.__counter.set(newValue); + } + render() { + Text.create(this.counter); + Text.pop(); + } + rerender() { + this.__counter.markDependentElementsDirty(this); + this.updateDirtyElements(); + } +} +class ParentComponent extends View { + constructor(parent, params) { + super(parent); + this.__value = new ObservedPropertySimple('first init content', this, "value"); + this.setInitiallyProvidedValue(params); + } + setInitiallyProvidedValue(params) { + if (params.value !== undefined) { + this.value = params.value; + } + } + setStateSourcePropertiesUnchanged() { + this.__value.SetPropertyUnchanged(); + } + setOneWaySyncPropertiesUnchanged() { + } + setTwoWaySyncPropertiesUnchanged() { + } + purgeVariableDependenciesOnElmtId(rmElmtId) { + this.__value.purgeDependencyOnElmtId(rmElmtId); + } + aboutToBeDeleted() { + this.__value.aboutToBeDeleted(); + SubscriberManager.Get().delete(this.id__()); + this.aboutToBeDeletedInternal(); + } + get value() { + return this.__value.get(); + } + set value(newValue) { + this.__value.set(newValue); + } + render() { + Column.create(); + let earlierCreatedChild_2 = this.findChildById("2"); + if (earlierCreatedChild_2 == undefined) { + View.create(new PropComponent("2", this, { counter: this.__value })); + } + else { + earlierCreatedChild_2.updateWithValueParams({ + counter: this.__value + }); + View.create(earlierCreatedChild_2); + } + Column.pop(); + } + rerender() { + this.__value.markDependentElementsDirty(this); + this.updateDirtyElements(); + } +} +loadDocument(new ParentComponent("1", undefined, {})); +` \ No newline at end of file diff --git a/compiler/test/utForPartialUpdate/ui_state_management/inner_struct_state_management/@state/@state.ts b/compiler/test/utForPartialUpdate/ui_state_management/inner_struct_state_management/@state/@state.ts new file mode 100644 index 0000000..960af8a --- /dev/null +++ b/compiler/test/utForPartialUpdate/ui_state_management/inner_struct_state_management/@state/@state.ts @@ -0,0 +1,73 @@ +/* + * 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 StatePage { + @State counter: number = 0; + build() { + Column() { + Text("counter:" + this.counter) + } + } +} +` +exports.expectResult = +`class StatePage extends View { + constructor(parent, params) { + super(parent); + this.__counter = new ObservedPropertySimple(0, this, "counter"); + this.setInitiallyProvidedValue(params); + } + setInitiallyProvidedValue(params) { + if (params.counter !== undefined) { + this.counter = params.counter; + } + } + setStateSourcePropertiesUnchanged() { + this.__counter.SetPropertyUnchanged(); + } + setOneWaySyncPropertiesUnchanged() { + } + setTwoWaySyncPropertiesUnchanged() { + } + purgeVariableDependenciesOnElmtId(rmElmtId) { + this.__counter.purgeDependencyOnElmtId(rmElmtId); + } + aboutToBeDeleted() { + this.__counter.aboutToBeDeleted(); + SubscriberManager.Get().delete(this.id__()); + this.aboutToBeDeletedInternal(); + } + get counter() { + return this.__counter.get(); + } + set counter(newValue) { + this.__counter.set(newValue); + } + render() { + Column.create(); + Text.create("counter:" + this.counter); + Text.pop(); + Column.pop(); + } + rerender() { + this.__counter.markDependentElementsDirty(this); + this.updateDirtyElements(); + } +} +loadDocument(new StatePage("1", undefined, {})); +`