!949 @Extend支持逻辑与属性混用

Merge pull request !949 from houhaoyu/master18
This commit is contained in:
openharmony_ci
2022-08-19 09:42:06 +00:00
committed by Gitee
5 changed files with 154 additions and 43 deletions
-1
View File
@@ -1,6 +1,5 @@
{
"name": "XComponent",
"atomic": true,
"attrs": [
"id", "type", "libraryname", "onLoad", "onDestroy"
]
+38 -9
View File
@@ -33,7 +33,8 @@ import {
STYLE_ADD_DOUBLE_DOLLAR,
$$,
PROPERTIES_ADD_DOUBLE_DOLLAR,
$$_BLOCK_INTERFACE
$$_BLOCK_INTERFACE,
COMPONENT_EXTEND_DECORATOR
} from './pre_define';
import { getName } from './process_component_build';
import { INNER_COMPONENT_NAMES } from './component_map';
@@ -43,6 +44,8 @@ import {
CacheFileName,
cache
} from './compile_info';
import { hasDecorator } from './utils';
import { isExtendFunction, isOriginalExtend } from './process_ui_syntax';
function readDeaclareFiles(): string[] {
const declarationsFileNames: string[] = [];
@@ -85,6 +88,12 @@ function setCompilerOptions() {
});
}
interface extendInfo {
start: number,
end: number,
compName: string
}
export function createLanguageService(rootFileNames: string[]): ts.LanguageService {
setCompilerOptions();
const files: ts.MapLike<{ version: number }> = {};
@@ -97,8 +106,9 @@ export function createLanguageService(rootFileNames: string[]): ts.LanguageServi
return undefined;
}
if (/(?<!\.d)\.(ets|ts)$/.test(fileName)) {
const content: string = processContent(fs.readFileSync(fileName).toString(), fileName);
checkUISyntax(content, fileName);
let content: string = processContent(fs.readFileSync(fileName).toString(), fileName);
const extendFunctionInfo: extendInfo[] = [];
content = instanceInsteadThis(content, fileName, extendFunctionInfo);
return ts.ScriptSnapshot.fromString(content);
}
return ts.ScriptSnapshot.fromString(fs.readFileSync(fileName).toString());
@@ -232,8 +242,9 @@ export function createWatchCompilerHost(rootFileNames: string[],
return undefined;
}
if (/(?<!\.d)\.(ets|ts)$/.test(fileName)) {
const content: string = processContent(fs.readFileSync(fileName).toString(), fileName);
checkUISyntax(content, fileName);
let content: string = processContent(fs.readFileSync(fileName).toString(), fileName);
const extendFunctionInfo: extendInfo[] = [];
content = instanceInsteadThis(content, fileName, extendFunctionInfo);
return content;
}
return fs.readFileSync(fileName).toString();
@@ -242,6 +253,18 @@ export function createWatchCompilerHost(rootFileNames: string[],
return host;
}
function instanceInsteadThis(content: string, fileName: string, extendFunctionInfo: extendInfo[]): string {
checkUISyntax(content, fileName, extendFunctionInfo);
extendFunctionInfo.reverse().forEach((item) => {
const subStr: string = content.substring(item.start, item.end);
const insert: string = subStr.replace(/(\s)this(\.)/g, (origin, item1, item2) => {
return item1 + item.compName + 'Instance' + item2;
});
content = content.slice(0, item.start) + insert + content.slice(item.end);
});
return content;
}
function getResolveModule(modulePath: string, type): ts.ResolvedModuleFull {
return {
resolvedFileName: modulePath,
@@ -255,18 +278,18 @@ export const decoratorParamsCollection: Set<string> = new Set();
export const extendCollection: Set<string> = new Set();
export const importModuleCollection: Set<string> = new Set();
function checkUISyntax(source: string, fileName: string): void {
function checkUISyntax(source: string, fileName: string, extendFunctionInfo: extendInfo[]): void {
if (/\.ets$/.test(fileName)) {
if (path.basename(fileName) !== 'app.ets') {
const sourceFile: ts.SourceFile = ts.createSourceFile(fileName, source,
ts.ScriptTarget.Latest, true, ts.ScriptKind.ETS);
parseAllNode(sourceFile, sourceFile);
parseAllNode(sourceFile, sourceFile, extendFunctionInfo);
props.push(...dollarCollection, ...decoratorParamsCollection, ...extendCollection);
}
}
}
function parseAllNode(node: ts.Node, sourceFileNode: ts.SourceFile): void {
function parseAllNode(node: ts.Node, sourceFileNode: ts.SourceFile, extendFunctionInfo: extendInfo[]): void {
if (ts.isStructDeclaration(node)) {
if (node.members) {
node.members.forEach(item => {
@@ -295,7 +318,13 @@ function parseAllNode(node: ts.Node, sourceFileNode: ts.SourceFile): void {
});
}
}
node.getChildren().forEach((item: ts.Node) => parseAllNode(item, sourceFileNode));
if (ts.isFunctionDeclaration(node) && hasDecorator(node, COMPONENT_EXTEND_DECORATOR)) {
if (node.body && node.body.statements && node.body.statements.length &&
!isOriginalExtend(node.body)) {
extendFunctionInfo.push({start: node.pos, end: node.end, compName: isExtendFunction(node)});
}
}
node.getChildren().forEach((item: ts.Node) => parseAllNode(item, sourceFileNode, extendFunctionInfo));
}
function traverseBuild(node: ts.Node, index: number): void {
+30 -14
View File
@@ -94,6 +94,7 @@ import {
import { projectConfig } from '../main';
import { transformLog, contextGlobal } from './process_ui_syntax';
import { props } from './compile_info';
import { CUSTOM_COMPONENT } from '../lib/pre_define';
export function processComponentBuild(node: ts.MethodDeclaration,
log: LogInfo[]): ts.MethodDeclaration {
@@ -113,10 +114,10 @@ export function processComponentBuild(node: ts.MethodDeclaration,
}
export function processComponentBlock(node: ts.Block, isLazy: boolean, log: LogInfo[],
isTransition: boolean = false, isInnerBuilder: boolean = false): ts.Block {
isTransition: boolean = false, isInnerBuilder: boolean = false, parent: string = undefined): ts.Block {
const newStatements: ts.Statement[] = [];
processComponentChild(node, newStatements, log,
{isAcceleratePreview: false, line: 0, column: 0, fileName: ''}, isInnerBuilder);
{isAcceleratePreview: false, line: 0, column: 0, fileName: ''}, isInnerBuilder, parent);
if (isLazy) {
newStatements.unshift(createRenderingInProgress(true));
}
@@ -214,7 +215,7 @@ let sourceNode: ts.SourceFile;
export function processComponentChild(node: ts.Block | ts.SourceFile, newStatements: ts.Statement[],
log: LogInfo[], supplement: supplementType = {isAcceleratePreview: false, line: 0, column: 0, fileName: ''},
isInnerBuilder: boolean = false): void {
isInnerBuilder: boolean = false, parent: string = undefined): void {
if (supplement.isAcceleratePreview) {
newsupplement = supplement;
const compilerOptions = ts.readConfigFile(
@@ -229,11 +230,13 @@ export function processComponentChild(node: ts.Block | ts.SourceFile, newStateme
if (ts.isExpressionStatement(item)) {
checkEtsComponent(item, log);
const name: string = getName(item);
switch (getComponentType(item, log, name)) {
switch (getComponentType(item, log, name, parent)) {
case ComponentType.innerComponent:
processInnerComponent(item, newStatements, log);
parent = name;
processInnerComponent(item, newStatements, log, parent);
break;
case ComponentType.customComponent:
parent = undefined;
if (!newsupplement.isAcceleratePreview) {
if (item.expression && ts.isEtsComponentExpression(item.expression) && item.expression.body) {
const expressionResult: ts.ExpressionStatement =
@@ -246,9 +249,11 @@ export function processComponentChild(node: ts.Block | ts.SourceFile, newStateme
}
break;
case ComponentType.forEachComponent:
parent = undefined;
processForEachComponent(item, newStatements, log, isInnerBuilder);
break;
case ComponentType.customBuilderMethod:
parent = undefined;
if (INNER_CUSTOM_BUILDER_METHOD.has(name)) {
newStatements.push(addInnerBuilderParameter(item));
} else {
@@ -256,8 +261,13 @@ export function processComponentChild(node: ts.Block | ts.SourceFile, newStateme
}
break;
case ComponentType.builderParamMethod:
parent = undefined;
newStatements.push(addInnerBuilderParameter(item));
break;
case ComponentType.function:
parent = undefined;
newStatements.push(item);
break;
}
} else if (ts.isIfStatement(item)) {
processIfStatement(item, newStatements, log, isInnerBuilder);
@@ -360,7 +370,8 @@ function parseEtsComponentExpression(node: ts.ExpressionStatement): EtsComponent
return { etsComponentNode: etsComponentNode, hasAttr: hasAttr };
}
function processInnerComponent(node: ts.ExpressionStatement, newStatements: ts.Statement[], log: LogInfo[]): void {
function processInnerComponent(node: ts.ExpressionStatement, newStatements: ts.Statement[],
log: LogInfo[], parent: string = undefined): void {
const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION);
newStatements.push(res.newNode);
const nameResult: NameResult = { name: null };
@@ -408,7 +419,8 @@ function processInnerComponent(node: ts.ExpressionStatement, newStatements: ts.S
if (etsComponentResult.hasAttr) {
bindComponentAttr(node, res.identifierNode, newStatements, log);
}
processComponentChild(etsComponentResult.etsComponentNode.body, newStatements, log);
processComponentChild(etsComponentResult.etsComponentNode.body, newStatements, log,
{isAcceleratePreview: false, line: 0, column: 0, fileName: ''}, false, parent);
} else {
bindComponentAttr(node, res.identifierNode, newStatements, log);
}
@@ -1148,9 +1160,9 @@ function traverseStateStylesAttr(temp: any, statements: ts.Statement[],
bindComponentAttr(ts.factory.createExpressionStatement(
item.initializer.properties[0].initializer), identifierNode, statements, log, false, true);
} else {
if (!(ts.isObjectLiteralExpression(item.initializer) && item.initializer.properties.length === 0)) {
validateStateStyleSyntax(temp, log);
}
if (!(ts.isObjectLiteralExpression(item.initializer) && item.initializer.properties.length === 0)) {
validateStateStyleSyntax(temp, log);
}
}
if (item.name) {
statements.push(createViewStackProcessor(item, false));
@@ -1288,7 +1300,8 @@ enum ComponentType {
customComponent,
forEachComponent,
customBuilderMethod,
builderParamMethod
builderParamMethod,
function
}
function isEtsComponent(node: ts.ExpressionStatement): boolean {
@@ -1304,7 +1317,7 @@ function isEtsComponent(node: ts.ExpressionStatement): boolean {
}
function getComponentType(node: ts.ExpressionStatement, log: LogInfo[],
name: string): ComponentType {
name: string, parent: string): ComponentType {
if (isEtsComponent(node)) {
if (componentCollection.customComponents.has(name)) {
return ComponentType.customComponent;
@@ -1320,6 +1333,9 @@ function getComponentType(node: ts.ExpressionStatement, log: LogInfo[],
} else if (builderParamObjectCollection.get(componentCollection.currentClassName) &&
builderParamObjectCollection.get(componentCollection.currentClassName).has(name)) {
return ComponentType.builderParamMethod;
} else if ((['Column', 'XComponent'].includes(parent) || CUSTOM_BUILDER_METHOD.has(parent)) &&
ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression)) {
return ComponentType.function;
} else if (!isAttributeNode(node)) {
log.push({
type: LogType.ERROR,
@@ -1340,7 +1356,7 @@ export function validateStateStyleSyntax(temp: any, log: LogInfo[]): void {
function getEtsComponentExpression(node:ts.ExpressionStatement): ts.EtsComponentExpression {
let current: any = node.expression;
while(current) {
while (current) {
if (ts.isEtsComponentExpression(current)) {
return current;
}
@@ -1350,7 +1366,7 @@ function getEtsComponentExpression(node:ts.ExpressionStatement): ts.EtsComponent
}
function checkEtsComponent(node: ts.ExpressionStatement, log: LogInfo[]): void {
const etsComponentExpression: ts.EtsComponentExpression = getEtsComponentExpression(node);
const etsComponentExpression: ts.EtsComponentExpression = getEtsComponentExpression(node);
if (etsComponentExpression) {
checkAllNode(
etsComponentExpression,
+22 -10
View File
@@ -363,16 +363,28 @@ function createFindChildById(id: string, name: string, isInnerBuilder: boolean =
return ts.factory.createVariableStatement(undefined, ts.factory.createVariableDeclarationList(
[ts.factory.createVariableDeclaration(ts.factory.createIdentifier(
`${CUSTOM_COMPONENT_EARLIER_CREATE_CHILD}${id}`), undefined, ts.factory.createTypeReferenceNode(
ts.factory.createIdentifier(name)), ts.factory.createAsExpression(ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(isInnerBuilder ?
ts.factory.createParenthesizedExpression(ts.factory.createConditionalExpression(
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.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));
ts.factory.createIdentifier(name)),
ts.factory.createConditionalExpression(
ts.factory.createParenthesizedExpression(
ts.factory.createBinaryExpression(
ts.factory.createThis(),
ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
ts.factory.createPropertyAccessExpression(
ts.factory.createThis(),
ts.factory.createIdentifier(CUSTOM_COMPONENT_FUNCTION_FIND_CHILD_BY_ID)
))), ts.factory.createToken(ts.SyntaxKind.QuestionToken),
ts.factory.createAsExpression(ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(isInnerBuilder ?
ts.factory.createParenthesizedExpression(ts.factory.createConditionalExpression(
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.createThis(), ts.factory.createIdentifier(
`${CUSTOM_COMPONENT_FUNCTION_FIND_CHILD_BY_ID}`)), undefined, [ts.factory.createStringLiteral(id)]),
ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(name))),
ts.factory.createToken(ts.SyntaxKind.ColonToken),
ts.factory.createIdentifier('undefined')))], ts.NodeFlags.Let));
}
function createCustomComponentIfStatement(id: string, node: ts.ExpressionStatement,
+64 -9
View File
@@ -141,7 +141,7 @@ export function processUISyntax(program: ts.Program, ut = false): Function {
CUSTOM_BUILDER_METHOD.add(node.name.getText());
node = ts.factory.updateFunctionDeclaration(node, undefined, node.modifiers,
node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type,
processComponentBlock(node.body, false, transformLog.errors));
processComponentBlock(node.body, false, transformLog.errors, false, false, node.name.getText()));
} else if (hasDecorator(node, COMPONENT_STYLES_DECORATOR)) {
if (node.parameters.length === 0) {
node = undefined;
@@ -425,10 +425,15 @@ function processExtend(node: ts.FunctionDeclaration, log: LogInfo[]): ts.Functio
const componentName: string = isExtendFunction(node);
if (componentName && node.body && node.body.statements.length) {
const statementArray: ts.Statement[] = [];
let bodynode: ts.Block;
const attrSet: ts.CallExpression = node.body.statements[0].expression;
const changeCompName: ts.ExpressionStatement = ts.factory.createExpressionStatement(processExtendBody(attrSet));
bindComponentAttr(changeCompName as ts.ExpressionStatement,
ts.factory.createIdentifier(componentName), statementArray, log);
if (isOriginalExtend(node.body)) {
const changeCompName: ts.ExpressionStatement = ts.factory.createExpressionStatement(processExtendBody(attrSet));
bindComponentAttr(changeCompName as ts.ExpressionStatement,
ts.factory.createIdentifier(componentName), statementArray, log);
} else {
bodynode = ts.visitEachChild(node.body, traverseExtendExpression, contextGlobal);
}
let extendFunctionName: string;
if (node.name.getText().startsWith('__' + componentName + '__')) {
extendFunctionName = node.name.getText();
@@ -438,18 +443,68 @@ function processExtend(node: ts.FunctionDeclaration, log: LogInfo[]): ts.Functio
}
return ts.factory.updateFunctionDeclaration(node, undefined, node.modifiers, node.asteriskToken,
ts.factory.createIdentifier(extendFunctionName), node.typeParameters,
node.parameters, node.type, ts.factory.updateBlock(node.body, statementArray));
node.parameters, node.type, isOriginalExtend(node.body) ?
ts.factory.updateBlock(node.body, statementArray) : bodynode);
}
function traverseExtendExpression(node: ts.Node): ts.Node {
if (ts.isExpressionStatement(node) && isThisNode(node)) {
const changeCompName: ts.ExpressionStatement =
ts.factory.createExpressionStatement(processExtendBody(node.expression, componentName));
const statementArray: ts.Statement[] = [];
bindComponentAttr(changeCompName, ts.factory.createIdentifier(componentName), statementArray, []);
return ts.factory.createCallExpression(
ts.factory.createParenthesizedExpression(ts.factory.createFunctionExpression(
undefined, undefined, undefined, undefined, [], undefined,
ts.factory.createBlock(statementArray, true))), undefined, []);
}
return ts.visitEachChild(node, traverseExtendExpression, contextGlobal);
}
}
function processExtendBody(node: ts.Node): ts.Expression {
export function isOriginalExtend(node: ts.Block): boolean {
let innerNode: ts.Node = node.statements[0];
if (node.statements.length === 1 && ts.isExpressionStatement(innerNode)) {
while (innerNode.expression) {
innerNode = innerNode.expression;
}
if (ts.isIdentifier(innerNode) && innerNode.pos && innerNode.end && innerNode.pos === innerNode.end &&
innerNode.escapedText.toString().match(/Instance$/)) {
return true;
}
}
return false;
}
function isThisNode(node: ts.ExpressionStatement): boolean {
let innerNode: ts.Node = node;
while (innerNode.expression) {
innerNode = innerNode.expression;
}
if (innerNode.kind === ts.SyntaxKind.ThisKeyword) {
return true;
} else {
return false;
}
}
function processExtendBody(node: ts.Node, componentName?: string): ts.Expression {
switch (node.kind) {
case ts.SyntaxKind.CallExpression:
return ts.factory.createCallExpression(processExtendBody(node.expression), undefined, node.arguments);
return ts.factory.createCallExpression(processExtendBody(node.expression, componentName),
undefined, node.arguments);
case ts.SyntaxKind.PropertyAccessExpression:
return ts.factory.createPropertyAccessExpression(processExtendBody(node.expression), node.name);
return ts.factory.createPropertyAccessExpression(
processExtendBody(node.expression, componentName), node.name);
case ts.SyntaxKind.Identifier:
return ts.factory.createIdentifier(node.escapedText.toString().replace(INSTANCE, ''));
if (!componentName) {
return ts.factory.createIdentifier(node.escapedText.toString().replace(INSTANCE, ''));
}
break;
case ts.SyntaxKind.ThisKeyword:
if (componentName) {
return ts.factory.createIdentifier(componentName);
}
break;
}
}