diff --git a/packages/plugin/__test__/__snapshots__/test.js.snap b/packages/plugin/__test__/__snapshots__/test.js.snap index 895385d..08f6bad 100644 --- a/packages/plugin/__test__/__snapshots__/test.js.snap +++ b/packages/plugin/__test__/__snapshots__/test.js.snap @@ -1670,12 +1670,35 @@ exports[`typescript ts-class-controller-extension-extended.ts 1`] = ` "use strict"; const MyExtendedController = Controller.extend("test.controller.MyExtendedController", { + constructor: function constructor() { + Controller.prototype.constructor.apply(this, arguments); + this.routing2 = Routing.use(Routing.override({})); + this.routing3 = Controller.use(Routing.override({})); + }, routing: Routing.override({}) }); return MyExtendedController; });" `; +exports[`typescript ts-class-controller-extension-extended-error-1.ts 1`] = ` +"ControllerExtension.use() must be called with exactly one argument but has 0 +  7 |  */ +  8 | export default class MyExtendedController extends Controller { +> 9 | routing = ControllerExtension.use(); // should throw an error +  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +  10 | }" +`; + +exports[`typescript ts-class-controller-extension-extended-error-2.ts 1`] = ` +"ControllerExtension.use() must be called with exactly one argument but has 2 +  7 |  */ +  8 | export default class MyExtendedController extends Controller { +> 9 | routing = ControllerExtension.use(1, 2); // should throw an error +  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +  10 | }" +`; + exports[`typescript ts-class-controller-extension-extended-explicit-type.ts 1`] = ` "sap.ui.define(["sap/ui/core/mvc/Controller", "sap/ui/core/mvc/ControllerExtension", "sap/fe/core/controllerextensions/Routing"], function (Controller, ControllerExtension, Routing) { "use strict"; @@ -1691,6 +1714,17 @@ exports[`typescript ts-class-controller-extension-extended-explicit-type.ts 1`] });" `; +exports[`typescript ts-class-controller-extension-extended-renamed.ts 1`] = ` +"sap.ui.define(["sap/ui/core/mvc/Controller", "sap/ui/core/mvc/ControllerExtension", "sap/fe/core/controllerextensions/Routing"], function (Controller, CtrlEx, Routing) { + "use strict"; + + const MyExtendedController = Controller.extend("test.controller.MyExtendedController", { + routing: Routing.override({}) + }); + return MyExtendedController; +});" +`; + exports[`typescript ts-class-controller-extension-usage.ts 1`] = ` "sap.ui.define(["sap/ui/core/mvc/Controller", "sap/fe/core/controllerextensions/Routing", "sap/fe/core/controllerextensions/OtherExtension", "sap/fe/core/controllerextensions/ThirdExtension", "sap/fe/core/controllerextensions/DoubleExportExtension", "sap/fe/core/controllerextensions/ManyExtensions"], function (Controller, Routing, sap_fe_core_controllerextensions_OtherExtension, ThirdExtension, sap_fe_core_controllerextensions_DoubleExportExtension, extensionCollection) { "use strict"; diff --git a/packages/plugin/__test__/fixtures/typescript/ts-class-controller-extension-extended-error-1.ts b/packages/plugin/__test__/fixtures/typescript/ts-class-controller-extension-extended-error-1.ts new file mode 100644 index 0000000..55571b8 --- /dev/null +++ b/packages/plugin/__test__/fixtures/typescript/ts-class-controller-extension-extended-error-1.ts @@ -0,0 +1,10 @@ +import Controller from "sap/ui/core/mvc/Controller"; +import ControllerExtension from "sap/ui/core/mvc/ControllerExtension"; +import Routing from "sap/fe/core/controllerextensions/Routing"; + +/** + * @namespace test.controller + */ +export default class MyExtendedController extends Controller { + routing = ControllerExtension.use(); // should throw an error +} \ No newline at end of file diff --git a/packages/plugin/__test__/fixtures/typescript/ts-class-controller-extension-extended-error-2.ts b/packages/plugin/__test__/fixtures/typescript/ts-class-controller-extension-extended-error-2.ts new file mode 100644 index 0000000..67f8900 --- /dev/null +++ b/packages/plugin/__test__/fixtures/typescript/ts-class-controller-extension-extended-error-2.ts @@ -0,0 +1,10 @@ +import Controller from "sap/ui/core/mvc/Controller"; +import ControllerExtension from "sap/ui/core/mvc/ControllerExtension"; +import Routing from "sap/fe/core/controllerextensions/Routing"; + +/** + * @namespace test.controller + */ +export default class MyExtendedController extends Controller { + routing = ControllerExtension.use(1, 2); // should throw an error +} \ No newline at end of file diff --git a/packages/plugin/__test__/fixtures/typescript/ts-class-controller-extension-extended-renamed.ts b/packages/plugin/__test__/fixtures/typescript/ts-class-controller-extension-extended-renamed.ts new file mode 100644 index 0000000..984bde8 --- /dev/null +++ b/packages/plugin/__test__/fixtures/typescript/ts-class-controller-extension-extended-renamed.ts @@ -0,0 +1,17 @@ +import Controller from "sap/ui/core/mvc/Controller"; +import CtrlEx from "sap/ui/core/mvc/ControllerExtension"; +import Routing from "sap/fe/core/controllerextensions/Routing"; + +/** + * @namespace test.controller + */ +export default class MyExtendedController extends Controller { + routing = /* comment */ CtrlEx.use( + /* comment */ + Routing.override( + /* comment */ + { + /* comment */ + } + )); +} \ No newline at end of file diff --git a/packages/plugin/__test__/fixtures/typescript/ts-class-controller-extension-extended.ts b/packages/plugin/__test__/fixtures/typescript/ts-class-controller-extension-extended.ts index 255946e..5eb9f56 100644 --- a/packages/plugin/__test__/fixtures/typescript/ts-class-controller-extension-extended.ts +++ b/packages/plugin/__test__/fixtures/typescript/ts-class-controller-extension-extended.ts @@ -7,4 +7,6 @@ import Routing from "sap/fe/core/controllerextensions/Routing"; */ export default class MyExtendedController extends Controller { routing = ControllerExtension.use(Routing.override({})); + routing2 = (Routing as any).use(Routing.override({})); // should not even try to handle this + routing3 = Controller.use(Routing.override({})); // should not even try to handle this } \ No newline at end of file diff --git a/packages/plugin/src/classes/helpers/classes.js b/packages/plugin/src/classes/helpers/classes.js index 114d659..ed37e6f 100644 --- a/packages/plugin/src/classes/helpers/classes.js +++ b/packages/plugin/src/classes/helpers/classes.js @@ -190,7 +190,7 @@ export function convertClassToUI5Extend( // 3. restore the import in case it was run already and removed the import const neededImportDeclaration = getImportDeclaration( - memberPath.hub.file.opts.filename, + memberPath?.hub?.file?.opts?.filename, typeName ); if ( @@ -231,14 +231,25 @@ export function convertClassToUI5Extend( callee.property.name === "use" // we are looking for "ControllerExtension.use(...)" ) { const importDeclaration = getImportDeclaration( - memberPath.hub.file.opts.filename, - callee.object.name // usually, but not necessarily always: "ControllerExtension"... + memberPath?.hub?.file?.opts?.filename, + callee?.object?.name // usually, but not necessarily always: "ControllerExtension"... ); // ...hence we rather look at the imported module name to be sure if ( - importDeclaration.source.value === + importDeclaration?.source?.value === "sap/ui/core/mvc/ControllerExtension" ) { + if ( + !member.value.arguments || + member.value.arguments.length !== 1 + ) { + // exactly one argument must be there + throw memberPath.buildCodeFrameError( + `ControllerExtension.use() must be called with exactly one argument but has ${ + member.value.arguments ? member.value.arguments.length : 0 + }` + ); + } member.value = member.value.arguments[0]; extendProps.unshift(buildObjectProperty(member)); // add it to the properties of the extend() config object continue; // prevent the member from also being added to the constructor diff --git a/packages/plugin/src/classes/helpers/imports.js b/packages/plugin/src/classes/helpers/imports.js index a0ce239..55ab1e3 100644 --- a/packages/plugin/src/classes/helpers/imports.js +++ b/packages/plugin/src/classes/helpers/imports.js @@ -11,6 +11,10 @@ export const saveImports = (file) => { // can be called from visitor to access previously present declarations export function getImportDeclaration(filename, typeName) { + if (!filename || !typeName) { + return null; + } + const typeNameParts = typeName.split("."); // find the declaration importing the typeName among the collected import declarations in this file