!764 add: validate component

Merge pull request !764 from laibo102/master
This commit is contained in:
openharmony_ci
2022-06-27 11:24:11 +00:00
committed by Gitee
2 changed files with 85 additions and 50 deletions
+38 -4
View File
@@ -81,7 +81,8 @@ import {
} from './component_map';
import {
componentCollection,
builderParamObjectCollection
builderParamObjectCollection,
checkAllNode
} from './validate_ui_syntax';
import { processCustomComponent } from './process_custom_component';
import {
@@ -134,8 +135,17 @@ export function processComponentBlock(node: ts.Block, isLazy: boolean, log: LogI
function validateRootNode(node: ts.MethodDeclaration, log: LogInfo[]): boolean {
let isValid: boolean = false;
if (node.body.statements.length === 1) {
const statement: ts.Statement = node.body.statements[0];
const bodyStatements: ts.NodeArray<ts.Statement> = node.body.statements;
let length: number = bodyStatements.length;
bodyStatements.map(node => {
const nodeName: string = node.expression && node.expression.expression &&
node.expression.expression.escapedText || undefined;
if (BUILDER_MIX_STYLES.has(nodeName) || BUILDER_MIX_EXTEND.has(nodeName)) {
length--;
}
});
if (length === 1) {
const statement: ts.Statement = bodyStatements[0];
if (ts.isIfStatement(statement) || validateFirstNode(statement)) {
isValid = true;
}
@@ -146,7 +156,7 @@ function validateRootNode(node: ts.MethodDeclaration, log: LogInfo[]): boolean {
log.push({
type: LogType.ERROR,
message: `There should have a root container component.`,
pos: node.body.statements.pos
pos: bodyStatements.pos
});
}
return isValid;
@@ -226,6 +236,7 @@ export function processComponentChild(node: ts.Block | ts.SourceFile, newStateme
let lastExpression: ts.Statement;
node.statements.forEach((item, index) => {
if (ts.isExpressionStatement(item)) {
checkEtsComponent(item, log);
const name: string = getName(item);
switch (getComponentType(item, log, name)) {
case ComponentType.innerComponent:
@@ -1355,3 +1366,26 @@ export function validateStateStyleSyntax(temp: any, log: LogInfo[]): void {
pos: temp.getStart()
});
}
function getEtsComponentExpression(node:ts.ExpressionStatement): ts.EtsComponentExpression {
let current: any = node.expression;
while(current) {
if (ts.isEtsComponentExpression(current)) {
return current;
}
current = current.expression;
}
return null;
}
function checkEtsComponent(node: ts.ExpressionStatement, log: LogInfo[]): void {
const etsComponentExpression: ts.EtsComponentExpression = getEtsComponentExpression(node);
if (etsComponentExpression) {
checkAllNode(
etsComponentExpression,
new Set([...INNER_COMPONENT_NAMES, ...componentCollection.customComponents]),
transformLog.sourceFile,
log
);
}
}
+47 -46
View File
@@ -333,7 +333,6 @@ function checkUISyntax(filePath: string, allComponentNames: Set<string>, content
function visitAllNode(node: ts.Node, sourceFileNode: ts.SourceFile, allComponentNames: Set<string>,
log: LogInfo[]) {
checkAllNode(node, allComponentNames, sourceFileNode, log);
if (ts.isStructDeclaration(node) && node.name && ts.isIdentifier(node.name)) {
collectComponentProps(node);
}
@@ -359,18 +358,17 @@ function visitAllNode(node: ts.Node, sourceFileNode: ts.SourceFile, allComponent
node.getChildren().forEach((item: ts.Node) => visitAllNode(item, sourceFileNode, allComponentNames, log));
}
function checkAllNode(node: ts.Node, allComponentNames: Set<string>, sourceFileNode: ts.SourceFile,
log: LogInfo[]): void {
if (ts.isExpressionStatement(node) && node.expression && ts.isIdentifier(node.expression) &&
allComponentNames.has(node.expression.escapedText.toString())) {
const pos: number = node.expression.getStart();
const message: string =
`The component name must be followed by parentheses, like '${node.expression.getText()}()'.`;
addLog(LogType.ERROR, message, pos, log, sourceFileNode);
export function checkAllNode(
node: ts.EtsComponentExpression,
allComponentNames: Set<string>,
sourceFileNode: ts.SourceFile,
log: LogInfo[]
): void {
if (ts.isIdentifier(node.expression)) {
checkNoChildComponent(node, sourceFileNode, log);
checkOneChildComponent(node, allComponentNames, sourceFileNode, log);
checkSpecificChildComponent(node, allComponentNames, sourceFileNode, log);
}
checkNoChildComponent(node, sourceFileNode, log);
checkOneChildComponent(node, allComponentNames, sourceFileNode, log);
checkSpecificChildComponent(node, allComponentNames, sourceFileNode, log);
}
interface ParamType {
@@ -378,12 +376,11 @@ interface ParamType {
value: string,
}
function checkNoChildComponent(node: ts.Node, sourceFileNode: ts.SourceFile, log: LogInfo[]): void {
function checkNoChildComponent(node: ts.EtsComponentExpression, sourceFileNode: ts.SourceFile, log: LogInfo[]): void {
const isCheckType: ParamType = { name: null, value: null};
if (ts.isExpressionStatement(node) && ts.isEtsComponentExpression(node.expression) &&
ts.isIdentifier(node.expression.expression) && hasChild(node, isCheckType)) {
const componentName: string = node.expression.expression.escapedText.toString();
const pos: number = node.expression.expression.getStart();
if (hasChild(node, isCheckType)) {
const componentName: string = (node.expression as ts.Identifier).escapedText.toString();
const pos: number = node.expression.getStart();
const message: string = isCheckType.name === null ?
`The component '${componentName}' can't have any child.` :
`When the component '${componentName}' set '${isCheckType.name}' is '${isCheckType.value}'` +
@@ -392,11 +389,10 @@ function checkNoChildComponent(node: ts.Node, sourceFileNode: ts.SourceFile, log
}
}
function hasChild(node: ts.ExpressionStatement, isCheckType: ParamType): boolean {
const etsComponentExpression: ts.EtsComponentExpression = node.expression as ts.EtsComponentExpression;
const nodeName: ts.Identifier = etsComponentExpression.expression as ts.Identifier;
if (AUTOMIC_COMPONENT.has(nodeName.escapedText.toString()) || judgeComponentType(
nodeName, etsComponentExpression, isCheckType) && getNextNode(etsComponentExpression)) {
function hasChild(node: ts.EtsComponentExpression, isCheckType: ParamType): boolean {
const nodeName: ts.Identifier = node.expression as ts.Identifier;
if ((AUTOMIC_COMPONENT.has(nodeName.escapedText.toString()) || judgeComponentType(nodeName, node, isCheckType)) &&
getNextNode(node)) {
return true;
}
return false;
@@ -433,13 +429,12 @@ function getNextNode(node: ts.EtsComponentExpression): ts.Block {
}
}
function checkOneChildComponent(node: ts.Node, allComponentNames: Set<string>,
function checkOneChildComponent(node: ts.EtsComponentExpression, allComponentNames: Set<string>,
sourceFileNode: ts.SourceFile, log: LogInfo[]): void {
const isCheckType: ParamType = { name: null, value: null};
if (ts.isExpressionStatement(node) && ts.isEtsComponentExpression(node.expression) &&
ts.isIdentifier(node.expression.expression) && hasNonSingleChild(node, allComponentNames, isCheckType)) {
const componentName: string = node.expression.expression.escapedText.toString();
const pos: number = node.expression.expression.getStart();
if (hasNonSingleChild(node, allComponentNames, isCheckType)) {
const componentName: string = (node.expression as ts.Identifier).escapedText.toString();
const pos: number = node.expression.getStart();
const message: string = isCheckType.name === null ?
`The component '${componentName}' can only have a single child component.` :
`When the component '${componentName}' set '${isCheckType.name}' is ` +
@@ -448,21 +443,29 @@ function checkOneChildComponent(node: ts.Node, allComponentNames: Set<string>,
}
}
function hasNonSingleChild(node: ts.ExpressionStatement, allComponentNames: Set<string>,
function hasNonSingleChild(node: ts.EtsComponentExpression, allComponentNames: Set<string>,
isCheckType: ParamType): boolean {
const etsComponentExpression: ts.EtsComponentExpression = node.expression as ts.EtsComponentExpression;
const nodeName: ts.Identifier = etsComponentExpression.expression as ts.Identifier;
const BlockNode: ts.Block = getNextNode(etsComponentExpression);
if (SINGLE_CHILD_COMPONENT.has(nodeName.escapedText.toString()) || !judgeComponentType(
nodeName, etsComponentExpression, isCheckType) && isCheckType.value === COMPONENT_BUTTON) {
const nodeName: ts.Identifier = node.expression as ts.Identifier;
const BlockNode: ts.Block = getNextNode(node);
if ((SINGLE_CHILD_COMPONENT.has(nodeName.escapedText.toString()) || !judgeComponentType(nodeName, node, isCheckType))
&& isCheckType.value === COMPONENT_BUTTON) {
if (!BlockNode) {
return false;
}
if (BlockNode && BlockNode.statements) {
const length: number = BlockNode.statements.length;
let length: number = BlockNode.statements.length;
if (!length) {
return false;
}
BlockNode.statements.map(node => {
const nodeName: string = ts.isExpressionStatement(node) &&
ts.isCallExpression(node.expression) &&
ts.isIdentifier(node.expression.expression) ?
node.expression.expression.escapedText.toString() : '';
if (BUILDER_MIX_STYLES.has(nodeName) || BUILDER_MIX_EXTEND.has(nodeName)) {
length--;
}
});
if (length > 3) {
return true;
}
@@ -507,7 +510,7 @@ function getBlockChildrenCount(blockNode: ts.Block, allComponentNames: Set<strin
return maxCount;
}
function isComponent(node: ts.EtsComponentExpression, allComponentNames: Set<string>): boolean {
function isComponent(node: ts.EtsComponentExpression | ts.CallExpression, allComponentNames: Set<string>): boolean {
if (ts.isIdentifier(node.expression) &&
allComponentNames.has(node.expression.escapedText.toString())) {
return true;
@@ -515,7 +518,7 @@ function isComponent(node: ts.EtsComponentExpression, allComponentNames: Set<str
return false;
}
function isForEachComponent(node: ts.CallExpression): boolean {
function isForEachComponent(node: ts.EtsComponentExpression | ts.CallExpression): boolean {
if (ts.isIdentifier(node.expression)) {
const componentName: string = node.expression.escapedText.toString();
return componentName === COMPONENT_FOREACH || componentName === COMPONENT_LAZYFOREACH;
@@ -548,12 +551,11 @@ function getStatementCount(node: ts.Node, allComponentNames: Set<string>): numbe
return maxCount;
}
function checkSpecificChildComponent(node: ts.Node, allComponentNames: Set<string>,
function checkSpecificChildComponent(node: ts.EtsComponentExpression, allComponentNames: Set<string>,
sourceFileNode: ts.SourceFile, log: LogInfo[]): void {
if (ts.isExpressionStatement(node) && ts.isCallExpression(node.expression) &&
ts.isIdentifier(node.expression.expression) && hasNonspecificChild(node, allComponentNames)) {
const componentName: string = node.expression.expression.escapedText.toString();
const pos: number = node.expression.expression.getStart();
if (hasNonspecificChild(node, allComponentNames)) {
const componentName: string = (node.expression as ts.Identifier).escapedText.toString();
const pos: number = node.expression.getStart();
const specificChildArray: string =
Array.from(SPECIFIC_CHILD_COMPONENT.get(componentName)).join(' and ');
const message: string =
@@ -562,12 +564,11 @@ function checkSpecificChildComponent(node: ts.Node, allComponentNames: Set<strin
}
}
function hasNonspecificChild(node: ts.ExpressionStatement,
function hasNonspecificChild(node: ts.EtsComponentExpression,
allComponentNames: Set<string>): boolean {
const etsComponentExpression: ts.EtsComponentExpression = node.expression as ts.EtsComponentExpression;
const nodeName: ts.Identifier = etsComponentExpression.expression as ts.Identifier;
const nodeName: ts.Identifier = node.expression as ts.Identifier;
const nodeNameString: string = nodeName.escapedText.toString();
const blockNode: ts.Block = getNextNode(etsComponentExpression);
const blockNode: ts.Block = getNextNode(node);
let isNonspecific: boolean = false;
if (SPECIFIC_CHILD_COMPONENT.has(nodeNameString) && blockNode) {
const specificChildSet: Set<string> = SPECIFIC_CHILD_COMPONENT.get(nodeNameString);
@@ -1070,4 +1071,4 @@ export function resetComponentCollection() {
componentCollection.entryComponent = null;
componentCollection.entryComponentPos = null;
componentCollection.previewComponent = new Set([]);
}
}