extend support logic

Signed-off-by: houhaoyu <houhaoyu@huawei.com>
Change-Id: I51bef8847b245afd90972fd54a1213b5a72eacfa
This commit is contained in:
houhaoyu
2022-08-18 19:05:26 +08:00
parent d64367656d
commit 4af54783b3
2 changed files with 104 additions and 17 deletions
+52 -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 } 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);
let 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);
let 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)=>{
let subStr: string = content.substring(item.start,item.end);
let 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,27 @@ 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));
}
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 traverseBuild(node: ts.Node, index: number): void {
+52 -8
View File
@@ -80,6 +80,7 @@ import {
projectConfig
} from '../main';
import { createCustomComponentNewExpression, createViewCreate } from './process_component_member';
import { isOriginalExtend } from './ets_checker'
export const transformLog: FileLog = new FileLog();
export let contextGlobal: ts.TransformationContext;
@@ -425,10 +426,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 +444,56 @@ 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)) {
let 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 {
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;
}
}