diff --git a/.gitignore b/.gitignore index f2c855be..20f19194 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,7 @@ jspm_packages # VS Code .vscode + +.env + +npm-shrinkwrap.json diff --git a/README.md b/README.md index f7ae17cc..599404be 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,23 @@ ![UI5 logo](./docs/images/UI5_logo_wide.png) -# ui5-migration -> Tooling to support the migration of UI5 projects by adapting code for new UI5 framework versions. +# Migrate API Calls of sap/ui/core/Core.js with new APIs -[![REUSE status](https://api.reuse.software/badge/github.com/SAP/ui5-migration)](https://api.reuse.software/info/github.com/SAP/ui5-migration) -[![Build Status](https://dev.azure.com/sap/opensource/_apis/build/status/SAP.ui5-migration?branchName=master)](https://dev.azure.com/sap/opensource/_build/latest?definitionId=41&branchName=master) -[![npm version](https://badge.fury.io/js/%40ui5%2Fmigration.svg)](https://www.npmjs.com/package/@ui5/migration) +## Preparation -_**Note:** This project is currently in beta. While there are ongoing improvements and round-offs being applied, we see the early release as a great opportunity to collect feedback from the community to further advance the UI5 migration tooling._ +- Change the value of "OPENUI5_HOME" in ".env" file to the absolute path of the local root folder of openui5 project -The UI5 migration tool is node.js-based and performs source code replacements and optimizations, reducing or getting rid of deprecated API. It builds upon a powerful parsing of JavaScript sources into an AST (abstract syntax tree) in order to perform the actual code replacements. Migration typically consists of an analysis part and a code modification part. +- `npm install` -**IMPORTANT**: The modified source code needs to be manually reviewed and thoroughly tested. There is no 100% guarantee that the modified code works as expected. +- `npm run build` -**For more details on how-to migrate your project's codebase, please consult additional information such as the [migration guide](./docs/guide/migrationguide.md)** +- `npm link` +- Go to your openui5 project folder and run `npm link @ui5/migration` -## Installation +## Execution -### Requirements -- [Node.js](https://nodejs.org/) (**version 14 or higher** ⚠️) - -The migration tool is currently available for early usage. It can be installed with npm. +- Run the command below in your openui5 project to migrate the existing API Calls of sap/ui/core/Core.js ```cli -npm install --global @ui5/migration +ui5-migration migrate src/sap.m/src --task fix-jquery-plugin-imports ``` -## Usage -### CLI - -To verify that the installation worked, run: -```cli -ui5-migration --help -``` - -Execute migration for the current folder: -```cli -ui5-migration migrate -``` - -Please see [command-line interface](./docs/guide/cli.md) for more details. - - -### Available migration tasks -A list of currently available migration tasks can be found [here](./docs/guide/tasks.md) - -### Formatting options -A list of options to configure the formatting of migration output can be found [here](./docs/guide/print.md) - -## Contributing -Please check our [Contribution Guidelines](https://github.com/SAP/ui5-migration/blob/master/CONTRIBUTING.md). Your input and support is welcome! - -## Support -Please follow our [Contribution Guidelines](https://github.com/SAP/ui5-migration/blob/master/CONTRIBUTING.md#report-an-issue) on how to report an issue. diff --git a/defaultConfig/addMissingDependencies.config.json b/defaultConfig/addMissingDependencies.config.json index dda97a28..acfe59d9 100644 --- a/defaultConfig/addMissingDependencies.config.json +++ b/defaultConfig/addMissingDependencies.config.json @@ -1,249 +1,150 @@ { "modules": { - "jQuery Function Extensions": { - "*.cursorPos": { - "newModulePath": "sap/ui/dom/jquery/cursorPos", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"cursorPos\"", - "finder": "FunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - }, - "*.control@1.58.0": { - "newModulePath": "sap/ui/dom/jquery/control", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"control\"", - "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - }, - "*.control@1.106.0": { - "newModulePath": "sap/ui/core/Element", - "newVariableName": "UI5Element", - "replacer": "UI5ElementClosestTo", - "finder": "JQueryControlCallFinder", + "CoreX API Replacements": { + "sap.ui.getCore()": { + "newModulePath": "sap/ui/core/Core", + "newVariableName": "Core", + "replacer": "Module", + "finder": "GlobalGetCoreFinder", "extender": "AddImport", - "version": "^1.106.0" - }, - "*.firstFocusableDomRef": { - "newModulePath": "sap/ui/dom/jquery/Focusable", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"firstFocusableDomRef\"", - "finder": "FunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - }, - "*.lastFocusableDomRef": { - "newModulePath": "sap/ui/dom/jquery/Focusable", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"lastFocusableDomRef\"", - "finder": "FunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - }, - "*.getSelectedText": { - "newModulePath": "sap/ui/dom/jquery/getSelectedText", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"getSelectedText\"", - "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - }, - "*.hasTabIndex": { - "newModulePath": "sap/ui/dom/jquery/hasTabIndex", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"hasTabIndex\"", - "finder": "FunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - }, - "*.parentByAttribute": { - "newModulePath": "sap/ui/dom/jquery/parentByAttribute", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"parentByAttribute\"", - "finder": "FunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - }, - "*.rect": { - "newModulePath": "sap/ui/dom/jquery/rect", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"rect\"", - "finder": "FunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - }, - "*.rectContains": { - "newModulePath": "sap/ui/dom/jquery/rectContains", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"rectContains\"", - "finder": "FunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - }, - "*.scrollLeftRTL": { - "newModulePath": "sap/ui/dom/jquery/scrollLeftRTL", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"scrollLeftRTL\"", - "finder": "FunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", "version": "^1.58.0" }, - "*.scrollRightRTL": { - "newModulePath": "sap/ui/dom/jquery/scrollRightRTL", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"scrollRightRTL\"", - "finder": "FunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", + "core.getLibraryResourceBundle": { + "newModulePath": "sap/ui/core/Lib", + "newVariableName": "Lib", + "replacer": "LibGetResourceBundle", + "finder": "CoreFunctionCallFinder", + "functionToFind": "getLibraryResourceBundle", + "extender": "AddImportAndRemoveUnused", "version": "^1.58.0" }, - "*.disableSelection": { - "newModulePath": "sap/ui/dom/jquery/Selection", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"disableSelection\"", - "finder": "FunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - }, - "*.enableSelection": { - "newModulePath": "sap/ui/dom/jquery/Selection", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"enableSelection\"", - "finder": "FunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - }, - "*.selectText": { - "newModulePath": "sap/ui/dom/jquery/selectText", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"selectText\"", - "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - }, - "*.zIndex": { - "newModulePath": "sap/ui/dom/jquery/zIndex", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"zIndex\"", - "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - }, - "*.addAriaLabelledBy": { - "newModulePath": "sap/ui/dom/jquery/Aria", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"addAriaLabelledBy\"", - "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", + "core.initLibrary": { + "newModulePath": "sap/ui/core/Lib", + "newVariableName": "Lib", + "replacer": "Call", + "functionName": "init", + "finder": "CoreFunctionCallFinder", + "functionToFind": "initLibrary", + "extender": "AddImportAndRemoveUnused", "version": "^1.58.0" }, - "*.removeAriaLabelledBy": { - "newModulePath": "sap/ui/dom/jquery/Aria", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"removeAriaLabelledBy\"", - "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", + "core.attachLocalizationChanged": { + "newModulePath": "sap/base/i18n/Localization", + "newVariableName": "Localization", + "replacer": "Call", + "functionName": "attachChange", + "finder": "CoreFunctionCallFinder", + "functionToFind": "attachLocalizationChanged", + "extender": "AddImportAndRemoveUnused", "version": "^1.58.0" }, - "*.addAriaDescribedBy": { - "newModulePath": "sap/ui/dom/jquery/Aria", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"addAriaDescribedBy\"", - "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", + "core.byId": { + "newModulePath": "sap/ui/core/Element", + "newVariableName": "Element", + "replacer": "ElementRegistryGet", + "finder": "CoreFunctionCallFinder", + "functionToFind": "byId", + "extender": "AddImportAndRemoveUnused", + "version": "^1.58.0" + }, + "core.createRenderManager": { + "newModulePath": "sap/ui/core/RenderManager", + "newVariableName": "RenderManager", + "replacer": "NewRenderManager", + "finder": "CoreFunctionCallFinder", + "functionToFind": "createRenderManager", + "extender": "AddImportAndRemoveUnused" + }, + "core.getStaticAreaRef": { + "newModulePath": "sap/ui/core/StaticArea", + "newVariableName": "StaticArea", + "replacer": "UIAreaGetStaticAreaRef", + "finder": "CoreFunctionCallFinder", + "functionToFind": "getStaticAreaRef", + "extender": "AddImportAndRemoveUnused", + "version": "^1.58.0" + }, + "core.getConfiguration().getFormatLocale": { + "newModulePath": "sap/base/i18n/Formatting", + "newVariableName": "Formatting", + "replacer": "LanguageTagToString", + "finder": "ConfigurationFunctionCallFinder", + "functionToFind": "getFormatLocale", + "extender": "AddImportAndRemoveUnused", + "version": "^1.58.0" + }, + "core.getConfiguration().getTimezone": { + "newModulePath": "sap/base/i18n/Localization", + "newVariableName": "Localization", + "replacer": "Call", + "functionName": "getTimezone", + "finder": "ConfigurationFunctionCallFinder", + "functionToFind": "getTimezone", + "extender": "AddImportAndRemoveUnused", "version": "^1.58.0" }, - "*.removeAriaDescribedBy": { - "newModulePath": "sap/ui/dom/jquery/Aria", - "replacer": "AddComment", - "commentText": " jQuery Plugin \"removeAriaDescribedBy\"", - "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - } - }, - "jQuery Selectors": { - ":sapTabbable": { - "newModulePath": "sap/ui/dom/jquery/Selectors", - "replacer": "AddComment", - "commentText": " jQuery custom selectors \":sapTabbable\"", - "finder": "CallWithArgumentFinderWithDependencyCheck", - "finderIncludesName": ":sapTabbable", - "extender": "AddUnusedImportWithComment", + "core.getConfiguration().getRTL": { + "newModulePath": "sap/base/i18n/Localization", + "newVariableName": "Localization", + "replacer": "Call", + "functionName": "getRTL", + "finder": "ConfigurationFunctionCallFinder", + "functionToFind": "getRTL", + "extender": "AddImportAndRemoveUnused", "version": "^1.58.0" }, - ":focusable": { - "newModulePath": "sap/ui/dom/jquery/Selectors", - "replacer": "AddComment", - "commentText": " jQuery custom selectors \":focusable\"", - "finder": "CallWithArgumentFinderWithDependencyCheck", - "finderIncludesName": ":focusable", - "extender": "AddUnusedImportWithComment", + "core.getConfiguration().getAccessibility": { + "newModulePath": "sap/ui/core/ControlBehavior", + "newVariableName": "ControlBehavior", + "replacer": "Call", + "functionName": "isAccessibilityEnabled", + "finder": "ConfigurationFunctionCallFinder", + "functionToFind": "getAccessibility", + "extender": "AddImportAndRemoveUnused", "version": "^1.58.0" }, - ":sapFocusable": { - "newModulePath": "sap/ui/dom/jquery/Selectors", - "replacer": "AddComment", - "commentText": " jQuery custom selectors \":sapFocusable\"", - "finder": "CallWithArgumentFinderWithDependencyCheck", - "finderIncludesName": ":sapFocusable", - "extender": "AddUnusedImportWithComment", - "version": "^1.58.0" - } - }, - "Replacement interim solution fix": { - "UriParameters with url param (fromQuery search)": { - "newExpressionArgsLength": 1, - "newExpressionArgs": ["window.location.href"], - "newExpressionCalleeName": "UriParameters", - "newVariableName": "UriParameters", - "functionName": "fromQuery", - "newArgs": ["window.location.search"], - "importPath": "sap/base/util/UriParameters", + "core.getConfiguration().getAnimationMode": { + "newModulePath": "sap/ui/core/ControlBehavior", + "newVariableName": "ControlBehavior", "replacer": "Call", - "finder": "NewExpressionFinder", - "extender": "LeaveImport", + "functionName": "getAnimationMode", + "finder": "ConfigurationFunctionCallFinder", + "functionToFind": "getAnimationMode", + "extender": "AddImportAndRemoveUnused", "version": "^1.58.0" }, - "UriParameters with url param (fromQuery href)": { - "newExpressionArgsLength": 1, - "newExpressionArgs": ["window.location.search"], - "newExpressionCalleeName": "UriParameters", - "newVariableName": "UriParameters", - "functionName": "fromQuery", - "newArgs": ["window.location.search"], - "importPath": "sap/base/util/UriParameters", - "replacer": "Call", - "finder": "NewExpressionFinder", - "extender": "LeaveImport", + "core.getConfiguration": { + "newModulePath": "sap/ui/core/Configuration", + "newVariableName": "Configuration", + "replacer": "Module", + "finder": "CoreFunctionCallFinder", + "functionToFind": "getConfiguration", + "extender": "AddImportAndRemoveUnused", "version": "^1.58.0" }, - "UriParameters with url param (fromQuery empty)": { - "newExpressionArgsLength": 0, - "newExpressionCalleeName": "UriParameters", - "newVariableName": "UriParameters", - "functionName": "fromQuery", - "newArgs": ["window.location.search"], - "importPath": "sap/base/util/UriParameters", - "replacer": "Call", - "finder": "NewExpressionFinder", - "extender": "LeaveImport", + "core.getMessageManager": { + "newModulePath": "sap/ui/core/message/MessageManager", + "newVariableName": "MessageManager", + "replacer": "Module", + "finder": "CoreFunctionCallFinder", + "functionToFind": "getMessageManager", + "extender": "AddImportAndRemoveUnused", "version": "^1.58.0" }, - "UriParameters with query param (fromURL)": { - "newExpressionArgsLength": 1, - "newExpressionCalleeName": "UriParameters", - "newVariableName": "UriParameters", - "functionName": "fromURL", - "importPath": "sap/base/util/UriParameters", + "core.byFieldGroupId": { + "newModulePath": "sap/ui/core/Control", + "newVariableName": "Control", "replacer": "Call", - "finder": "UriParametersWithURLFinder", - "extender": "LeaveImport", + "functionName": "getControlsByFieldGroupId", + "finder": "CoreFunctionCallFinder", + "functionToFind": "byFieldGroupId", + "extender": "AddImportAndRemoveUnused", "version": "^1.58.0" } } }, "finders": { + "GlobalGetCoreFinder": "tasks/helpers/finders/GlobalGetCoreFinder.js", "GlobalCoreConfigurationFinder": "tasks/helpers/finders/GlobalCoreConfigurationFinder.js", "FunctionExtensionFinder": "tasks/helpers/finders/FunctionExtensionFinder.js", "FunctionExtensionFinderWithDependencyCheck": "tasks/helpers/finders/FunctionExtensionFinderWithDependencyCheck.js", @@ -253,12 +154,17 @@ "CallWithArgumentFinder": "tasks/helpers/finders/CallWithArgumentFinder.js", "CallWithArgumentFinderWithDependencyCheck": "tasks/helpers/finders/CallWithArgumentFinderWithDependencyCheck.js", "NewExpressionFinder": "tasks/helpers/finders/NewExpressionFinder.js", - "UriParametersWithURLFinder": "tasks/helpers/finders/UriParametersWithURLFinder.js" + "UriParametersWithURLFinder": "tasks/helpers/finders/UriParametersWithURLFinder.js", + "CoreFunctionCallFinder": "tasks/helpers/finders/CoreFunctionCallFinder.js", + "ConfigurationFunctionCallFinder": "tasks/helpers/finders/ConfigurationFunctionCallFinder.js", + "FormatSettingsFunctionCallFinder": "tasks/helpers/finders/FormatSettingsFunctionCallFinder.js" }, "extenders": { + "addImportWithResolvedPath": "tasks/helpers/extenders/addImportWithResolvedPath.js", "AddUnusedImport": "tasks/helpers/extenders/AddUnusedImport.js", "AddUnusedImportWithComment": "tasks/helpers/extenders/AddUnusedImportWithComment.js", "AddImport": "tasks/helpers/extenders/AddImport.js", + "AddImportAndRemoveUnused": "tasks/helpers/extenders/AddImportAndRemoveUnused.js", "LeaveImport": "tasks/helpers/extenders/LeaveImport.js" }, "replacers": { @@ -267,7 +173,16 @@ "NOOP": "tasks/helpers/replacers/NOOP.js", "AddComment": "tasks/helpers/replacers/AddComment.js", "Call": "tasks/helpers/replacers/Call.js", - "UI5ElementClosestTo": "tasks/helpers/replacers/UI5ElementClosestTo.js" + "UI5ElementClosestTo": "tasks/helpers/replacers/UI5ElementClosestTo.js", + "LibGetResourceBundle": "tasks/helpers/replacers/LibGetResourceBundle.js", + "FocusHandlerGetCurrentFocus": "tasks/helpers/replacers/FocusHandlerGetCurrentFocus.js", + "ThemeManagerThemeLoaded": "tasks/helpers/replacers/ThemeManagerThemeLoaded.js", + "ThemeManagerAttachEvent": "tasks/helpers/replacers/ThemeManagerAttachEvent.js", + "ThemeManagerDetachEvent": "tasks/helpers/replacers/ThemeManagerDetachEvent.js", + "NewRenderManager": "tasks/helpers/replacers/NewRenderManager.js", + "ElementRegistryGet": "tasks/helpers/replacers/ElementRegistryGet.js", + "UIAreaGetStaticAreaRef": "tasks/helpers/replacers/UIAreaGetStaticAreaRef.js", + "LanguageTagToString": "tasks/helpers/replacers/LanguageTagToString.js" }, "comments": { "unhandledReplacementComment": "TODO unhandled replacement" diff --git a/defaultConfig/addMissingDependencies.config.json.backup b/defaultConfig/addMissingDependencies.config.json.backup new file mode 100644 index 00000000..7db72d5c --- /dev/null +++ b/defaultConfig/addMissingDependencies.config.json.backup @@ -0,0 +1,359 @@ +{ + "modules": { + "jQuery Function Extensions": { + "*.cursorPos": { + "newModulePath": "sap/ui/dom/jquery/cursorPos", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"cursorPos\"", + "finder": "FunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.control@1.58.0": { + "newModulePath": "sap/ui/dom/jquery/control", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"control\"", + "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.control@1.106.0": { + "newModulePath": "sap/ui/core/Element", + "newVariableName": "UI5Element", + "replacer": "UI5ElementClosestTo", + "finder": "JQueryControlCallFinder", + "extender": "AddImport", + "version": "^1.106.0" + }, + "*.firstFocusableDomRef": { + "newModulePath": "sap/ui/dom/jquery/Focusable", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"firstFocusableDomRef\"", + "finder": "FunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.lastFocusableDomRef": { + "newModulePath": "sap/ui/dom/jquery/Focusable", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"lastFocusableDomRef\"", + "finder": "FunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.getSelectedText": { + "newModulePath": "sap/ui/dom/jquery/getSelectedText", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"getSelectedText\"", + "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.hasTabIndex": { + "newModulePath": "sap/ui/dom/jquery/hasTabIndex", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"hasTabIndex\"", + "finder": "FunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.parentByAttribute": { + "newModulePath": "sap/ui/dom/jquery/parentByAttribute", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"parentByAttribute\"", + "finder": "FunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.rect": { + "newModulePath": "sap/ui/dom/jquery/rect", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"rect\"", + "finder": "FunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.rectContains": { + "newModulePath": "sap/ui/dom/jquery/rectContains", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"rectContains\"", + "finder": "FunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.scrollLeftRTL": { + "newModulePath": "sap/ui/dom/jquery/scrollLeftRTL", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"scrollLeftRTL\"", + "finder": "FunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.scrollRightRTL": { + "newModulePath": "sap/ui/dom/jquery/scrollRightRTL", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"scrollRightRTL\"", + "finder": "FunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.disableSelection": { + "newModulePath": "sap/ui/dom/jquery/Selection", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"disableSelection\"", + "finder": "FunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.enableSelection": { + "newModulePath": "sap/ui/dom/jquery/Selection", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"enableSelection\"", + "finder": "FunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.selectText": { + "newModulePath": "sap/ui/dom/jquery/selectText", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"selectText\"", + "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.zIndex": { + "newModulePath": "sap/ui/dom/jquery/zIndex", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"zIndex\"", + "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.addAriaLabelledBy": { + "newModulePath": "sap/ui/dom/jquery/Aria", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"addAriaLabelledBy\"", + "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.removeAriaLabelledBy": { + "newModulePath": "sap/ui/dom/jquery/Aria", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"removeAriaLabelledBy\"", + "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.addAriaDescribedBy": { + "newModulePath": "sap/ui/dom/jquery/Aria", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"addAriaDescribedBy\"", + "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + "*.removeAriaDescribedBy": { + "newModulePath": "sap/ui/dom/jquery/Aria", + "replacer": "AddComment", + "commentText": " jQuery Plugin \"removeAriaDescribedBy\"", + "finder": "JQueryFunctionExtensionFinderWithDependencyCheck", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + } + }, + "jQuery Selectors": { + ":sapTabbable": { + "newModulePath": "sap/ui/dom/jquery/Selectors", + "replacer": "AddComment", + "commentText": " jQuery custom selectors \":sapTabbable\"", + "finder": "CallWithArgumentFinderWithDependencyCheck", + "finderIncludesName": ":sapTabbable", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + ":focusable": { + "newModulePath": "sap/ui/dom/jquery/Selectors", + "replacer": "AddComment", + "commentText": " jQuery custom selectors \":focusable\"", + "finder": "CallWithArgumentFinderWithDependencyCheck", + "finderIncludesName": ":focusable", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + }, + ":sapFocusable": { + "newModulePath": "sap/ui/dom/jquery/Selectors", + "replacer": "AddComment", + "commentText": " jQuery custom selectors \":sapFocusable\"", + "finder": "CallWithArgumentFinderWithDependencyCheck", + "finderIncludesName": ":sapFocusable", + "extender": "AddUnusedImportWithComment", + "version": "^1.58.0" + } + }, + "CoreX API Replacements": { + "core.getLibraryResourceBundle": { + "newModulePath": "sap/ui/core/Lib", + "newVariableName": "Library", + "replacer": "LibGetResourceBundle", + "finder": "CoreFunctionCallFinder", + "functionName": "getLibraryResourceBundle", + "extender": "AddImport", + "version": "^1.58.0" + }, + "core.getCurrentFocusedControlId": { + "newModulePath": "sap/ui/core/FocusHandler", + "newVariableName": "FocusHandler", + "replacer": "FocusHandlerGetCurrentFocus", + "finder": "CoreFunctionCallFinder", + "functionName": "getCurrentFocusedControlId", + "extender": "AddImport", + "version": "^1.58.0" + }, + "core.isThemeApplied": { + "newModulePath": "sap/ui/core/theming/ThemeManager", + "newVariableName": "ThemeManager", + "replacer": "ThemeManagerThemeLoaded", + "finder": "CoreFunctionCallFinder", + "functionName": "isThemeApplied", + "extender": "AddImport", + "version": "^1.58.0" + }, + "core.attachThemeChanged": { + "newModulePath": "sap/ui/core/theming/ThemeManager", + "newVariableName": "ThemeManager", + "replacer": "ThemeManagerAttachEvent", + "finder": "CoreFunctionCallFinder", + "functionName": "attachThemeChanged", + "extender": "AddImport", + "version": "^1.58.0" + }, + "core.detachThemeChanged": { + "newModulePath": "sap/ui/core/theming/ThemeManager", + "newVariableName": "ThemeManager", + "replacer": "ThemeManagerDetachEvent", + "finder": "CoreFunctionCallFinder", + "functionName": "detachThemeChanged", + "extender": "AddImport", + "version": "^1.58.0" + }, + "core.createRenderManager": { + "newModulePath": "sap/ui/core/RenderManager", + "newVariableName": "RenderManager", + "replacer": "NewRenderManager", + "finder": "CoreFunctionCallFinder", + "functionName": "createRenderManager", + "extender": "AddImport", + "version": "^1.58.0" + }, + "core.byId": { + "newModulePath": "sap/ui/core/Element", + "newVariableName": "UI5Element", + "replacer": "ElementRegistryGet", + "finder": "CoreFunctionCallFinder", + "functionName": "byId", + "extender": "AddImport", + "version": "^1.58.0" + }, + "core.getStaticAreaRef": { + "newModulePath": "sap/ui/core/UIArea", + "newVariableName": "UIArea", + "replacer": "UIAreaGetStaticAreaRef", + "finder": "CoreFunctionCallFinder", + "functionName": "getStaticAreaRef", + "extender": "AddImport", + "version": "^1.58.0" + } + }, + "Replacement interim solution fix": { + "UriParameters with url param (fromQuery search)": { + "newExpressionArgsLength": 1, + "newExpressionArgs": ["window.location.href"], + "newExpressionCalleeName": "UriParameters", + "newVariableName": "UriParameters", + "functionName": "fromQuery", + "newArgs": ["window.location.search"], + "importPath": "sap/base/util/UriParameters", + "replacer": "Call", + "finder": "NewExpressionFinder", + "extender": "LeaveImport", + "version": "^1.58.0" + }, + "UriParameters with url param (fromQuery href)": { + "newExpressionArgsLength": 1, + "newExpressionArgs": ["window.location.search"], + "newExpressionCalleeName": "UriParameters", + "newVariableName": "UriParameters", + "functionName": "fromQuery", + "newArgs": ["window.location.search"], + "importPath": "sap/base/util/UriParameters", + "replacer": "Call", + "finder": "NewExpressionFinder", + "extender": "LeaveImport", + "version": "^1.58.0" + }, + "UriParameters with url param (fromQuery empty)": { + "newExpressionArgsLength": 0, + "newExpressionCalleeName": "UriParameters", + "newVariableName": "UriParameters", + "functionName": "fromQuery", + "newArgs": ["window.location.search"], + "importPath": "sap/base/util/UriParameters", + "replacer": "Call", + "finder": "NewExpressionFinder", + "extender": "LeaveImport", + "version": "^1.58.0" + }, + "UriParameters with query param (fromURL)": { + "newExpressionArgsLength": 1, + "newExpressionCalleeName": "UriParameters", + "newVariableName": "UriParameters", + "functionName": "fromURL", + "importPath": "sap/base/util/UriParameters", + "replacer": "Call", + "finder": "UriParametersWithURLFinder", + "extender": "LeaveImport", + "version": "^1.58.0" + } + } + }, + "finders": { + "GlobalCoreConfigurationFinder": "tasks/helpers/finders/GlobalCoreConfigurationFinder.js", + "FunctionExtensionFinder": "tasks/helpers/finders/FunctionExtensionFinder.js", + "FunctionExtensionFinderWithDependencyCheck": "tasks/helpers/finders/FunctionExtensionFinderWithDependencyCheck.js", + "JQueryControlCallFinder": "tasks/helpers/finders/JQueryControlCallFinder.js", + "JQueryFunctionExtensionFinder": "tasks/helpers/finders/JQueryFunctionExtensionFinder.js", + "JQueryFunctionExtensionFinderWithDependencyCheck": "tasks/helpers/finders/JQueryFunctionExtensionFinderWithDependencyCheck.js", + "CallWithArgumentFinder": "tasks/helpers/finders/CallWithArgumentFinder.js", + "CallWithArgumentFinderWithDependencyCheck": "tasks/helpers/finders/CallWithArgumentFinderWithDependencyCheck.js", + "NewExpressionFinder": "tasks/helpers/finders/NewExpressionFinder.js", + "UriParametersWithURLFinder": "tasks/helpers/finders/UriParametersWithURLFinder.js", + "CoreFunctionCallFinder": "tasks/helpers/finders/CoreFunctionCallFinder.js" + }, + "extenders": { + "AddUnusedImport": "tasks/helpers/extenders/AddUnusedImport.js", + "AddUnusedImportWithComment": "tasks/helpers/extenders/AddUnusedImportWithComment.js", + "AddImport": "tasks/helpers/extenders/AddImport.js", + "LeaveImport": "tasks/helpers/extenders/LeaveImport.js" + }, + "replacers": { + "Module": "tasks/helpers/replacers/Module.js", + "ModuleFunction": "tasks/helpers/replacers/ModuleFunction.js", + "NOOP": "tasks/helpers/replacers/NOOP.js", + "AddComment": "tasks/helpers/replacers/AddComment.js", + "Call": "tasks/helpers/replacers/Call.js", + "UI5ElementClosestTo": "tasks/helpers/replacers/UI5ElementClosestTo.js", + "LibGetResourceBundle": "tasks/helpers/replacers/LibGetResourceBundle.js", + "FocusHandlerGetCurrentFocus": "tasks/helpers/replacers/FocusHandlerGetCurrentFocus.js", + "ThemeManagerThemeLoaded": "tasks/helpers/replacers/ThemeManagerThemeLoaded.js", + "ThemeManagerAttachEvent": "tasks/helpers/replacers/ThemeManagerAttachEvent.js", + "ThemeManagerDetachEvent": "tasks/helpers/replacers/ThemeManagerDetachEvent.js", + "NewRenderManager": "tasks/helpers/replacers/NewRenderManager.js", + "ElementRegistryGet": "tasks/helpers/replacers/ElementRegistryGet.js", + "UIAreaGetStaticAreaRef": "tasks/helpers/replacers/UIAreaGetStaticAreaRef.js" + }, + "comments": { + "unhandledReplacementComment": "TODO unhandled replacement" + }, + "excludes": [] +} \ No newline at end of file diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index c2b59726..462bdeab 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -10,7 +10,8 @@ "license": "Apache-2.0", "dependencies": { "diff": "^5.1.0", - "esprima": "^4.0.1", + "dotenv": "^16.0.3", + "espree": "^9.6.1", "globals": "^13.20.0", "graceful-fs": "^4.2.11", "ignore": "^5.2.4", @@ -549,6 +550,29 @@ "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/@eslint/eslintrc/node_modules/ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -1116,7 +1140,6 @@ "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -1128,7 +1151,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -1806,6 +1828,17 @@ "node": ">=6.0.0" } }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -2155,6 +2188,29 @@ "node": ">=4" } }, + "node_modules/eslint/node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/eslint/node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/eslint/node_modules/ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -2177,26 +2233,41 @@ } }, "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" } }, "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "engines": { - "node": ">=4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -6093,6 +6164,23 @@ "concat-map": "0.0.1" } }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + } + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -6534,14 +6622,12 @@ "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, "requires": {} }, "acorn-walk": { @@ -7027,6 +7113,11 @@ "esutils": "^2.0.2" } }, + "dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==" + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -7157,6 +7248,25 @@ } } }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -7299,21 +7409,24 @@ "dev": true }, "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "dependencies": { + "acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==" + }, "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==" } } }, diff --git a/package.json b/package.json index 12f3e0d1..9c264535 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "coverage": "nyc npm run unit", "coverage-junit": "nyc --reporter=text --reporter=text-summary --reporter=cobertura npm run unit-junit", "unit": "mocha -r ts-node/register -r source-map-support/register ./test/**/*Test.ts ./test/**/*/**Test.ts ./test/*Test.ts", + "unitd": "mocha --inspect-brk -r ts-node/register -r source-map-support/register ./test/**/*Test.ts ./test/**/*/**Test.ts ./test/*Test.ts", "unit-junit": "npm run unit -- --reporter mocha-junit-reporter", "unit-watch": "npm run unit -- -w", "clean": "gts clean", @@ -99,7 +100,8 @@ }, "dependencies": { "diff": "^5.1.0", - "esprima": "^4.0.1", + "dotenv": "^16.0.3", + "espree": "^9.6.1", "globals": "^13.20.0", "graceful-fs": "^4.2.11", "ignore": "^5.2.4", diff --git a/src/Migration.ts b/src/Migration.ts index e1157255..65c4b06a 100644 --- a/src/Migration.ts +++ b/src/Migration.ts @@ -14,3 +14,4 @@ export {ConsoleReporter} from "./reporter/ConsoleReporter"; export {JSONReporter} from "./reporter/JSONReporter"; export {Reporter, ReportLevel} from "./reporter/Reporter"; export {ASTVisitor} from "./util/ASTVisitor"; +export {Syntax} from "esprima"; diff --git a/src/reporter/ConsoleReporter.ts b/src/reporter/ConsoleReporter.ts index 4a119a67..48c8c86a 100644 --- a/src/reporter/ConsoleReporter.ts +++ b/src/reporter/ConsoleReporter.ts @@ -138,7 +138,12 @@ export class ConsoleReporter extends BaseReporter { } else { this.report( level, - "value: " + key + ": entries: " + value.length + "value: " + + key + + ", size: " + + value.length + + ", entries: " + + value.join(", ") ); } }); diff --git a/src/tasks/addMissingDependencies.ts b/src/tasks/addMissingDependencies.ts index cea916ea..628599bc 100644 --- a/src/tasks/addMissingDependencies.ts +++ b/src/tasks/addMissingDependencies.ts @@ -6,7 +6,7 @@ * jQuery.sap.assert(true) * require(["sap/base/assert"], function(assert){assert(true);})" */ -import {Syntax} from "esprima"; +import {Syntax} from "../Migration"; import * as ESTree from "estree"; import * as path from "path"; import {ASTReplaceable} from "ui5-migration"; @@ -24,11 +24,19 @@ import {ASTVisitor, NodePath} from "../util/ASTVisitor"; import * as CommentUtils from "../util/CommentUtils"; import {removeModulesNotMatchingTargetVersion} from "../util/ConfigUtils"; import {SapUiDefineCall} from "../util/SapUiDefineCall"; +import {FileInfo} from "../util/FileInfo"; +import * as dotenv from "dotenv"; + +if (__filename.endsWith(".ts")) { + dotenv.config({path: path.join(__dirname, "../../.env")}); +} else { + dotenv.config({path: path.join(__dirname, "../../../.env")}); +} function getDefineCall( oAst: ESTree.Node, sModuleName: string, - reporter: Reporter + reporter?: Reporter ) { const defineCalls = ASTUtils.findCalls( oAst, @@ -244,6 +252,7 @@ interface ConfigObject { newModulePath?: string; newVariableName?: string; functionName?: string; + modulePath?: string; } interface FoundCall { @@ -290,6 +299,64 @@ function checkFindersInConfig( } } +// map of module name in string to absolute path of itself and its dependencies +const dependenciesMap: Map> = new Map(); +const ui5Home = process.env["OPENUI5_HOME"]; +const corePrefix = "src/sap.ui.core/src"; + +async function getAbsoluteDepPathsOf( + module: string, + reporter: Reporter +): Promise> { + const filePath = path.join(ui5Home, corePrefix, module); + + if (dependenciesMap.has(filePath)) { + return dependenciesMap.get(filePath); + } + + const dependencies = new Set(); + + const queue: string[] = [filePath]; + + while (queue.length) { + let currentPath = queue.shift(); + if (!path.isAbsolute(currentPath)) { + currentPath = path.join(ui5Home, corePrefix, currentPath); + } + + if (!dependencies.has(currentPath)) { + dependencies.add(currentPath); + const file = new FileInfo("", currentPath + ".js", "", ""); + + const ast = await file.loadContent(); + const defineCall = getDefineCall(ast, file.getFileName()); + + if (defineCall && defineCall.dependencyArray) { + defineCall.dependencyArray.elements.forEach(element => { + let moduleName = ( + element as ESTree.Literal + ).value.toString(); + + if (moduleName.startsWith(".")) { + moduleName = path.resolve( + currentPath.substring( + 0, + currentPath.lastIndexOf("/") + ), + moduleName + ); + } + + queue.push(moduleName); + }); + } + } + } + + dependenciesMap.set(filePath, dependencies); + return dependencies; +} + async function analyse(args: Mod.AnalyseArguments): Promise<{} | undefined> { if (!args.config) { throw new Error("No configuration given"); @@ -354,6 +421,41 @@ async function analyse(args: Mod.AnalyseArguments): Promise<{} | undefined> { visitor, args.reporter ); + + if (oAnalysis.replaceCalls.length > 0) { + for (let i = oAnalysis.replaceCalls.length - 1; i >= 0; i--) { + const oReplaceCall = oAnalysis.replaceCalls[i]; + let circularDependency = false; + const sNewModule = oReplaceCall.config.newModulePath; + const oDependencies = await getAbsoluteDepPathsOf( + sNewModule, + args.reporter + ); + + for (const sPath of oDependencies) { + if (sPath.endsWith(args.file.getFileName())) { + circularDependency = true; + break; + } + } + + if (circularDependency) { + // delete this replace call + oAnalysis.replaceCalls.splice(i, 1); + + const defineCalls = ASTUtils.findCalls( + ast, + SapUiDefineCall.isValidRootPath + ); + + oAnalysis.addComments.push({ + nodePath: defineCalls[0], + comment: `${oReplaceCall.configName}: circular dependency to ${sNewModule}`, + }); + } + } + } + args.reporter.collect("replacementsFound", oAnalysis.replaceCalls.length); return oAnalysis; } @@ -421,10 +523,15 @@ async function migrate(args: Mod.MigrateArguments): Promise { // retrieve variable name from existing import and use it as name argument of replace call let variableNameToUse = oReplace.config.newVariableName; if (oReplace.config.newModulePath) { - variableNameToUse = - analyseResult.defineCall.getParamNameByImport( - oReplace.config.newModulePath - ) || variableNameToUse; + const absolutePaths = + analyseResult.defineCall.getAbsoluteDependencyPaths(); + const importIndex = absolutePaths.findIndex(path => + path.endsWith(oReplace.config.newModulePath) + ); + if (importIndex >= 0) { + variableNameToUse = + analyseResult.defineCall.paramNames[importIndex]; + } } mReplacerFuncs[oReplace.importObj.replacerName].replace( oNodePath, @@ -472,6 +579,13 @@ async function migrate(args: Mod.MigrateArguments): Promise { } } + if (analyseResult.defineCall.getNodeOfImport("sap/ui/core/Core")) { + args.reporter.collect( + "moduleStillHasCoreDependency", + args.file.getFileName() + ); + } + // add comments for (const oComment of analyseResult.addComments) { if (CommentUtils.addComment(oComment.nodePath, oComment.comment)) { diff --git a/src/tasks/addRenderers.ts b/src/tasks/addRenderers.ts index 5e98c4ba..adc3252a 100644 --- a/src/tasks/addRenderers.ts +++ b/src/tasks/addRenderers.ts @@ -8,7 +8,7 @@ * ### Add renderer dependency */ -import {Syntax} from "esprima"; +import {Syntax} from "../Migration"; import * as ESTree from "estree"; import * as path from "path"; import * as recast from "recast"; diff --git a/src/tasks/helpers/extenders/AddImportAndRemoveUnused.ts b/src/tasks/helpers/extenders/AddImportAndRemoveUnused.ts new file mode 100644 index 00000000..29354c36 --- /dev/null +++ b/src/tasks/helpers/extenders/AddImportAndRemoveUnused.ts @@ -0,0 +1,103 @@ +import {Extender} from "../../../dependencies"; +import {SapUiDefineCall} from "../../../util/SapUiDefineCall"; +import {ASTVisitor} from "../../../util/ASTVisitor"; +import * as ESTree from "estree"; +import {Syntax} from "../../../Migration"; + +/** + * Adds an import to the define statement + */ +class AddImportAndRemoveUnused implements Extender { + extend( + defineCall: SapUiDefineCall, + config: { + newModulePath: string; + newVariableName: string; + removeModulePath?: string; + } + ): boolean { + const importToRemove = "sap/ui/core/Core"; + + const absoluteImports = defineCall.getAbsoluteDependencyPaths(); + + const coreImportIndex = absoluteImports.findIndex(importString => + importString.endsWith(importToRemove) + ); + + let dependencyRemoved: boolean; + + if (coreImportIndex >= 0) { + const paramToRemove = defineCall.paramNames[coreImportIndex]; + + const variableNames = new Set(); + const visitor = new ASTVisitor(); + let bGlobalGetCoreFound = false; + + visitor.visit(defineCall.factory.body, { + visitIdentifier(identifierPath) { + const oParentPath = identifierPath.parentPath; + + if ( + oParentPath.value.type !== "LabeledStatement" && + (oParentPath.value.type !== "Property" || + (oParentPath.value as ESTree.Property).key === + identifierPath.value) && + (oParentPath.value.type !== "MemberExpression" || + (oParentPath.value as ESTree.MemberExpression) + .object === identifierPath.value) + ) { + variableNames.add( + (identifierPath.value as ESTree.Identifier).name + ); + } + this.traverse(identifierPath); + }, + visitCallExpression(callPath) { + const oCall = callPath.value; + + if ( + oCall.callee.type === Syntax.MemberExpression && + oCall.callee.property.type === Syntax.Identifier && + oCall.callee.property.name === "getCore" && + oCall.callee.object.type === Syntax.MemberExpression && + oCall.callee.object.property.type === + Syntax.Identifier && + oCall.callee.object.property.name === "ui" && + oCall.callee.object.object.type === Syntax.Identifier && + oCall.callee.object.object.name === "sap" + ) { + bGlobalGetCoreFound = true; + } else { + this.traverse(callPath); + } + }, + }); + + if (!bGlobalGetCoreFound && !variableNames.has(paramToRemove)) { + dependencyRemoved = defineCall.removeDependency( + ( + defineCall.dependencyArray.elements[ + coreImportIndex + ] as ESTree.Literal + ).value as string, + paramToRemove + ); + } + } + + const moduleExists = absoluteImports.some(path => + path.endsWith(config.newModulePath) + ); + + if (moduleExists) { + return dependencyRemoved; + } else { + return defineCall.addDependency( + config.newModulePath, + config.newVariableName + ); + } + } +} + +module.exports = new AddImportAndRemoveUnused(); diff --git a/src/tasks/helpers/extenders/AddImportWithResolvedPath.ts b/src/tasks/helpers/extenders/AddImportWithResolvedPath.ts new file mode 100644 index 00000000..79ae7a0e --- /dev/null +++ b/src/tasks/helpers/extenders/AddImportWithResolvedPath.ts @@ -0,0 +1,30 @@ +import {Extender} from "../../../dependencies"; +import {SapUiDefineCall} from "../../../util/SapUiDefineCall"; + +/** + * Adds an import to the define statement + */ +class AddImportWithResolvedPath implements Extender { + extend( + defineCall: SapUiDefineCall, + config: { + newModulePath: string; + newVariableName: string; + } + ): boolean { + const bExists = defineCall + .getAbsoluteDependencyPaths() + .some(path => path.endsWith(config.newModulePath)); + + if (!bExists) { + return defineCall.addDependency( + config.newModulePath, + config.newVariableName + ); + } else { + return false; + } + } +} + +module.exports = new AddImportWithResolvedPath(); diff --git a/src/tasks/helpers/finders/AssignReplacementFinder.ts b/src/tasks/helpers/finders/AssignReplacementFinder.ts index 5a05fe9a..1ef86e46 100644 --- a/src/tasks/helpers/finders/AssignReplacementFinder.ts +++ b/src/tasks/helpers/finders/AssignReplacementFinder.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; diff --git a/src/tasks/helpers/finders/CallWithArgumentFinder.ts b/src/tasks/helpers/finders/CallWithArgumentFinder.ts index ad7735fc..65c11e74 100644 --- a/src/tasks/helpers/finders/CallWithArgumentFinder.ts +++ b/src/tasks/helpers/finders/CallWithArgumentFinder.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; diff --git a/src/tasks/helpers/finders/ConfigurationFunctionCallFinder.ts b/src/tasks/helpers/finders/ConfigurationFunctionCallFinder.ts new file mode 100644 index 00000000..5a788cca --- /dev/null +++ b/src/tasks/helpers/finders/ConfigurationFunctionCallFinder.ts @@ -0,0 +1,36 @@ +import * as ESTree from "estree"; + +import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; +import {SapUiDefineCall} from "../../../util/SapUiDefineCall"; +import isFunctionCallOnConfiguration from "./utils/isFunctionCallOnConfigurationInstance"; + +class ConfigurationFunctionCallFinder implements Finder { + /** + * Finds expression that matches one of the following conditions + *
    + *
  • sap.ui.getCore().FUNCTION_NAME()
  • + *
  • Core.FUNCTION_NAME()
  • + *
  • oCore.FUNCTION_NAME()
  • + *
+ */ + find( + node: ESTree.Node, + config: {functionToFind: string}, + sConfigName: string, + defineCall: SapUiDefineCall + ): FinderResult { + if (!config.functionToFind) { + throw new Error( + "ConfigurationFunctionCallFinder needs config 'functionToFind'" + ); + } + + if (isFunctionCallOnConfiguration(node, config.functionToFind)) { + return {configName: sConfigName}; + } else { + return EMPTY_FINDER_RESULT; + } + } +} + +module.exports = new ConfigurationFunctionCallFinder(); diff --git a/src/tasks/helpers/finders/CoreFunctionCallFinder.ts b/src/tasks/helpers/finders/CoreFunctionCallFinder.ts new file mode 100644 index 00000000..ac0ed7a7 --- /dev/null +++ b/src/tasks/helpers/finders/CoreFunctionCallFinder.ts @@ -0,0 +1,36 @@ +import * as ESTree from "estree"; + +import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; +import {SapUiDefineCall} from "../../../util/SapUiDefineCall"; +import isFunctionCallOnCore from "./utils/isFunctionCallOnCoreInstance"; + +class CoreFunctionCallFinder implements Finder { + /** + * Finds expression that matches one of the following conditions + *
    + *
  • sap.ui.getCore().FUNCTION_NAME()
  • + *
  • Core.FUNCTION_NAME()
  • + *
  • oCore.FUNCTION_NAME()
  • + *
+ */ + find( + node: ESTree.Node, + config: {functionToFind: string}, + sConfigName: string, + defineCall: SapUiDefineCall + ): FinderResult { + if (!config.functionToFind) { + throw new Error( + "CoreFunctionCallFinder needs config 'functionToFind'" + ); + } + + if (isFunctionCallOnCore(node, config.functionToFind)) { + return {configName: sConfigName}; + } else { + return EMPTY_FINDER_RESULT; + } + } +} + +module.exports = new CoreFunctionCallFinder(); diff --git a/src/tasks/helpers/finders/FormatSettingsFunctionCallFinder.ts b/src/tasks/helpers/finders/FormatSettingsFunctionCallFinder.ts new file mode 100644 index 00000000..698cce00 --- /dev/null +++ b/src/tasks/helpers/finders/FormatSettingsFunctionCallFinder.ts @@ -0,0 +1,28 @@ +import * as ESTree from "estree"; + +import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; +import {SapUiDefineCall} from "../../../util/SapUiDefineCall"; +import isFunctionCallOnFormatSettings from "./utils/isFunctionCallOnFormatSettingsInstance"; + +class ConfigurationFunctionCallFinder implements Finder { + find( + node: ESTree.Node, + config: {functionToFind: string}, + sConfigName: string, + defineCall: SapUiDefineCall + ): FinderResult { + if (!config.functionToFind) { + throw new Error( + "FormatSettingsFunctionCallFinder needs config 'functionToFind'" + ); + } + + if (isFunctionCallOnFormatSettings(node, config.functionToFind)) { + return {configName: sConfigName}; + } else { + return EMPTY_FINDER_RESULT; + } + } +} + +module.exports = new ConfigurationFunctionCallFinder(); diff --git a/src/tasks/helpers/finders/FunctionExtensionFinder.ts b/src/tasks/helpers/finders/FunctionExtensionFinder.ts index e31e9ff2..de17acac 100644 --- a/src/tasks/helpers/finders/FunctionExtensionFinder.ts +++ b/src/tasks/helpers/finders/FunctionExtensionFinder.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; diff --git a/src/tasks/helpers/finders/GlobalCoreConfigurationFinder.ts b/src/tasks/helpers/finders/GlobalCoreConfigurationFinder.ts index 20b0c439..d981c1c2 100644 --- a/src/tasks/helpers/finders/GlobalCoreConfigurationFinder.ts +++ b/src/tasks/helpers/finders/GlobalCoreConfigurationFinder.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; diff --git a/src/tasks/helpers/finders/GlobalGetCoreFinder.ts b/src/tasks/helpers/finders/GlobalGetCoreFinder.ts new file mode 100644 index 00000000..a86c4417 --- /dev/null +++ b/src/tasks/helpers/finders/GlobalGetCoreFinder.ts @@ -0,0 +1,44 @@ +import {Syntax} from "../../../Migration"; +import * as ESTree from "estree"; + +import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; +import {SapUiDefineCall} from "../../../util/SapUiDefineCall"; + +const getPropertyValue = (node: ESTree.Node) => { + if (node.type === Syntax.Identifier) { + return node.name; + } + return ""; +}; + +class GlobalGetCoreFinder implements Finder { + /** + * Finds expression that matches one of the following conditions + *
    + *
  • sap.ui.getCore()
  • + *
+ */ + find( + node: ESTree.Node, + config: {}, + sConfigName: string, + defineCall: SapUiDefineCall + ): FinderResult { + const bGetCoreCall = + node.type === Syntax.CallExpression && + node.arguments.length === 0 && + node.callee.type === Syntax.MemberExpression && + getPropertyValue(node.callee.property) === "getCore" && + node.callee.object.type === Syntax.MemberExpression && + getPropertyValue(node.callee.object.property) === "ui" && + getPropertyValue(node.callee.object.object) === "sap"; + + if (bGetCoreCall) { + return {configName: sConfigName}; + } else { + return EMPTY_FINDER_RESULT; + } + } +} + +module.exports = new GlobalGetCoreFinder(); diff --git a/src/tasks/helpers/finders/JQueryControlCallFinder.ts b/src/tasks/helpers/finders/JQueryControlCallFinder.ts index 080dd1b2..af305a51 100644 --- a/src/tasks/helpers/finders/JQueryControlCallFinder.ts +++ b/src/tasks/helpers/finders/JQueryControlCallFinder.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; diff --git a/src/tasks/helpers/finders/JQueryDOMVariableNameFinder.ts b/src/tasks/helpers/finders/JQueryDOMVariableNameFinder.ts index ee6ad199..72806bc7 100644 --- a/src/tasks/helpers/finders/JQueryDOMVariableNameFinder.ts +++ b/src/tasks/helpers/finders/JQueryDOMVariableNameFinder.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; diff --git a/src/tasks/helpers/finders/JQueryEventExtensionFinder.ts b/src/tasks/helpers/finders/JQueryEventExtensionFinder.ts index 101bf11c..4851ce05 100644 --- a/src/tasks/helpers/finders/JQueryEventExtensionFinder.ts +++ b/src/tasks/helpers/finders/JQueryEventExtensionFinder.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; diff --git a/src/tasks/helpers/finders/JQueryFunctionExtensionFinder.ts b/src/tasks/helpers/finders/JQueryFunctionExtensionFinder.ts index 2c5ddf39..313bfb91 100644 --- a/src/tasks/helpers/finders/JQueryFunctionExtensionFinder.ts +++ b/src/tasks/helpers/finders/JQueryFunctionExtensionFinder.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; diff --git a/src/tasks/helpers/finders/JQuerySapCallFinder.ts b/src/tasks/helpers/finders/JQuerySapCallFinder.ts index 5a6562f0..348296ed 100644 --- a/src/tasks/helpers/finders/JQuerySapCallFinder.ts +++ b/src/tasks/helpers/finders/JQuerySapCallFinder.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; diff --git a/src/tasks/helpers/finders/JQuerySapExtendFinder.ts b/src/tasks/helpers/finders/JQuerySapExtendFinder.ts index f1a6e981..d014dc0c 100644 --- a/src/tasks/helpers/finders/JQuerySapExtendFinder.ts +++ b/src/tasks/helpers/finders/JQuerySapExtendFinder.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; diff --git a/src/tasks/helpers/finders/JQuerySapFunctionFinder.ts b/src/tasks/helpers/finders/JQuerySapFunctionFinder.ts index 6b5fa5f8..4ad80a37 100644 --- a/src/tasks/helpers/finders/JQuerySapFunctionFinder.ts +++ b/src/tasks/helpers/finders/JQuerySapFunctionFinder.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; diff --git a/src/tasks/helpers/finders/NewExpressionFinder.ts b/src/tasks/helpers/finders/NewExpressionFinder.ts index acfaae86..be5ddcb3 100644 --- a/src/tasks/helpers/finders/NewExpressionFinder.ts +++ b/src/tasks/helpers/finders/NewExpressionFinder.ts @@ -1,9 +1,10 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {EMPTY_FINDER_RESULT, Finder, FinderResult} from "../../../dependencies"; import {SapUiDefineCall} from "../../../util/SapUiDefineCall"; +import {parse} from "../../../util/ParseUtils"; /** * Finds new expressions if the number of arguments match and the callee name. @@ -84,7 +85,7 @@ class NewExpressionFinder implements Finder { } function evaluateExpressions(parameter) { - const expressionStatement = recast.parse(parameter).program.body[ + const expressionStatement = parse(parameter).program.body[ "0" ] as ESTree.ExpressionStatement; return expressionStatement.expression; diff --git a/src/tasks/helpers/finders/UriParametersWithURLFinder.ts b/src/tasks/helpers/finders/UriParametersWithURLFinder.ts index 364aac33..8841ef98 100644 --- a/src/tasks/helpers/finders/UriParametersWithURLFinder.ts +++ b/src/tasks/helpers/finders/UriParametersWithURLFinder.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; diff --git a/src/tasks/helpers/finders/utils/isFunctionCallOnConfigurationInstance.ts b/src/tasks/helpers/finders/utils/isFunctionCallOnConfigurationInstance.ts new file mode 100644 index 00000000..00754dc0 --- /dev/null +++ b/src/tasks/helpers/finders/utils/isFunctionCallOnConfigurationInstance.ts @@ -0,0 +1,40 @@ +import {Syntax} from "../../../../Migration"; +import * as ESTree from "estree"; +import isFunctionCallOnCore from "./isFunctionCallOnCoreInstance"; + +const getPropertyValue = (node: ESTree.Node) => { + if (node.type === Syntax.Identifier) { + return node.name; + } + return ""; +}; + +const isNamedFunctionCall = (node: ESTree.Node, name: string) => { + return ( + node.type === Syntax.CallExpression && + node.callee.type === Syntax.MemberExpression && + getPropertyValue(node.callee.property) === name + ); +}; + +/** + * check whether the node is a function call on a core instance and the function name should be identical to + * the given functionName + * + * For example: + * sap.ui.getCore().getConfiguration().getXXX() + * oCore.getConfiguration().getXXX() + * oConfiguration.getXXX(); + * Configuration.getXXX(); + */ + +export default function (node: ESTree.Node, functionName: string): boolean { + return ( + node.type === Syntax.CallExpression && + isNamedFunctionCall(node, functionName) && + node.callee.type === Syntax.MemberExpression && + ((node.callee.object.type === Syntax.Identifier && + node.callee.object.name.toLowerCase().includes("configuration")) || + isFunctionCallOnCore(node.callee.object, "getConfiguration")) + ); +} diff --git a/src/tasks/helpers/finders/utils/isFunctionCallOnCoreInstance.ts b/src/tasks/helpers/finders/utils/isFunctionCallOnCoreInstance.ts new file mode 100644 index 00000000..e2c6fcd5 --- /dev/null +++ b/src/tasks/helpers/finders/utils/isFunctionCallOnCoreInstance.ts @@ -0,0 +1,45 @@ +import {Syntax} from "../../../../Migration"; +import * as ESTree from "estree"; + +const getPropertyValue = (node: ESTree.Node) => { + if (node.type === Syntax.Identifier) { + return node.name; + } + return ""; +}; + +const isNamedFunctionCall = (node: ESTree.Node, name: string) => { + return ( + node.type === Syntax.CallExpression && + node.callee.type === Syntax.MemberExpression && + getPropertyValue(node.callee.property) === name + ); +}; + +/** + * check whether the node is a function call on a core instance and the function name should be identical to + * the given functionName + * + * For example: + * sap.ui.getCore().functionCall() + * oCore.functionCall() + */ + +export default function (node: ESTree.Node, functionName: string): boolean { + return ( + node.type === Syntax.CallExpression && + isNamedFunctionCall(node, functionName) && + node.callee.type === Syntax.MemberExpression && + ((node.callee.object.type === Syntax.Identifier && + node.callee.object.name.toLowerCase().includes("core")) || + (node.callee.object.type === Syntax.CallExpression && + isNamedFunctionCall(node.callee.object, "getCore") && + node.callee.object.callee.type === Syntax.MemberExpression && + node.callee.object.callee.object.type === + Syntax.MemberExpression && + getPropertyValue(node.callee.object.callee.object.property) === + "ui" && + getPropertyValue(node.callee.object.callee.object.object) === + "sap")) + ); +} diff --git a/src/tasks/helpers/finders/utils/isFunctionCallOnFormatSettingsInstance.ts b/src/tasks/helpers/finders/utils/isFunctionCallOnFormatSettingsInstance.ts new file mode 100644 index 00000000..0c79960a --- /dev/null +++ b/src/tasks/helpers/finders/utils/isFunctionCallOnFormatSettingsInstance.ts @@ -0,0 +1,38 @@ +import {Syntax} from "../../../../Migration"; +import * as ESTree from "estree"; +import isFunctionCallOnConfiguration from "./isFunctionCallOnConfigurationInstance"; + +const getPropertyValue = (node: ESTree.Node) => { + if (node.type === Syntax.Identifier) { + return node.name; + } + return ""; +}; + +const isNamedFunctionCall = (node: ESTree.Node, name: string) => { + return ( + node.type === Syntax.CallExpression && + node.callee.type === Syntax.MemberExpression && + getPropertyValue(node.callee.property) === name + ); +}; + +/** + * check whether the node is a function call on a core instance and the function name should be identical to + * the given functionName + * + * For example: + * sap.ui.getCore().getConfiguration().getXXX() + * oCore.getConfiguration().getXXX() + * oConfiguration.getXXX(); + * Configuration.getXXX(); + */ + +export default function (node: ESTree.Node, functionName: string): boolean { + return ( + node.type === Syntax.CallExpression && + isNamedFunctionCall(node, functionName) && + node.callee.type === Syntax.MemberExpression && + isFunctionCallOnConfiguration(node.callee.object, "getFormatSettings") + ); +} diff --git a/src/tasks/helpers/replacers/Call.ts b/src/tasks/helpers/replacers/Call.ts index e974f2b1..fa8e8f6e 100644 --- a/src/tasks/helpers/replacers/Call.ts +++ b/src/tasks/helpers/replacers/Call.ts @@ -1,9 +1,10 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; const builders = recast.types.builders; +import {parse} from "../../../util/ParseUtils"; /** * Creates a call expression as replacement @@ -85,12 +86,21 @@ const replaceable: ASTReplaceable = { case Syntax.ReturnStatement: // return MyModule.myField oInsertionPoint[node.name] = oNewCall; break; - case Syntax.ExpressionStatement: // MyModule.myFunction() + case Syntax.ExpressionStatement: + oInsertionPoint[node.name] = oNewCall; + break; + case Syntax.IfStatement: + oInsertionPoint[node.name] = oNewCall; + break; + case Syntax.ConditionalExpression: + oInsertionPoint[node.name] = oNewCall; + break; + case Syntax.Property: oInsertionPoint[node.name] = oNewCall; break; default: throw new Error( - "Module: insertion is of an unsupported type " + + "Replacer Call: insertion is of an unsupported type " + oInsertionPoint.type ); } @@ -98,7 +108,7 @@ const replaceable: ASTReplaceable = { }; function evaluateExpressions(parameter) { - const expressionStatement = recast.parse(parameter).program.body[ + const expressionStatement = parse(parameter).program.body[ "0" ] as ESTree.ExpressionStatement; return expressionStatement.expression; diff --git a/src/tasks/helpers/replacers/DelayedCall.ts b/src/tasks/helpers/replacers/DelayedCall.ts index 6563960a..02251806 100644 --- a/src/tasks/helpers/replacers/DelayedCall.ts +++ b/src/tasks/helpers/replacers/DelayedCall.ts @@ -1,9 +1,10 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; import {ASTVisitor} from "../../../util/ASTVisitor"; +import {parse} from "../../../util/ParseUtils"; const builders = recast.types.builders; @@ -74,7 +75,7 @@ const replaceable: ASTReplaceable = { "(function(){\n" + " setTimeout(fnMethod.bind(oObject), 0);\n" + "})"; - const oAst = recast.parse(sText); + const oAst = parse(sText); const oNodeSetTimeout = getInnerExpression(oAst.program); oNodeSetTimeout.arguments[1] = aArgs[0]; // iDelay @@ -134,7 +135,7 @@ const replaceable: ASTReplaceable = { " setTimeout(oObject[fnMethod].bind(oObject), 0);\n" + "})"; - const oAst = recast.parse(sText); + const oAst = parse(sText); const oNodeSetTimeout = getInnerExpression(oAst.program); // iDelay -> args 0 @@ -181,7 +182,7 @@ const replaceable: ASTReplaceable = { " }.bind(oObject), 0);\n" + "})"; - const oAst = recast.parse(sText); + const oAst = parse(sText); const oNodeSetTimeout = getInnerExpression(oAst.program); const oInnerCallExpression = oNodeSetTimeout.arguments[ "0" diff --git a/src/tasks/helpers/replacers/ElementRegistryGet.ts b/src/tasks/helpers/replacers/ElementRegistryGet.ts new file mode 100644 index 00000000..ca3235da --- /dev/null +++ b/src/tasks/helpers/replacers/ElementRegistryGet.ts @@ -0,0 +1,107 @@ +import {Syntax} from "../../../Migration"; +import * as ESTree from "estree"; +import * as recast from "recast"; +import {ASTReplaceable, NodePath} from "ui5-migration"; + +const builders = recast.types.builders; + +/** + * Replace + * - sap.ui.getCore().byId(ID) + * - oCore.byId(ID) + * + * With + * Element.registry.get(ID) + * + * + * @param {recast.NodePath} node The top node of the module reference + * @param {string} name The name of the new module + * @param {string} fnName The name of the function inside the new module + * @param {string} oldModuleCall The old import name + * @returns {void} + */ +const replaceable: ASTReplaceable = { + replace( + node: NodePath, + name: string, + fnName: string, + oldModuleCall: string, + config: {newVariableName: string} //config object + ): void { + const oObjectIdent: ESTree.Identifier = builders.identifier( + name || config.newVariableName + ); + + const oInsertionPoint = node.parentPath.value; + + const oCallExpression = node.value as ESTree.CallExpression; + + const aArgs = oCallExpression.arguments.slice(); + + const oNodeModule: ESTree.Expression = builders.callExpression( + builders.memberExpression( + builders.memberExpression( + oObjectIdent, + builders.identifier("registry") + ), + builders.identifier("get") + ), + aArgs + ); + + // arrays do not have a type + if (Array.isArray(oInsertionPoint)) { + oInsertionPoint[node.name] = oNodeModule; + return; + } + + switch (oInsertionPoint.type) { + case Syntax.CallExpression: // MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.NewExpression: // new MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.MemberExpression: // MyModule.myField + oInsertionPoint.object = oNodeModule; + break; + case Syntax.LogicalExpression: // value1 && MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.UnaryExpression: // !MyModule.myField + oInsertionPoint.argument = oNodeModule; + break; + case Syntax.VariableDeclarator: // var test = MyModule.myField + oInsertionPoint.init = oNodeModule; + break; + case Syntax.AssignmentExpression: // test = MyModule.myField + oInsertionPoint.right = oNodeModule; + break; + case Syntax.BinaryExpression: // var1 + MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ReturnStatement: // return MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ExpressionStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.IfStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ConditionalExpression: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.Property: + oInsertionPoint[node.name] = oNodeModule; + break; + default: + throw new Error( + "Module: insertion is of an unsupported type " + + oInsertionPoint.type + ); + } + }, +}; + +module.exports = replaceable; diff --git a/src/tasks/helpers/replacers/FocusHandlerGetCurrentFocus.ts b/src/tasks/helpers/replacers/FocusHandlerGetCurrentFocus.ts new file mode 100644 index 00000000..e065cd54 --- /dev/null +++ b/src/tasks/helpers/replacers/FocusHandlerGetCurrentFocus.ts @@ -0,0 +1,100 @@ +import {Syntax} from "../../../Migration"; +import * as ESTree from "estree"; +import * as recast from "recast"; +import {ASTReplaceable, NodePath} from "ui5-migration"; + +const builders = recast.types.builders; + +/** + * Replace + * - sap.ui.getCore().getCurrentFocusedControlId() + * - oCore.getCurrentFocusedControlId() + * + * With + * FocusHandler.getCurrentFocusedControlId() + * + * + * @param {recast.NodePath} node The top node of the module reference + * @param {string} name The name of the new module + * @param {string} fnName The name of the function inside the new module + * @param {string} oldModuleCall The old import name + * @returns {void} + */ +const replaceable: ASTReplaceable = { + replace( + node: NodePath, + name: string, + fnName: string, + oldModuleCall: string, + config: {newVariableName: string} //config object + ): void { + const oFocusHandlerIdent: ESTree.Identifier = builders.identifier( + name || config.newVariableName + ); + + const oInsertionPoint = node.parentPath.value; + + const oNodeModule: ESTree.Expression = builders.callExpression( + builders.memberExpression( + oFocusHandlerIdent, + builders.identifier("getCurrentFocusedControlId") + ), + [] + ); + + // arrays do not have a type + if (Array.isArray(oInsertionPoint)) { + oInsertionPoint[node.name] = oNodeModule; + return; + } + + switch (oInsertionPoint.type) { + case Syntax.CallExpression: // MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.NewExpression: // new MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.MemberExpression: // MyModule.myField + oInsertionPoint.object = oNodeModule; + break; + case Syntax.LogicalExpression: // value1 && MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.UnaryExpression: // !MyModule.myField + oInsertionPoint.argument = oNodeModule; + break; + case Syntax.VariableDeclarator: // var test = MyModule.myField + oInsertionPoint.init = oNodeModule; + break; + case Syntax.AssignmentExpression: // test = MyModule.myField + oInsertionPoint.right = oNodeModule; + break; + case Syntax.BinaryExpression: // var1 + MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ReturnStatement: // return MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ExpressionStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.IfStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ConditionalExpression: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.Property: + oInsertionPoint[node.name] = oNodeModule; + break; + default: + throw new Error( + "Module: insertion is of an unsupported type " + + oInsertionPoint.type + ); + } + }, +}; + +module.exports = replaceable; diff --git a/src/tasks/helpers/replacers/GenNOOP.ts b/src/tasks/helpers/replacers/GenNOOP.ts index 4d249d91..a201e584 100644 --- a/src/tasks/helpers/replacers/GenNOOP.ts +++ b/src/tasks/helpers/replacers/GenNOOP.ts @@ -1,6 +1,6 @@ -import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; import * as ESTree from "estree"; +import {parse} from "../../../util/ParseUtils"; /** * Generates a noop function @@ -19,7 +19,7 @@ const replaceable: ASTReplaceable = { oldModuleCall: string ): void { const sText = "(function() {})"; - const expressionStatement = recast.parse(sText).program.body[ + const expressionStatement = parse(sText).program.body[ "0" ] as ESTree.ExpressionStatement; diff --git a/src/tasks/helpers/replacers/GetObject.ts b/src/tasks/helpers/replacers/GetObject.ts index 70cd6c3f..96a632f2 100644 --- a/src/tasks/helpers/replacers/GetObject.ts +++ b/src/tasks/helpers/replacers/GetObject.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/Getter.ts b/src/tasks/helpers/replacers/Getter.ts index b7ac76bb..c05914ce 100644 --- a/src/tasks/helpers/replacers/Getter.ts +++ b/src/tasks/helpers/replacers/Getter.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/IntervalCall.ts b/src/tasks/helpers/replacers/IntervalCall.ts index cf83a247..309e17d5 100644 --- a/src/tasks/helpers/replacers/IntervalCall.ts +++ b/src/tasks/helpers/replacers/IntervalCall.ts @@ -1,9 +1,10 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; import * as ESTree from "estree"; import {ASTVisitor} from "../../../util/ASTVisitor"; +import {parse} from "../../../util/ParseUtils"; const builders = recast.types.builders; @@ -75,7 +76,7 @@ const replaceable: ASTReplaceable = { "(function(){\n" + " setInterval(fnMethod.bind(oObject), 0);\n" + "})"; - const oAst = recast.parse(sText); + const oAst = parse(sText); const oFunctionExpression = ( oAst.program.body["0"] as ESTree.ExpressionStatement @@ -142,7 +143,7 @@ const replaceable: ASTReplaceable = { " setInterval(oObject[fnMethod].bind(oObject), 0);\n" + "})"; - const oAst = recast.parse(sText); + const oAst = parse(sText); const oFunctionExpression = ( oAst.program.body["0"] as ESTree.ExpressionStatement ).expression as ESTree.FunctionExpression; @@ -196,7 +197,7 @@ const replaceable: ASTReplaceable = { " }.bind(oObject), 0);\n" + "})"; - const oAst = recast.parse(sText); + const oAst = parse(sText); const oIntervalExpressionStatement = oAst.program.body[ "0" ] as ESTree.ExpressionStatement; diff --git a/src/tasks/helpers/replacers/LanguageTagToString.ts b/src/tasks/helpers/replacers/LanguageTagToString.ts new file mode 100644 index 00000000..f45501d3 --- /dev/null +++ b/src/tasks/helpers/replacers/LanguageTagToString.ts @@ -0,0 +1,97 @@ +import {Syntax} from "../../../Migration"; +import * as recast from "recast"; +import {ASTReplaceable, NodePath} from "ui5-migration"; + +const builders = recast.types.builders; + +/** + * Creates a call expression as replacement + * + * Formatting.getLanguageTag().toString() + * + * @param {recast.NodePath} node The top node of the module reference + * @param {string} name The name of the new module + * @param {string} fnName The name of the function inside the new module + * @param {string} oldModuleCall The old import name + * @returns {void} + */ +const replaceable: ASTReplaceable = { + replace( + node: NodePath, + name: string, + fnName: string, + oldModuleCall: string, + config: {} + ): void { + const oInsertionPoint = node.parentPath.value; + const oNewCall = builders.callExpression( + builders.memberExpression( + builders.callExpression( + builders.memberExpression( + builders.identifier(name), + builders.identifier("getLanguageTag"), + false + ), + [] + ), + builders.identifier("toString"), + false + ), + [] + ); + + if (Array.isArray(oInsertionPoint)) { + oInsertionPoint[node.name] = oNewCall; + return; + } + + switch (oInsertionPoint.type) { + case Syntax.CallExpression: // MyModule.myFunction() + oInsertionPoint.callee = oNewCall; + break; + case Syntax.NewExpression: // new MyModule.myFunction() + oInsertionPoint.callee = oNewCall; + break; + case Syntax.MemberExpression: // MyModule.myField + oInsertionPoint.object = oNewCall; + break; + case Syntax.LogicalExpression: // value1 && MyModule.myField + oInsertionPoint[node.name] = oNewCall; + break; + case Syntax.UnaryExpression: // !MyModule.myField + oInsertionPoint.argument = oNewCall; + break; + case Syntax.VariableDeclarator: // var test = MyModule.myField + oInsertionPoint.init = oNewCall; + break; + case Syntax.AssignmentExpression: // test = MyModule.myField + oInsertionPoint.right = oNewCall; + break; + case Syntax.BinaryExpression: // var1 + MyModule.myField + oInsertionPoint[node.name] = oNewCall; + break; + case Syntax.ReturnStatement: // return MyModule.myField + oInsertionPoint[node.name] = oNewCall; + break; + case Syntax.ExpressionStatement: + oInsertionPoint[node.name] = oNewCall; + break; + case Syntax.IfStatement: + oInsertionPoint[node.name] = oNewCall; + break; + case Syntax.ConditionalExpression: + oInsertionPoint[node.name] = oNewCall; + break; + case Syntax.Property: + oInsertionPoint[node.name] = oNewCall; + break; + default: + throw new Error( + "Replacer Call: insertion is of an unsupported type " + + oInsertionPoint.type + ); + } + }, +}; + +module.exports = replaceable; diff --git a/src/tasks/helpers/replacers/LibGetResourceBundle.ts b/src/tasks/helpers/replacers/LibGetResourceBundle.ts new file mode 100644 index 00000000..ffe3d1a8 --- /dev/null +++ b/src/tasks/helpers/replacers/LibGetResourceBundle.ts @@ -0,0 +1,112 @@ +import {Syntax} from "../../../Migration"; +import * as ESTree from "estree"; +import * as recast from "recast"; +import {ASTReplaceable, NodePath} from "ui5-migration"; + +const builders = recast.types.builders; + +/** + * Replace + * - sap.ui.getCore().getLibraryResourceBundle(LIBRARY_NAME) + * - oCore.getLibraryResourceBundle(LIBRARY_NAME) + * + * With + * Library.get(LIBRARY_NAME || "sap.ui.core").getResourceBundle() + * + * + * @param {recast.NodePath} node The top node of the module reference + * @param {string} name The name of the new module + * @param {string} fnName The name of the function inside the new module + * @param {string} oldModuleCall The old import name + * @returns {void} + */ +const replaceable: ASTReplaceable = { + replace( + node: NodePath, + name: string, + fnName: string, + oldModuleCall: string, + config: {newVariableName: string} //config object + ): void { + const libraryIdent: ESTree.Identifier = builders.identifier( + name || config.newVariableName + ); + + const oInsertionPoint = node.parentPath.value; + + const oCallExpression = node.value as ESTree.CallExpression; + let oArg: ESTree.Literal | ESTree.Identifier; + + if (oCallExpression.arguments.length > 0) { + oArg = + oCallExpression.arguments[0].type === Syntax.Literal + ? (oCallExpression.arguments[0] as ESTree.Literal) + : (oCallExpression.arguments[0] as ESTree.Identifier); + } else { + oArg = builders.literal("sap.ui.core"); + } + + const oNodeModule: ESTree.Expression = builders.callExpression( + builders.memberExpression( + libraryIdent, + builders.identifier("getResourceBundleFor") + ), + [oArg] + ); + + // arrays do not have a type + if (Array.isArray(oInsertionPoint)) { + oInsertionPoint[node.name] = oNodeModule; + return; + } + + switch (oInsertionPoint.type) { + case Syntax.CallExpression: // MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.NewExpression: // new MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.MemberExpression: // MyModule.myField + oInsertionPoint.object = oNodeModule; + break; + case Syntax.LogicalExpression: // value1 && MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.UnaryExpression: // !MyModule.myField + oInsertionPoint.argument = oNodeModule; + break; + case Syntax.VariableDeclarator: // var test = MyModule.myField + oInsertionPoint.init = oNodeModule; + break; + case Syntax.AssignmentExpression: // test = MyModule.myField + oInsertionPoint.right = oNodeModule; + break; + case Syntax.BinaryExpression: // var1 + MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ReturnStatement: // return MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ExpressionStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.IfStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ConditionalExpression: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.Property: + oInsertionPoint[node.name] = oNodeModule; + break; + default: + throw new Error( + "Module: insertion is of an unsupported type " + + oInsertionPoint.type + ); + } + }, +}; + +module.exports = replaceable; diff --git a/src/tasks/helpers/replacers/Module.ts b/src/tasks/helpers/replacers/Module.ts index 5da7529a..480744b7 100644 --- a/src/tasks/helpers/replacers/Module.ts +++ b/src/tasks/helpers/replacers/Module.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; @@ -67,6 +67,18 @@ const replaceable: ASTReplaceable = { case Syntax.ReturnStatement: // return MyModule.myField oInsertionPoint[node.name] = oNodeModule; break; + case Syntax.ExpressionStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.IfStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ConditionalExpression: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.Property: + oInsertionPoint[node.name] = oNodeModule; + break; default: throw new Error( "Module: insertion is of an unsupported type " + diff --git a/src/tasks/helpers/replacers/ModuleFunction.ts b/src/tasks/helpers/replacers/ModuleFunction.ts index 002f23ed..8ac128bf 100644 --- a/src/tasks/helpers/replacers/ModuleFunction.ts +++ b/src/tasks/helpers/replacers/ModuleFunction.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as recast from "recast"; import {ASTReplaceable, ASTReplaceableResult, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/ModuleFunctionPadding.ts b/src/tasks/helpers/replacers/ModuleFunctionPadding.ts index fd1ea8e3..1866f397 100644 --- a/src/tasks/helpers/replacers/ModuleFunctionPadding.ts +++ b/src/tasks/helpers/replacers/ModuleFunctionPadding.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/ModuleFunctionWithObjectProperty.ts b/src/tasks/helpers/replacers/ModuleFunctionWithObjectProperty.ts index 1ac11b19..45212e90 100644 --- a/src/tasks/helpers/replacers/ModuleFunctionWithObjectProperty.ts +++ b/src/tasks/helpers/replacers/ModuleFunctionWithObjectProperty.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/ModuleFunctionWithObjectPropertyComparison.ts b/src/tasks/helpers/replacers/ModuleFunctionWithObjectPropertyComparison.ts index 74f4bcdd..4825097b 100644 --- a/src/tasks/helpers/replacers/ModuleFunctionWithObjectPropertyComparison.ts +++ b/src/tasks/helpers/replacers/ModuleFunctionWithObjectPropertyComparison.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/ModuleSystem.ts b/src/tasks/helpers/replacers/ModuleSystem.ts index 4a27d751..13194cc2 100644 --- a/src/tasks/helpers/replacers/ModuleSystem.ts +++ b/src/tasks/helpers/replacers/ModuleSystem.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/ModuleWithInvocation.ts b/src/tasks/helpers/replacers/ModuleWithInvocation.ts index f0068034..044835cf 100644 --- a/src/tasks/helpers/replacers/ModuleWithInvocation.ts +++ b/src/tasks/helpers/replacers/ModuleWithInvocation.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/NativeFunction.ts b/src/tasks/helpers/replacers/NativeFunction.ts index e83ca4f4..f1bd738b 100644 --- a/src/tasks/helpers/replacers/NativeFunction.ts +++ b/src/tasks/helpers/replacers/NativeFunction.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/NativeFunctionWithArgumentCheck.ts b/src/tasks/helpers/replacers/NativeFunctionWithArgumentCheck.ts index 7e517df8..417e1a50 100644 --- a/src/tasks/helpers/replacers/NativeFunctionWithArgumentCheck.ts +++ b/src/tasks/helpers/replacers/NativeFunctionWithArgumentCheck.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/NativeInstanceFunction.ts b/src/tasks/helpers/replacers/NativeInstanceFunction.ts index 4260cd3a..b2aa1393 100644 --- a/src/tasks/helpers/replacers/NativeInstanceFunction.ts +++ b/src/tasks/helpers/replacers/NativeInstanceFunction.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; diff --git a/src/tasks/helpers/replacers/NativeObject.ts b/src/tasks/helpers/replacers/NativeObject.ts index c9f921fd..ffb52e43 100644 --- a/src/tasks/helpers/replacers/NativeObject.ts +++ b/src/tasks/helpers/replacers/NativeObject.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/NativeStringFunction.ts b/src/tasks/helpers/replacers/NativeStringFunction.ts index 3c80a748..4300570c 100644 --- a/src/tasks/helpers/replacers/NativeStringFunction.ts +++ b/src/tasks/helpers/replacers/NativeStringFunction.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/NewInstance.ts b/src/tasks/helpers/replacers/NewInstance.ts index b13250e8..395fa800 100644 --- a/src/tasks/helpers/replacers/NewInstance.ts +++ b/src/tasks/helpers/replacers/NewInstance.ts @@ -1,7 +1,8 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; import * as ESTree from "estree"; +import {parse} from "../../../util/ParseUtils"; const builders = recast.types.builders; @@ -31,7 +32,7 @@ const replaceable: ASTReplaceable = { let args = oInsertion.arguments; if (fnName) { const oAst = ( - recast.parse(fnName).program.body[ + parse(fnName).program.body[ "0" ] as ESTree.ExpressionStatement ).expression; diff --git a/src/tasks/helpers/replacers/NewInstanceNoArgs.ts b/src/tasks/helpers/replacers/NewInstanceNoArgs.ts index 76c5fbd8..a5b1ce6e 100644 --- a/src/tasks/helpers/replacers/NewInstanceNoArgs.ts +++ b/src/tasks/helpers/replacers/NewInstanceNoArgs.ts @@ -1,7 +1,8 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; import * as ESTree from "estree"; +import {parse} from "../../../util/ParseUtils"; const builders = recast.types.builders; @@ -32,7 +33,7 @@ const replaceable: ASTReplaceable = { if (oldArgs.length === 0) { let args = []; if (fnName) { - const oAst = recast.parse(fnName).program.body[ + const oAst = parse(fnName).program.body[ "0" ] as ESTree.ExpressionStatement; args = [oAst]; diff --git a/src/tasks/helpers/replacers/NewRenderManager.ts b/src/tasks/helpers/replacers/NewRenderManager.ts new file mode 100644 index 00000000..a12bfe5a --- /dev/null +++ b/src/tasks/helpers/replacers/NewRenderManager.ts @@ -0,0 +1,94 @@ +import {Syntax} from "../../../Migration"; +import * as ESTree from "estree"; +import * as recast from "recast"; +import {ASTReplaceable, NodePath} from "ui5-migration"; + +const builders = recast.types.builders; + +/** + * Replace + * - sap.ui.getCore().createRenderManager() + * - oCore.createRenderManager() + * + * With + * new RenderManager() + * + * + * @param {recast.NodePath} node The top node of the module reference + * @param {string} name The name of the new module + * @param {string} fnName The name of the function inside the new module + * @param {string} oldModuleCall The old import name + * @returns {void} + */ +const replaceable: ASTReplaceable = { + replace( + node: NodePath, + name: string, + fnName: string, + oldModuleCall: string, + config: {newVariableName: string} //config object + ): void { + const identName = name || config.newVariableName; + const oInsertionPoint = node.parentPath.value; + + const oNodeModule: ESTree.Expression = builders.newExpression( + builders.identifier(identName), + [] + ); + + // arrays do not have a type + if (Array.isArray(oInsertionPoint)) { + oInsertionPoint[node.name] = oNodeModule; + return; + } + + switch (oInsertionPoint.type) { + case Syntax.CallExpression: // MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.NewExpression: // new MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.MemberExpression: // MyModule.myField + oInsertionPoint.object = oNodeModule; + break; + case Syntax.LogicalExpression: // value1 && MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.UnaryExpression: // !MyModule.myField + oInsertionPoint.argument = oNodeModule; + break; + case Syntax.VariableDeclarator: // var test = MyModule.myField + oInsertionPoint.init = oNodeModule; + break; + case Syntax.AssignmentExpression: // test = MyModule.myField + oInsertionPoint.right = oNodeModule; + break; + case Syntax.BinaryExpression: // var1 + MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ReturnStatement: // return MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ExpressionStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.IfStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ConditionalExpression: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.Property: + oInsertionPoint[node.name] = oNodeModule; + break; + default: + throw new Error( + "Module: insertion is of an unsupported type " + + oInsertionPoint.type + ); + } + }, +}; + +module.exports = replaceable; diff --git a/src/tasks/helpers/replacers/RemoveUrlWhitelist.ts b/src/tasks/helpers/replacers/RemoveUrlWhitelist.ts index e9b94996..246258dd 100644 --- a/src/tasks/helpers/replacers/RemoveUrlWhitelist.ts +++ b/src/tasks/helpers/replacers/RemoveUrlWhitelist.ts @@ -1,9 +1,9 @@ -import {Syntax} from "esprima"; -import * as recast from "recast"; +import {Syntax} from "../../../Migration"; import {ASTReplaceable, NodePath} from "ui5-migration"; import * as ESTree from "estree"; import * as CommentUtils from "../../../util/CommentUtils"; +import {parse} from "../../../util/ParseUtils"; /** * From: @@ -37,7 +37,7 @@ const replaceable: ASTReplaceable = { "(function () {\n" + " URLWhitelist.delete(URLWhitelist.entries()[iIndexToReplace]);\n" + "})"; - const oAst = recast.parse(sText); + const oAst = parse(sText); const oBody = oAst.program.body[ "0" ] as ESTree.ExpressionStatement; diff --git a/src/tasks/helpers/replacers/RetinaSupport.ts b/src/tasks/helpers/replacers/RetinaSupport.ts index 9d4138aa..9b2a8b49 100644 --- a/src/tasks/helpers/replacers/RetinaSupport.ts +++ b/src/tasks/helpers/replacers/RetinaSupport.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/SetObject.ts b/src/tasks/helpers/replacers/SetObject.ts index 0b2aa3ba..751a327a 100644 --- a/src/tasks/helpers/replacers/SetObject.ts +++ b/src/tasks/helpers/replacers/SetObject.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/ThemeManagerAttachEvent.ts b/src/tasks/helpers/replacers/ThemeManagerAttachEvent.ts new file mode 100644 index 00000000..0f08f607 --- /dev/null +++ b/src/tasks/helpers/replacers/ThemeManagerAttachEvent.ts @@ -0,0 +1,104 @@ +import {Syntax} from "../../../Migration"; +import * as ESTree from "estree"; +import * as recast from "recast"; +import {ASTReplaceable, NodePath} from "ui5-migration"; + +const builders = recast.types.builders; + +/** + * Replace + * - sap.ui.getCore().attachThemeChanged(...) + * - oCore.attachThemeChanged(...) + * + * With + * sap/ui/core/Theming.attachApplied(...) + * + * + * @param {recast.NodePath} node The top node of the module reference + * @param {string} name The name of the new module + * @param {string} fnName The name of the function inside the new module + * @param {string} oldModuleCall The old import name + * @returns {void} + */ +const replaceable: ASTReplaceable = { + replace( + node: NodePath, + name: string, + fnName: string, + oldModuleCall: string, + config: {newVariableName: string} //config object + ): void { + const oObjectIdent: ESTree.Identifier = builders.identifier( + name || config.newVariableName + ); + + const oInsertionPoint = node.parentPath.value; + + const oCallExpression = node.value as ESTree.CallExpression; + + const aArgs = oCallExpression.arguments.slice(); + + const oNodeModule: ESTree.Expression = builders.callExpression( + builders.memberExpression( + oObjectIdent, + builders.identifier("attachApplied") + ), + aArgs + ); + + // arrays do not have a type + if (Array.isArray(oInsertionPoint)) { + oInsertionPoint[node.name] = oNodeModule; + return; + } + + switch (oInsertionPoint.type) { + case Syntax.CallExpression: // MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.NewExpression: // new MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.MemberExpression: // MyModule.myField + oInsertionPoint.object = oNodeModule; + break; + case Syntax.LogicalExpression: // value1 && MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.UnaryExpression: // !MyModule.myField + oInsertionPoint.argument = oNodeModule; + break; + case Syntax.VariableDeclarator: // var test = MyModule.myField + oInsertionPoint.init = oNodeModule; + break; + case Syntax.AssignmentExpression: // test = MyModule.myField + oInsertionPoint.right = oNodeModule; + break; + case Syntax.BinaryExpression: // var1 + MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ReturnStatement: // return MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ExpressionStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.IfStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ConditionalExpression: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.Property: + oInsertionPoint[node.name] = oNodeModule; + break; + default: + throw new Error( + "Module: insertion is of an unsupported type " + + oInsertionPoint.type + ); + } + }, +}; + +module.exports = replaceable; diff --git a/src/tasks/helpers/replacers/ThemeManagerDetachEvent.ts b/src/tasks/helpers/replacers/ThemeManagerDetachEvent.ts new file mode 100644 index 00000000..29b4d6af --- /dev/null +++ b/src/tasks/helpers/replacers/ThemeManagerDetachEvent.ts @@ -0,0 +1,104 @@ +import {Syntax} from "../../../Migration"; +import * as ESTree from "estree"; +import * as recast from "recast"; +import {ASTReplaceable, NodePath} from "ui5-migration"; + +const builders = recast.types.builders; + +/** + * Replace + * - sap.ui.getCore().detachThemeChanged(...) + * - oCore.detachThemeChanged(...) + * + * With + * Theming.detachApplied(...) + * + * + * @param {recast.NodePath} node The top node of the module reference + * @param {string} name The name of the new module + * @param {string} fnName The name of the function inside the new module + * @param {string} oldModuleCall The old import name + * @returns {void} + */ +const replaceable: ASTReplaceable = { + replace( + node: NodePath, + name: string, + fnName: string, + oldModuleCall: string, + config: {newVariableName: string} //config object + ): void { + const oObjectIdent: ESTree.Identifier = builders.identifier( + name || config.newVariableName + ); + + const oInsertionPoint = node.parentPath.value; + + const oCallExpression = node.value as ESTree.CallExpression; + + const aArgs = oCallExpression.arguments.slice(); + + const oNodeModule: ESTree.Expression = builders.callExpression( + builders.memberExpression( + oObjectIdent, + builders.identifier("detachApplied") + ), + aArgs + ); + + // arrays do not have a type + if (Array.isArray(oInsertionPoint)) { + oInsertionPoint[node.name] = oNodeModule; + return; + } + + switch (oInsertionPoint.type) { + case Syntax.CallExpression: // MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.NewExpression: // new MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.MemberExpression: // MyModule.myField + oInsertionPoint.object = oNodeModule; + break; + case Syntax.LogicalExpression: // value1 && MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.UnaryExpression: // !MyModule.myField + oInsertionPoint.argument = oNodeModule; + break; + case Syntax.VariableDeclarator: // var test = MyModule.myField + oInsertionPoint.init = oNodeModule; + break; + case Syntax.AssignmentExpression: // test = MyModule.myField + oInsertionPoint.right = oNodeModule; + break; + case Syntax.BinaryExpression: // var1 + MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ReturnStatement: // return MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ExpressionStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.IfStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ConditionalExpression: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.Property: + oInsertionPoint[node.name] = oNodeModule; + break; + default: + throw new Error( + "Module: insertion is of an unsupported type " + + oInsertionPoint.type + ); + } + }, +}; + +module.exports = replaceable; diff --git a/src/tasks/helpers/replacers/ThemeManagerThemeLoaded.ts b/src/tasks/helpers/replacers/ThemeManagerThemeLoaded.ts new file mode 100644 index 00000000..f694c537 --- /dev/null +++ b/src/tasks/helpers/replacers/ThemeManagerThemeLoaded.ts @@ -0,0 +1,100 @@ +import {Syntax} from "../../../Migration"; +import * as ESTree from "estree"; +import * as recast from "recast"; +import {ASTReplaceable, NodePath} from "ui5-migration"; + +const builders = recast.types.builders; + +/** + * Replace + * - sap.ui.getCore().isThemeApplied() + * - oCore.isThemeApplied() + * + * With + * ThemeManager.themeLoaded + * + * + * @param {recast.NodePath} node The top node of the module reference + * @param {string} name The name of the new module + * @param {string} fnName The name of the function inside the new module + * @param {string} oldModuleCall The old import name + * @returns {void} + */ +const replaceable: ASTReplaceable = { + replace( + node: NodePath, + name: string, + fnName: string, + oldModuleCall: string, + config: {newVariableName: string} //config object + ): void { + const oThemeManagerIdent: ESTree.Identifier = builders.identifier( + name || config.newVariableName + ); + + const oInsertionPoint = node.parentPath.value; + + const oNodeModule: ESTree.Expression = builders.callExpression( + builders.memberExpression( + oThemeManagerIdent, + builders.identifier("isApplied") + ), + [] + ); + + // arrays do not have a type + if (Array.isArray(oInsertionPoint)) { + oInsertionPoint[node.name] = oNodeModule; + return; + } + + switch (oInsertionPoint.type) { + case Syntax.CallExpression: // MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.NewExpression: // new MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.MemberExpression: // MyModule.myField + oInsertionPoint.object = oNodeModule; + break; + case Syntax.LogicalExpression: // value1 && MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.UnaryExpression: // !MyModule.myField + oInsertionPoint.argument = oNodeModule; + break; + case Syntax.VariableDeclarator: // var test = MyModule.myField + oInsertionPoint.init = oNodeModule; + break; + case Syntax.AssignmentExpression: // test = MyModule.myField + oInsertionPoint.right = oNodeModule; + break; + case Syntax.BinaryExpression: // var1 + MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ReturnStatement: // return MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ExpressionStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.IfStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ConditionalExpression: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.Property: + oInsertionPoint[node.name] = oNodeModule; + break; + default: + throw new Error( + "Module: insertion is of an unsupported type " + + oInsertionPoint.type + ); + } + }, +}; + +module.exports = replaceable; diff --git a/src/tasks/helpers/replacers/UI5ElementClosestTo.ts b/src/tasks/helpers/replacers/UI5ElementClosestTo.ts index 8ae7d95f..d0b84d43 100644 --- a/src/tasks/helpers/replacers/UI5ElementClosestTo.ts +++ b/src/tasks/helpers/replacers/UI5ElementClosestTo.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/UIAreaGetStaticAreaRef.ts b/src/tasks/helpers/replacers/UIAreaGetStaticAreaRef.ts new file mode 100644 index 00000000..ed4cfa28 --- /dev/null +++ b/src/tasks/helpers/replacers/UIAreaGetStaticAreaRef.ts @@ -0,0 +1,100 @@ +import {Syntax} from "../../../Migration"; +import * as ESTree from "estree"; +import * as recast from "recast"; +import {ASTReplaceable, NodePath} from "ui5-migration"; + +const builders = recast.types.builders; + +/** + * Replace + * - sap.ui.getCore().getStaticAreaRef() + * - oCore.getStaticAreaRef() + * + * With + * UIArea.getStaticAreaRef() + * + * + * @param {recast.NodePath} node The top node of the module reference + * @param {string} name The name of the new module + * @param {string} fnName The name of the function inside the new module + * @param {string} oldModuleCall The old import name + * @returns {void} + */ +const replaceable: ASTReplaceable = { + replace( + node: NodePath, + name: string, + fnName: string, + oldModuleCall: string, + config: {newVariableName: string} //config object + ): void { + const oObjectIdent: ESTree.Identifier = builders.identifier( + name || config.newVariableName + ); + + const oInsertionPoint = node.parentPath.value; + + const oNodeModule: ESTree.Expression = builders.callExpression( + builders.memberExpression( + oObjectIdent, + builders.identifier("getDomRef") + ), + [] + ); + + // arrays do not have a type + if (Array.isArray(oInsertionPoint)) { + oInsertionPoint[node.name] = oNodeModule; + return; + } + + switch (oInsertionPoint.type) { + case Syntax.CallExpression: // MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.NewExpression: // new MyModule.myFunction() + oInsertionPoint.callee = oNodeModule; + break; + case Syntax.MemberExpression: // MyModule.myField + oInsertionPoint.object = oNodeModule; + break; + case Syntax.LogicalExpression: // value1 && MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.UnaryExpression: // !MyModule.myField + oInsertionPoint.argument = oNodeModule; + break; + case Syntax.VariableDeclarator: // var test = MyModule.myField + oInsertionPoint.init = oNodeModule; + break; + case Syntax.AssignmentExpression: // test = MyModule.myField + oInsertionPoint.right = oNodeModule; + break; + case Syntax.BinaryExpression: // var1 + MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ReturnStatement: // return MyModule.myField + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ExpressionStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.IfStatement: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.ConditionalExpression: + oInsertionPoint[node.name] = oNodeModule; + break; + case Syntax.Property: + oInsertionPoint[node.name] = oNodeModule; + break; + default: + throw new Error( + "Module: insertion is of an unsupported type " + + oInsertionPoint.type + ); + } + }, +}; + +module.exports = replaceable; diff --git a/src/tasks/helpers/replacers/UriParameters.ts b/src/tasks/helpers/replacers/UriParameters.ts index 67c86318..4771331e 100644 --- a/src/tasks/helpers/replacers/UriParameters.ts +++ b/src/tasks/helpers/replacers/UriParameters.ts @@ -1,7 +1,8 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; +import {parse} from "../../../util/ParseUtils"; const builders = recast.types.builders; @@ -73,7 +74,7 @@ const replaceable: ASTReplaceable = { oNodeModule = fromURL; if (config.functionParameter) { const args: ESTree.Expression = ( - recast.parse(config.functionParameter).program.body[ + parse(config.functionParameter).program.body[ "0" ] as ESTree.ExpressionStatement ).expression; diff --git a/src/tasks/helpers/replacers/VariableNameReplacer.ts b/src/tasks/helpers/replacers/VariableNameReplacer.ts index dbbf51c8..085466f6 100644 --- a/src/tasks/helpers/replacers/VariableNameReplacer.ts +++ b/src/tasks/helpers/replacers/VariableNameReplacer.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import {ASTReplaceable, NodePath} from "ui5-migration"; /** diff --git a/src/tasks/helpers/replacers/domById.ts b/src/tasks/helpers/replacers/domById.ts index 99773928..20c26f91 100644 --- a/src/tasks/helpers/replacers/domById.ts +++ b/src/tasks/helpers/replacers/domById.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/domFocus.ts b/src/tasks/helpers/replacers/domFocus.ts index 6360008f..ebd6ccb6 100644 --- a/src/tasks/helpers/replacers/domFocus.ts +++ b/src/tasks/helpers/replacers/domFocus.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/inArray.ts b/src/tasks/helpers/replacers/inArray.ts index b26944ab..67655ae6 100644 --- a/src/tasks/helpers/replacers/inArray.ts +++ b/src/tasks/helpers/replacers/inArray.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/instanceOf.ts b/src/tasks/helpers/replacers/instanceOf.ts index ec351ce0..ababaef5 100644 --- a/src/tasks/helpers/replacers/instanceOf.ts +++ b/src/tasks/helpers/replacers/instanceOf.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/isMouseEventDelayed.ts b/src/tasks/helpers/replacers/isMouseEventDelayed.ts index 665ddd06..12649a6b 100644 --- a/src/tasks/helpers/replacers/isMouseEventDelayed.ts +++ b/src/tasks/helpers/replacers/isMouseEventDelayed.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/jQueryContains.ts b/src/tasks/helpers/replacers/jQueryContains.ts index 390976d1..eeade81f 100644 --- a/src/tasks/helpers/replacers/jQueryContains.ts +++ b/src/tasks/helpers/replacers/jQueryContains.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, ASTReplaceableResult, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/jQueryExtend.ts b/src/tasks/helpers/replacers/jQueryExtend.ts index c6be5883..67883c4c 100644 --- a/src/tasks/helpers/replacers/jQueryExtend.ts +++ b/src/tasks/helpers/replacers/jQueryExtend.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, ASTReplaceableResult, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/jQueryTrim.ts b/src/tasks/helpers/replacers/jQueryTrim.ts index f6cfd4fa..1e6f6daf 100644 --- a/src/tasks/helpers/replacers/jQueryTrim.ts +++ b/src/tasks/helpers/replacers/jQueryTrim.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, ASTReplaceableResult, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/jqueryDomById.ts b/src/tasks/helpers/replacers/jqueryDomById.ts index cc2f51db..ebe13528 100644 --- a/src/tasks/helpers/replacers/jqueryDomById.ts +++ b/src/tasks/helpers/replacers/jqueryDomById.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/mergeOrObjectAssign.ts b/src/tasks/helpers/replacers/mergeOrObjectAssign.ts index 40e337bf..ef41f985 100644 --- a/src/tasks/helpers/replacers/mergeOrObjectAssign.ts +++ b/src/tasks/helpers/replacers/mergeOrObjectAssign.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as recast from "recast"; import {ASTReplaceable, ASTReplaceableResult, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/resourceModulePaths.ts b/src/tasks/helpers/replacers/resourceModulePaths.ts index df98674e..a5095f21 100644 --- a/src/tasks/helpers/replacers/resourceModulePaths.ts +++ b/src/tasks/helpers/replacers/resourceModulePaths.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/helpers/replacers/startsOrEndsWithIgnoreCase.ts b/src/tasks/helpers/replacers/startsOrEndsWithIgnoreCase.ts index 8aa4fbde..9cc8c394 100644 --- a/src/tasks/helpers/replacers/startsOrEndsWithIgnoreCase.ts +++ b/src/tasks/helpers/replacers/startsOrEndsWithIgnoreCase.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../../../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; import {ASTReplaceable, NodePath} from "ui5-migration"; diff --git a/src/tasks/replaceGlobals.ts b/src/tasks/replaceGlobals.ts index fca8d5bb..c52f12e7 100644 --- a/src/tasks/replaceGlobals.ts +++ b/src/tasks/replaceGlobals.ts @@ -37,7 +37,7 @@ * anymore e.g. such as jQuery.sap.each, jQuery.sap.forIn,... * */ -import {Syntax} from "esprima"; +import {Syntax} from "../Migration"; import * as ESTree from "estree"; import * as path from "path"; import {ASTReplaceable} from "ui5-migration"; diff --git a/src/util/ASTUtils.ts b/src/util/ASTUtils.ts index 3aeb290a..1b9180d8 100644 --- a/src/util/ASTUtils.ts +++ b/src/util/ASTUtils.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../Migration"; import * as ESTree from "estree"; import {ASTVisitor, TNodePath} from "./ASTVisitor"; diff --git a/src/util/AmdCleanerUtil.ts b/src/util/AmdCleanerUtil.ts index 22005d17..8cd7113f 100644 --- a/src/util/AmdCleanerUtil.ts +++ b/src/util/AmdCleanerUtil.ts @@ -1,5 +1,6 @@ "use strict"; +import {Syntax} from "../Migration"; import {ConsoleReporter, Reporter, ReportLevel} from "../Migration"; import {SapUiDefineCall} from "./SapUiDefineCall"; import * as ASTUtils from "./ASTUtils"; @@ -12,7 +13,6 @@ import * as ModuleNameComparator from "./ModuleNameComparator"; import * as VariableNameCreator from "./VariableNameCreator"; const recast = require("recast"); -const Syntax = require("esprima").Syntax; const builders = recast.types.builders; @@ -1443,7 +1443,7 @@ module.exports = { globalNameConvertedToAMDExport = mainClassName; bModified = true; } else if ( - expression.type === Syntax.AssigmnentExpression && + expression.type === Syntax.AssignmentExpression && mainClassName && mainClassName === that.getObjectName( diff --git a/src/util/CommentUtils.ts b/src/util/CommentUtils.ts index 39a43012..d3a790a0 100644 --- a/src/util/CommentUtils.ts +++ b/src/util/CommentUtils.ts @@ -1,4 +1,4 @@ -import {Syntax} from "esprima"; +import {Syntax} from "../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; diff --git a/src/util/FileInfo.ts b/src/util/FileInfo.ts index af181ae9..696d034b 100644 --- a/src/util/FileInfo.ts +++ b/src/util/FileInfo.ts @@ -8,6 +8,7 @@ import {Reporter, ReportLevel} from "../Migration"; import {AnalyzeCharacter, CodeStyleAnalyzer} from "./CodeStyleAnalyzer"; import * as FileUtils from "./FileUtils"; import * as DiffOptimizer from "./whitespace/DiffOptimizer"; +import {parse} from "./ParseUtils"; // TODO rename to FileAccess @@ -62,7 +63,7 @@ export class FileInfo implements Mod.FileInfo { this.sFullPath, "utf8" ); - this.oAST = recast.parse(this.sSourceCode).program; + this.oAST = parse(this.sSourceCode).program; } return this.oAST; } diff --git a/src/util/NamespaceUtils.ts b/src/util/NamespaceUtils.ts index c1bf0519..4e9788f7 100644 --- a/src/util/NamespaceUtils.ts +++ b/src/util/NamespaceUtils.ts @@ -1,6 +1,6 @@ const recast = require("recast"); -const Syntax = require("esprima").Syntax; const builders = recast.types.builders; +import {Syntax} from "../Migration"; import * as ESTree from "estree"; import {SapUiDefineCall} from "./SapUiDefineCall"; diff --git a/src/util/ParseUtils.ts b/src/util/ParseUtils.ts new file mode 100644 index 00000000..d4bfda09 --- /dev/null +++ b/src/util/ParseUtils.ts @@ -0,0 +1,43 @@ +import {parse} from "espree"; +import * as recast from "recast"; + +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); + +/* + * NOTE: After updating the ecmaVersion: + * - Adopt JSModuleAnalyzer to handle new Syntax / VisitorKeys. + * - Adjust the JSModuleAnalyzer test "Check for consistency between VisitorKeys and EnrichedVisitorKeys" + * (See comments in test for details) + */ +export const ecmaVersion = 2022; + +export function parse(code: string, userOptions = {}): recast.File { + const options = { + comment: true, + ecmaVersion, + range: false, + sourceType: "script", + loc: true, + // if this is set to false, recast uses esprima to tokenize + tokens: true, + }; + + for (const [name, value] of Object.entries(userOptions)) { + if (!hasOwn(options, name)) { + throw new TypeError( + `Allowed parser options are ${Object.keys( + options + )}, but not '${name}'` + ); + } + options[name] = value; + } + + return recast.parse(code, { + parser: { + parse(code: string) { + return parse(code, options); + }, + }, + }); +} diff --git a/src/util/SapUiDefineCall.ts b/src/util/SapUiDefineCall.ts index eec165e1..ce8e192f 100644 --- a/src/util/SapUiDefineCall.ts +++ b/src/util/SapUiDefineCall.ts @@ -1,8 +1,9 @@ /* tslint:disable:no-console */ -import {Syntax} from "esprima"; +import {Syntax} from "../Migration"; import * as ESTree from "estree"; import * as recast from "recast"; +import * as path from "path"; import {TNodePath} from "ui5-migration"; import {ConsoleReporter} from "../Migration"; @@ -172,14 +173,21 @@ export class SapUiDefineCall { } } - static _resolveRelativeImports(relValue, currentModule) { - if (relValue.startsWith("./") && !currentModule.startsWith("./")) { + static _resolveRelativeImports( + relValue: string, + currentModule: string + ): string { + if ( + (relValue.startsWith("./") || relValue.startsWith("../")) && + !currentModule.startsWith("./") + ) { if (currentModule.includes("/")) { - relValue = - currentModule.substring(0, currentModule.lastIndexOf("/")) + - relValue.substring(".".length); + relValue = path.join( + currentModule.substring(0, currentModule.lastIndexOf("/")), + relValue + ); } else { - relValue = relValue.substring("./".length); + relValue = path.join("", relValue); } } return relValue; @@ -191,6 +199,10 @@ export class SapUiDefineCall { * @returns {string[]} dependency array elements resolved absolutely, e.g. ["a/b/c", "g/f/j"] */ getAbsoluteDependencyPaths() { + if (!this.dependencyArray) { + return []; + } + return this.dependencyArray.elements.map(oElement => { const value = (oElement as ESTree.Literal).value.toString(); return SapUiDefineCall._resolveRelativeImports(value, this.name); @@ -335,6 +347,11 @@ export class SapUiDefineCall { this.factory.params.splice(iIndexToRemove, 1); // sShortcut this.paramNames.splice(iIndexToRemove, 1); + + if (iIndexToRemove < this.dependencyInsertionIdx) { + this.dependencyInsertionIdx--; + } + return true; } @@ -407,7 +424,7 @@ export class SapUiDefineCall { return ( oElement.value === sModule || SapUiDefineCall._resolveRelativeImports( - oElement.value, + oElement.value as string, this.name ) === sModule ); diff --git a/src/util/SapUiDefineCallUtils.ts b/src/util/SapUiDefineCallUtils.ts index 6e88d91e..89ff8e73 100644 --- a/src/util/SapUiDefineCallUtils.ts +++ b/src/util/SapUiDefineCallUtils.ts @@ -5,7 +5,7 @@ import {SapUiDefineCall} from "./SapUiDefineCall"; import * as ESTree from "estree"; -const Syntax = require("esprima").Syntax; +import {Syntax} from "../Migration"; /* * resolves relative AMD module identifiers relative to a given base name @@ -92,7 +92,7 @@ export function checkForShortcutExpression( return undefined; } - let leftmost = node; + let leftmost: ESTree.Node = node; const propertyPath = []; while ( leftmost.type === Syntax.MemberExpression && diff --git a/src/util/StringFileInfo.ts b/src/util/StringFileInfo.ts index 2ad91444..0b245520 100644 --- a/src/util/StringFileInfo.ts +++ b/src/util/StringFileInfo.ts @@ -8,6 +8,7 @@ import {ReportLevel} from "../Migration"; import {AnalyzeCharacter, CodeStyleAnalyzer} from "./CodeStyleAnalyzer"; import * as DiffOptimizer from "./whitespace/DiffOptimizer"; +import {parse} from "./ParseUtils"; const mStrategiesCache = new Map(); @@ -44,7 +45,7 @@ export class StringFileInfo implements Mod.FileInfo { } async loadContent(): Promise { - this.oAST = recast.parse(this.input).program; + this.oAST = parse(this.input).program; return this.oAST; } diff --git a/src/util/TypeDependencyUtil.ts b/src/util/TypeDependencyUtil.ts index db7771d1..78680863 100644 --- a/src/util/TypeDependencyUtil.ts +++ b/src/util/TypeDependencyUtil.ts @@ -7,9 +7,9 @@ import * as ASTUtils from "./ASTUtils"; import {ASTVisitor} from "./ASTVisitor"; import * as Mod from "../Migration"; import {APIInfo} from "./APIInfo"; +import {Syntax} from "../Migration"; const recast = require("recast"); -const Syntax = require("esprima").Syntax; const builders = recast.types.builders; diff --git a/src/util/whitespace/AstStringOptimizeStrategy.ts b/src/util/whitespace/AstStringOptimizeStrategy.ts index e377ea5c..60e373fe 100644 --- a/src/util/whitespace/AstStringOptimizeStrategy.ts +++ b/src/util/whitespace/AstStringOptimizeStrategy.ts @@ -2,8 +2,8 @@ import {Reporter, ReportLevel} from "../../reporter/Reporter"; import * as StringWhitespaceUtils from "./StringWhitespaceUtils"; import {StringOptimizeStrategy} from "./StringOptimizeStrategy"; - -const esprima = require("esprima"); +import {ecmaVersion} from "../ParseUtils"; +import {parse} from "espree"; /** * processing direction @@ -15,6 +15,14 @@ enum PROCESS_DIRECTION { } const filterAstAttributes = ["type", "range", "loc"]; +const parseOptions = { + comment: false, + ecmaVersion, + range: true, + sourceType: "script", + loc: true, + tokens: false, +}; /** * Replacement function which performs a modification of the jsContent @@ -354,7 +362,7 @@ export class AstStringOptimizeStrategy implements StringOptimizeStrategy { */ private static isStringValidJs(jsString) { try { - esprima.parseScript(jsString); + parse(jsString, parseOptions); return true; } catch (e) { return false; @@ -561,9 +569,8 @@ export class AstStringOptimizeStrategy implements StringOptimizeStrategy { original: string, modified: string ): Promise { - const oOptions = {range: true, loc: true}; - const oParsedOriginal = esprima.parseScript(original, oOptions); - const oParsedModified = esprima.parseScript(modified, oOptions); + const oParsedOriginal = parse(original, parseOptions); + const oParsedModified = parse(modified, parseOptions); let result = true; this.iterateAstNode( oParsedOriginal, @@ -597,9 +604,8 @@ export class AstStringOptimizeStrategy implements StringOptimizeStrategy { ); } - const oOptions = {range: true, loc: true}; - const oParsedOriginal = esprima.parseScript(original, oOptions); - const oParsedModified = esprima.parseScript(modified, oOptions); + const oParsedOriginal = parse(original, parseOptions); + const oParsedModified = parse(modified, parseOptions); const aOptimizedContent = modified.split(""); const oUseStrictModifiedNode = diff --git a/test/addMissingDependencies/findGetCoreCalls.config.json b/test/addMissingDependencies/findGetCoreCalls.config.json new file mode 100644 index 00000000..4f18bbc0 --- /dev/null +++ b/test/addMissingDependencies/findGetCoreCalls.config.json @@ -0,0 +1,27 @@ +{ + "modules": { + "Find getCore() calls": { + "sap.ui.getCore()": { + "replacer": "NOOP", + "finder": "GlobalGetCoreFinder", + "extender": "addImportWithResolvedPath", + "newModulePath": "sap/ui/core/Core", + "newVariableName": "Core", + "version": "1.58.0" + } + } + }, + "finders": { + "GlobalGetCoreFinder": "tasks/helpers/finders/GlobalGetCoreFinder.js" + }, + "extenders": { + "addImportWithResolvedPath": "tasks/helpers/extenders/addImportWithResolvedPath.js" + }, + "replacers": { + "NOOP": "tasks/helpers/replacers/NOOP.js" + }, + "comments": { + "unhandledReplacementComment": "TODO unhandled replacement" + }, + "excludes": [] +} \ No newline at end of file diff --git a/test/addMissingDependencies/findGetCoreCalls.expected.js b/test/addMissingDependencies/findGetCoreCalls.expected.js new file mode 100644 index 00000000..0cadfa0b --- /dev/null +++ b/test/addMissingDependencies/findGetCoreCalls.expected.js @@ -0,0 +1,29 @@ +/* ! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/Core"], function(Core) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + /** + * + * @param oParam + * @param sContent + */ + A.x = function(oParam) { + if (sap.ui.getCore().getLoadedLibraries()) { + return true; + } else { + return false; + } + }; + + return A; +}, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/findGetCoreCalls.js b/test/addMissingDependencies/findGetCoreCalls.js new file mode 100644 index 00000000..dec70128 --- /dev/null +++ b/test/addMissingDependencies/findGetCoreCalls.js @@ -0,0 +1,29 @@ +/* ! + * ${copyright} + */ + +// A module +sap.ui.define([], function() { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + /** + * + * @param oParam + * @param sContent + */ + A.x = function(oParam) { + if (sap.ui.getCore().getLoadedLibraries()) { + return true; + } else { + return false; + } + }; + + return A; +}, /* bExport= */ true); diff --git a/test/addMissingDependencies/replaceCoreAPI/ElementRegistryGet.config.json b/test/addMissingDependencies/replaceCoreAPI/ElementRegistryGet.config.json new file mode 100644 index 00000000..5bb80c0f --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/ElementRegistryGet.config.json @@ -0,0 +1,27 @@ +{ + "modules": { + "GLOBALS": { + "core.byId": { + "newModulePath": "sap/ui/core/Element", + "newVariableName": "UI5Element", + "replacer": "ElementRegistryGet", + "finder": "CoreFunctionCallFinder", + "functionToFind": "byId", + "extender": "AddImportAndRemoveUnused" + } + } + }, + "finders": { + "CoreFunctionCallFinder": "tasks/helpers/finders/CoreFunctionCallFinder.js" + }, + "extenders": { + "AddImportAndRemoveUnused": "tasks/helpers/extenders/AddImportAndRemoveUnused.js" + }, + "replacers": { + "ElementRegistryGet": "tasks/helpers/replacers/ElementRegistryGet.js" + }, + "comments": { + "unhandledReplacementComment": "TODO unhandled replacement" + }, + "excludes": [] +} \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/ElementRegistryGet.expected.js b/test/addMissingDependencies/replaceCoreAPI/ElementRegistryGet.expected.js new file mode 100644 index 00000000..c2caa95c --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/ElementRegistryGet.expected.js @@ -0,0 +1,24 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/Element"], + function(UI5Element) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + var oControl = UI5Element.registry.get("id1"); + var oControl1 = UI5Element.registry.get(oParam.id); + + return [oControl, oControl1]; + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/ElementRegistryGet.js b/test/addMissingDependencies/replaceCoreAPI/ElementRegistryGet.js new file mode 100644 index 00000000..db8832b8 --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/ElementRegistryGet.js @@ -0,0 +1,24 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/Core"], + function(Core) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + var oControl = sap.ui.getCore().byId("id1"); + var oControl1 = Core.byId(oParam.id); + + return [oControl, oControl1]; + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/FocusHandlerGetCurrentFocus.config.json b/test/addMissingDependencies/replaceCoreAPI/FocusHandlerGetCurrentFocus.config.json new file mode 100644 index 00000000..f7b68efa --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/FocusHandlerGetCurrentFocus.config.json @@ -0,0 +1,27 @@ +{ + "modules": { + "GLOBALS": { + "core.getCurrentFocusedControlId": { + "newModulePath": "sap/ui/core/FocusHandler", + "newVariableName": "FocusHandler", + "replacer": "FocusHandlerGetCurrentFocus", + "finder": "CoreFunctionCallFinder", + "functionToFind": "getCurrentFocusedControlId", + "extender": "AddImportAndRemoveUnused" + } + } + }, + "finders": { + "CoreFunctionCallFinder": "tasks/helpers/finders/CoreFunctionCallFinder.js" + }, + "extenders": { + "AddImportAndRemoveUnused": "tasks/helpers/extenders/AddImportAndRemoveUnused.js" + }, + "replacers": { + "FocusHandlerGetCurrentFocus": "tasks/helpers/replacers/FocusHandlerGetCurrentFocus.js" + }, + "comments": { + "unhandledReplacementComment": "TODO unhandled replacement" + }, + "excludes": [] +} \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/FocusHandlerGetCurrentFocus.expected.js b/test/addMissingDependencies/replaceCoreAPI/FocusHandlerGetCurrentFocus.expected.js new file mode 100644 index 00000000..583f9960 --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/FocusHandlerGetCurrentFocus.expected.js @@ -0,0 +1,27 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/FocusHandler"], + function(FocusHandler) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + var sActiveElementId = FocusHandler.getCurrentFocusedControlId(); + var bPass = (oParam.a > oParam.b) && (FocusHandler.getCurrentFocusedControlId() === oParam.id); + if (oParam.id !== FocusHandler.getCurrentFocusedControlId()) { + return []; + } else { + return [sActiveElementId, bPass]; + } + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/FocusHandlerGetCurrentFocus.js b/test/addMissingDependencies/replaceCoreAPI/FocusHandlerGetCurrentFocus.js new file mode 100644 index 00000000..b145795b --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/FocusHandlerGetCurrentFocus.js @@ -0,0 +1,27 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/Core"], + function(Core) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + var sActiveElementId = Core.getCurrentFocusedControlId(); + var bPass = (oParam.a > oParam.b) && (sap.ui.getCore().getCurrentFocusedControlId() === oParam.id); + if (oParam.id !== sap.ui.getCore().getCurrentFocusedControlId()) { + return []; + } else { + return [sActiveElementId, bPass]; + } + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/ThemeManagerAttachEvent.config.json b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerAttachEvent.config.json new file mode 100644 index 00000000..0124fdd2 --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerAttachEvent.config.json @@ -0,0 +1,27 @@ +{ + "modules": { + "GLOBALS": { + "core.attachThemeChanged": { + "newModulePath": "sap/ui/core/theming/ThemeManager", + "newVariableName": "ThemeManager", + "replacer": "ThemeManagerAttachEvent", + "finder": "CoreFunctionCallFinder", + "functionToFind": "attachThemeChanged", + "extender": "AddImportAndRemoveUnused" + } + } + }, + "finders": { + "CoreFunctionCallFinder": "tasks/helpers/finders/CoreFunctionCallFinder.js" + }, + "extenders": { + "AddImportAndRemoveUnused": "tasks/helpers/extenders/AddImportAndRemoveUnused.js" + }, + "replacers": { + "ThemeManagerAttachEvent": "tasks/helpers/replacers/ThemeManagerAttachEvent.js" + }, + "comments": { + "unhandledReplacementComment": "TODO unhandled replacement" + }, + "excludes": [] +} \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/ThemeManagerAttachEvent.expected.js b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerAttachEvent.expected.js new file mode 100644 index 00000000..a9b9283f --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerAttachEvent.expected.js @@ -0,0 +1,25 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/theming/ThemeManager"], + function(ThemeManager) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + ThemeManager.attachEvent("ThemeChanged", oParam.fnThemeChangeHandler, this); + + ThemeManager.attachEvent("ThemeChanged", function() { + this.themeChanged = true; + }.bind(oParam)); + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/ThemeManagerAttachEvent.js b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerAttachEvent.js new file mode 100644 index 00000000..e3b10902 --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerAttachEvent.js @@ -0,0 +1,25 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/Core"], + function(Core) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + sap.ui.getCore().attachThemeChanged(oParam.fnThemeChangeHandler, this); + + Core.attachThemeChanged(function() { + this.themeChanged = true; + }.bind(oParam)); + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/ThemeManagerDetachEvent.config.json b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerDetachEvent.config.json new file mode 100644 index 00000000..d2d34f14 --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerDetachEvent.config.json @@ -0,0 +1,27 @@ +{ + "modules": { + "GLOBALS": { + "core.detachThemeChanged": { + "newModulePath": "sap/ui/core/theming/ThemeManager", + "newVariableName": "ThemeManager", + "replacer": "ThemeManagerDetachEvent", + "finder": "CoreFunctionCallFinder", + "functionToFind": "detachThemeChanged", + "extender": "AddImportAndRemoveUnused" + } + } + }, + "finders": { + "CoreFunctionCallFinder": "tasks/helpers/finders/CoreFunctionCallFinder.js" + }, + "extenders": { + "AddImportAndRemoveUnused": "tasks/helpers/extenders/AddImportAndRemoveUnused.js" + }, + "replacers": { + "ThemeManagerDetachEvent": "tasks/helpers/replacers/ThemeManagerDetachEvent.js" + }, + "comments": { + "unhandledReplacementComment": "TODO unhandled replacement" + }, + "excludes": [] +} \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/ThemeManagerDetachEvent.expected.js b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerDetachEvent.expected.js new file mode 100644 index 00000000..87641409 --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerDetachEvent.expected.js @@ -0,0 +1,23 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/theming/ThemeManager"], + function(ThemeManager) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + ThemeManager.detachEvent("ThemeChanged", oParam.fnThemeChangeHandler, this); + + ThemeManager.detachEvent("ThemeChanged", oParam.handler1); + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/ThemeManagerDetachEvent.js b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerDetachEvent.js new file mode 100644 index 00000000..36f5df42 --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerDetachEvent.js @@ -0,0 +1,23 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/Core"], + function(Core) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + sap.ui.getCore().detachThemeChanged(oParam.fnThemeChangeHandler, this); + + Core.detachThemeChanged(oParam.handler1); + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/ThemeManagerThemeLoaded.config.json b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerThemeLoaded.config.json new file mode 100644 index 00000000..eb0b459c --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerThemeLoaded.config.json @@ -0,0 +1,27 @@ +{ + "modules": { + "GLOBALS": { + "core.isThemeApplied": { + "newModulePath": "sap/ui/core/theming/ThemeManager", + "newVariableName": "ThemeManager", + "replacer": "ThemeManagerThemeLoaded", + "finder": "CoreFunctionCallFinder", + "functionToFind": "isThemeApplied", + "extender": "AddImportAndRemoveUnused" + } + } + }, + "finders": { + "CoreFunctionCallFinder": "tasks/helpers/finders/CoreFunctionCallFinder.js" + }, + "extenders": { + "AddImportAndRemoveUnused": "tasks/helpers/extenders/AddImportAndRemoveUnused.js" + }, + "replacers": { + "ThemeManagerThemeLoaded": "tasks/helpers/replacers/ThemeManagerThemeLoaded.js" + }, + "comments": { + "unhandledReplacementComment": "TODO unhandled replacement" + }, + "excludes": [] +} \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/ThemeManagerThemeLoaded.expected.js b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerThemeLoaded.expected.js new file mode 100644 index 00000000..847f04c0 --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerThemeLoaded.expected.js @@ -0,0 +1,25 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/theming/ThemeManager"], + function(ThemeManager) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + if (oParam.condition && ThemeManager.themeLoaded) { + return [oParam.a]; + } else { + return ThemeManager.themeLoaded; + } + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/ThemeManagerThemeLoaded.js b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerThemeLoaded.js new file mode 100644 index 00000000..002ffbd1 --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/ThemeManagerThemeLoaded.js @@ -0,0 +1,25 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/Core"], + function(Core) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + if (oParam.condition && sap.ui.getCore().isThemeApplied()) { + return [oParam.a]; + } else { + return Core.isThemeApplied(); + } + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/UIAreaGetStaticAreaRef.config.json b/test/addMissingDependencies/replaceCoreAPI/UIAreaGetStaticAreaRef.config.json new file mode 100644 index 00000000..c10c19af --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/UIAreaGetStaticAreaRef.config.json @@ -0,0 +1,27 @@ +{ + "modules": { + "GLOBALS": { + "core.getStaticAreaRef": { + "newModulePath": "sap/ui/core/UIArea", + "newVariableName": "UIArea", + "replacer": "UIAreaGetStaticAreaRef", + "finder": "CoreFunctionCallFinder", + "functionToFind": "getStaticAreaRef", + "extender": "AddImportAndRemoveUnused" + } + } + }, + "finders": { + "CoreFunctionCallFinder": "tasks/helpers/finders/CoreFunctionCallFinder.js" + }, + "extenders": { + "AddImportAndRemoveUnused": "tasks/helpers/extenders/AddImportAndRemoveUnused.js" + }, + "replacers": { + "UIAreaGetStaticAreaRef": "tasks/helpers/replacers/UIAreaGetStaticAreaRef.js" + }, + "comments": { + "unhandledReplacementComment": "TODO unhandled replacement" + }, + "excludes": [] +} \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/UIAreaGetStaticAreaRef.expected.js b/test/addMissingDependencies/replaceCoreAPI/UIAreaGetStaticAreaRef.expected.js new file mode 100644 index 00000000..d8caf185 --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/UIAreaGetStaticAreaRef.expected.js @@ -0,0 +1,24 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/UIArea"], + function(UIArea) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + var oUIArea = UIArea.getStaticAreaRef(); + var oUIArea1 = UIArea.getStaticAreaRef(); + + return [oUIArea, oUIArea1]; + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/UIAreaGetStaticAreaRef.js b/test/addMissingDependencies/replaceCoreAPI/UIAreaGetStaticAreaRef.js new file mode 100644 index 00000000..15fa78ac --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/UIAreaGetStaticAreaRef.js @@ -0,0 +1,24 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/Core"], + function(Core) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + var oUIArea = sap.ui.getCore().getStaticAreaRef(); + var oUIArea1 = Core.getStaticAreaRef(); + + return [oUIArea, oUIArea1]; + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/createRenderManager.config.json b/test/addMissingDependencies/replaceCoreAPI/createRenderManager.config.json new file mode 100644 index 00000000..77ae8da0 --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/createRenderManager.config.json @@ -0,0 +1,27 @@ +{ + "modules": { + "GLOBALS": { + "core.createRenderManager": { + "newModulePath": "sap/ui/core/RenderManager", + "newVariableName": "RenderManager", + "replacer": "NewRenderManager", + "finder": "CoreFunctionCallFinder", + "functionToFind": "createRenderManager", + "extender": "AddImportAndRemoveUnused" + } + } + }, + "finders": { + "CoreFunctionCallFinder": "tasks/helpers/finders/CoreFunctionCallFinder.js" + }, + "extenders": { + "AddImportAndRemoveUnused": "tasks/helpers/extenders/AddImportAndRemoveUnused.js" + }, + "replacers": { + "NewRenderManager": "tasks/helpers/replacers/NewRenderManager.js" + }, + "comments": { + "unhandledReplacementComment": "TODO unhandled replacement" + }, + "excludes": [] +} \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/createRenderManager.expected.js b/test/addMissingDependencies/replaceCoreAPI/createRenderManager.expected.js new file mode 100644 index 00000000..0094c751 --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/createRenderManager.expected.js @@ -0,0 +1,24 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/RenderManager"], + function(RenderManager) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + var oRm = new RenderManager(); + var oRm1 = new RenderManager(); + + return [oRm, oRm1]; + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/createRenderManager.js b/test/addMissingDependencies/replaceCoreAPI/createRenderManager.js new file mode 100644 index 00000000..f1674bad --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/createRenderManager.js @@ -0,0 +1,24 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/Core"], + function(Core) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + var oRm = sap.ui.getCore().createRenderManager(); + var oRm1 = Core.createRenderManager(); + + return [oRm, oRm1]; + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/getResourceBundle.config.json b/test/addMissingDependencies/replaceCoreAPI/getResourceBundle.config.json new file mode 100644 index 00000000..7bd3240e --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/getResourceBundle.config.json @@ -0,0 +1,27 @@ +{ + "modules": { + "GLOBALS": { + "core.getLibraryResourceBundle": { + "newModulePath": "sap/ui/core/Lib", + "newVariableName": "Library", + "replacer": "LibGetResourceBundle", + "finder": "CoreFunctionCallFinder", + "functionToFind": "getLibraryResourceBundle", + "extender": "AddImportAndRemoveUnused" + } + } + }, + "finders": { + "CoreFunctionCallFinder": "tasks/helpers/finders/CoreFunctionCallFinder.js" + }, + "extenders": { + "AddImportAndRemoveUnused": "tasks/helpers/extenders/AddImportAndRemoveUnused.js" + }, + "replacers": { + "LibGetResourceBundle": "tasks/helpers/replacers/LibGetResourceBundle.js" + }, + "comments": { + "unhandledReplacementComment": "TODO unhandled replacement" + }, + "excludes": [] +} \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/getResourceBundle.expected.js b/test/addMissingDependencies/replaceCoreAPI/getResourceBundle.expected.js new file mode 100644 index 00000000..2157c954 --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/getResourceBundle.expected.js @@ -0,0 +1,25 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/Lib"], + function(Library) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + var oResourceBundle = Library.get("sap.m").getResourceBundle(); + var sText = Library.get("sap.ui.core").getResourceBundle().getText("key"); + var sText1 = oResourceBundle.getText(oParam.key); + + return [sText, sText1, Library.get(oParam.library).getResourceBundle().getText("abc")]; + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependencies/replaceCoreAPI/getResourceBundle.js b/test/addMissingDependencies/replaceCoreAPI/getResourceBundle.js new file mode 100644 index 00000000..d4a63f36 --- /dev/null +++ b/test/addMissingDependencies/replaceCoreAPI/getResourceBundle.js @@ -0,0 +1,25 @@ +/*! + * ${copyright} + */ + +// A module +sap.ui.define(["sap/ui/core/Core"], + function(Core) { + "use strict"; + + /** + * + * @type {{}} + */ + var A = {}; + + A.x = function (oParam) { + var oResourceBundle = sap.ui.getCore().getLibraryResourceBundle("sap.m"); + var sText = sap.ui.getCore().getLibraryResourceBundle().getText("key"); + var sText1 = oResourceBundle.getText(oParam.key); + + return [sText, sText1, Core.getLibraryResourceBundle(oParam.library).getText("abc")]; + }; + + return A; + }, /* bExport= */ true); \ No newline at end of file diff --git a/test/addMissingDependenciesTest.ts b/test/addMissingDependenciesTest.ts index 3ae0a85c..9ba17fb7 100644 --- a/test/addMissingDependenciesTest.ts +++ b/test/addMissingDependenciesTest.ts @@ -536,5 +536,188 @@ describe("addMissingDependencies", () => { [] ); }); + + it("should replace Core.getLibraryResourceBundle() with Lib.get(...).getResourceBundle()", done => { + const fileName = "getResourceBundle"; + const subDir = rootDir + "replaceCoreAPI/"; + const expectedContent = fs.readFileSync( + `${subDir}${fileName}.expected.js`, + "utf8" + ); + const config = JSON.parse( + fs.readFileSync(`${subDir}${fileName}.config.json`, "utf8") + ); + const module = new CustomFileInfo(`${subDir}${fileName}.js`); + analyseMigrateAndTest( + module, + true, + expectedContent, + config, + done, + [] + ); + }); + + it("should replace Core.createRenderManager() with 'new RenderManager()'", done => { + const fileName = "createRenderManager"; + const subDir = rootDir + "replaceCoreAPI/"; + const expectedContent = fs.readFileSync( + `${subDir}${fileName}.expected.js`, + "utf8" + ); + const config = JSON.parse( + fs.readFileSync(`${subDir}${fileName}.config.json`, "utf8") + ); + const module = new CustomFileInfo(`${subDir}${fileName}.js`); + analyseMigrateAndTest( + module, + true, + expectedContent, + config, + done, + [] + ); + }); + + it("should replace Core.getCurrentFocusedControlId() with 'FocusHandler.getCurrentFocusedControlId()'", done => { + const fileName = "FocusHandlerGetCurrentFocus"; + const subDir = rootDir + "replaceCoreAPI/"; + const expectedContent = fs.readFileSync( + `${subDir}${fileName}.expected.js`, + "utf8" + ); + const config = JSON.parse( + fs.readFileSync(`${subDir}${fileName}.config.json`, "utf8") + ); + const module = new CustomFileInfo(`${subDir}${fileName}.js`); + analyseMigrateAndTest( + module, + true, + expectedContent, + config, + done, + [] + ); + }); + + it("should replace Core.isThemeApplied() with 'ThemeManager.themeLoaded'", done => { + const fileName = "ThemeManagerThemeLoaded"; + const subDir = rootDir + "replaceCoreAPI/"; + const expectedContent = fs.readFileSync( + `${subDir}${fileName}.expected.js`, + "utf8" + ); + const config = JSON.parse( + fs.readFileSync(`${subDir}${fileName}.config.json`, "utf8") + ); + const module = new CustomFileInfo(`${subDir}${fileName}.js`); + analyseMigrateAndTest( + module, + true, + expectedContent, + config, + done, + [] + ); + }); + + it("should replace Core.attachThemeChanged(...) with 'ThemeManager.attachEvent(\"ThemeChanged\", ...)'", done => { + const fileName = "ThemeManagerAttachEvent"; + const subDir = rootDir + "replaceCoreAPI/"; + const expectedContent = fs.readFileSync( + `${subDir}${fileName}.expected.js`, + "utf8" + ); + const config = JSON.parse( + fs.readFileSync(`${subDir}${fileName}.config.json`, "utf8") + ); + const module = new CustomFileInfo(`${subDir}${fileName}.js`); + analyseMigrateAndTest( + module, + true, + expectedContent, + config, + done, + [] + ); + }); + + it("should replace Core.detachThemeChanged(...) with 'ThemeManager.detachEvent(\"ThemeChanged\", ...)'", done => { + const fileName = "ThemeManagerDetachEvent"; + const subDir = rootDir + "replaceCoreAPI/"; + const expectedContent = fs.readFileSync( + `${subDir}${fileName}.expected.js`, + "utf8" + ); + const config = JSON.parse( + fs.readFileSync(`${subDir}${fileName}.config.json`, "utf8") + ); + const module = new CustomFileInfo(`${subDir}${fileName}.js`); + analyseMigrateAndTest( + module, + true, + expectedContent, + config, + done, + [] + ); + }); + + it("should replace Core.byId(...) with 'UI5Element.registry.get(...)'", done => { + const fileName = "ElementRegistryGet"; + const subDir = rootDir + "replaceCoreAPI/"; + const expectedContent = fs.readFileSync( + `${subDir}${fileName}.expected.js`, + "utf8" + ); + const config = JSON.parse( + fs.readFileSync(`${subDir}${fileName}.config.json`, "utf8") + ); + const module = new CustomFileInfo(`${subDir}${fileName}.js`); + analyseMigrateAndTest( + module, + true, + expectedContent, + config, + done, + [] + ); + }); + + it("should replace Core.getStaticAreaRef(...) with 'UIArea.getStaticAreaRef(...)'", done => { + const fileName = "UIAreaGetStaticAreaRef"; + const subDir = rootDir + "replaceCoreAPI/"; + const expectedContent = fs.readFileSync( + `${subDir}${fileName}.expected.js`, + "utf8" + ); + const config = JSON.parse( + fs.readFileSync(`${subDir}${fileName}.config.json`, "utf8") + ); + const module = new CustomFileInfo(`${subDir}${fileName}.js`); + analyseMigrateAndTest( + module, + true, + expectedContent, + config, + done, + [] + ); + }); + + it("should add missing dependency sap/ui/core/Core when sap.ui.getCore() is found", () => { + const subDir = rootDir; + + const expectedContent = fs.readFileSync( + subDir + "findGetCoreCalls.expected.js", + "utf8" + ); + + const config = JSON.parse( + fs.readFileSync(subDir + "findGetCoreCalls.config.json", "utf8") + ); + const module = new CustomFileInfo(subDir + "findGetCoreCalls.js"); + return analyseMigrateAndTest(module, true, expectedContent, config); + }); }); });