diff --git a/src/linter/ui5Types/amdTranspiler/rewriteExtendCall.ts b/src/linter/ui5Types/amdTranspiler/rewriteExtendCall.ts index 2b02e1f90..b9af9d002 100644 --- a/src/linter/ui5Types/amdTranspiler/rewriteExtendCall.ts +++ b/src/linter/ui5Types/amdTranspiler/rewriteExtendCall.ts @@ -18,10 +18,10 @@ export default function rewriteExtendCall(nodeFactory: ts.NodeFactory, callExp.expression.name.text === "extend")) { throw new UnsupportedExtendCall(`Not a UI5 Class#extends call ${toPosStr(callExp.expression)}`); } + const [extractedClassName, body] = extractInfoFromArguments(nodeFactory, callExp); if (!className) { - className = nodeFactory.createUniqueName(getClassNameFromArguments(callExp)); + className = nodeFactory.createUniqueName(extractedClassName); } - const body = getClassBodyFromArguments(nodeFactory, callExp); return nodeFactory.createClassDeclaration(modifiers, className, undefined, @@ -34,33 +34,33 @@ export default function rewriteExtendCall(nodeFactory: ts.NodeFactory, body); } -function getClassNameFromArguments(callExp: ts.CallExpression): string { - const firstArg = callExp.arguments[0]; - if (!firstArg) { - throw new UnsupportedExtendCall(`Missing extends argument at ${toPosStr(callExp)}`); +function extractInfoFromArguments( + nodeFactory: ts.NodeFactory, callExp: ts.CallExpression +): [string, ts.ClassElement[]] { + const args = callExp.arguments; + if (args.length === 0) { + throw new UnsupportedExtendCall(`Missing arguments at ${toPosStr(callExp)}`); } - if (firstArg && !ts.isStringLiteralLike(firstArg)) { - throw new UnsupportedExtendCall(`Unexpected extends argument of type ${ts.SyntaxKind[firstArg.kind]} at ` + - toPosStr(firstArg)); + const className = getClassNameFromArgument(args[0]); + // Class body is optional + const classBody: ts.ClassElement[] = args.length > 1 ? getClassBodyFromArgument(nodeFactory, args[1]) : []; + return [className, classBody]; +} + +function getClassNameFromArgument(className: ts.Expression): string { + if (!ts.isStringLiteralLike(className)) { + throw new UnsupportedExtendCall(`Unexpected extends argument of type ${ts.SyntaxKind[className.kind]} at ` + + toPosStr(className)); } // Just like OpenUI5's ObjectPath... - const nameSegments = firstArg.text.split("."); + const nameSegments = className.text.split("."); return nameSegments[nameSegments.length - 1]; } -function getClassBodyFromArguments( - nodeFactory: ts.NodeFactory, callExp: ts.CallExpression): ts.ClassElement[] { - const args = callExp.arguments; - let classBody: ts.ObjectLiteralExpression | undefined; - for (let i = args.length - 1; i >= 0; i--) { - const arg = args[i]; - if (ts.isObjectLiteralExpression(arg)) { - classBody = arg; - break; - } - } - if (!classBody) { - throw new UnsupportedExtendCall(`No class body found in extends call at ${toPosStr(callExp)}`); +function getClassBodyFromArgument(nodeFactory: ts.NodeFactory, classBody: ts.Expression): ts.ClassElement[] { + if (!ts.isObjectLiteralExpression(classBody)) { + throw new UnsupportedExtendCall(`Unexpected extends argument of type ${ts.SyntaxKind[classBody.kind]} at ` + + toPosStr(classBody)); } if (classBody.properties.find((prop) => ts.isSpreadAssignment(prop))) { // TODO: Support spread elements(?) diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_12/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_12/Component.js new file mode 100644 index 000000000..52a2b7140 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_12/Component.js @@ -0,0 +1,8 @@ +// Fixture description: +// Async flag (rootView only, no routing) in manifest.json +// No manifest: "json" configuration in metadata +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("mycomp.Component"); +}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_12/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_12/manifest.json new file mode 100644 index 000000000..d077969ee --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_12/manifest.json @@ -0,0 +1,23 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "mycomp", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "mycomp.view.App", + "type": "XML", + "id": "app", + "async": true + } + } +} diff --git a/test/fixtures/transpiler/amd/Factory_ClassWithoutClassInfo.js b/test/fixtures/transpiler/amd/Factory_ClassWithoutClassInfo.js new file mode 100644 index 000000000..ad92c2757 --- /dev/null +++ b/test/fixtures/transpiler/amd/Factory_ClassWithoutClassInfo.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + return UIComponent.extend("mycomp.Component"); +}); diff --git a/test/lib/linter/amdTranspiler/snapshots/transpiler.ts.md b/test/lib/linter/amdTranspiler/snapshots/transpiler.ts.md index f78080e7d..e279906d3 100644 --- a/test/lib/linter/amdTranspiler/snapshots/transpiler.ts.md +++ b/test/lib/linter/amdTranspiler/snapshots/transpiler.ts.md @@ -368,6 +368,28 @@ Generated by [AVA](https://avajs.dev). version: 3, } +## Transpile Factory_ClassWithoutClassInfo.js + +> Snapshot 1 + + `import UIComponent from "sap/ui/core/UIComponent";␊ + export default class Component_1 extends UIComponent {␊ + }␊ + //# sourceMappingURL=Factory_ClassWithoutClassInfo.js.map` + +> Snapshot 2 + + { + file: 'Factory_ClassWithoutClassInfo.js', + mappings: 'OAAqD,WAAW,MAAjD,yBAAyB;yCAChC,WAAW', + names: [], + sourceRoot: '', + sources: [ + 'Factory_ClassWithoutClassInfo.js', + ], + version: 3, + } + ## Transpile Factory_ClassWithoutName.js > Snapshot 1 diff --git a/test/lib/linter/amdTranspiler/snapshots/transpiler.ts.snap b/test/lib/linter/amdTranspiler/snapshots/transpiler.ts.snap index fb1929150..044c208a2 100644 Binary files a/test/lib/linter/amdTranspiler/snapshots/transpiler.ts.snap and b/test/lib/linter/amdTranspiler/snapshots/transpiler.ts.snap differ diff --git a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md index db43ded88..f2bf0b65d 100644 --- a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md +++ b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md @@ -537,3 +537,27 @@ Generated by [AVA](https://avajs.dev). warningCount: 1, }, ] + +## General: Positive_12 + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Component.js', + messages: [ + { + column: 9, + line: 7, + message: 'Component does not specify that it uses the descriptor via the manifest.json file', + messageDetails: 'A manifest.json has been found in the same directory as the component. Although it will be used at runtime automatically, this should still be expressed in the metadata of the component class (https://ui5.sap.com/#/topic/0187ea5e2eff4166b0453b9dcc8fc64f).', + ruleId: 'async-component-flags', + severity: 1, + }, + ], + warningCount: 1, + }, + ] diff --git a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap index b84ff36e3..d351468f4 100644 Binary files a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap and b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap differ