From 661e5621b20f4458556938c02abf71506383374d Mon Sep 17 00:00:00 2001 From: Ryan Murphy Date: Thu, 7 Feb 2019 23:37:51 -0500 Subject: [PATCH] Provide modulesMap option related to #19 --- README.md | 14 ++++++---- .../__test__/__snapshots__/test.js.snap | 28 +++++++++++++++++++ .../fixtures/imports/import-modules-map-fn.js | 4 +++ .../fixtures/imports/import-modules-map.js | 4 +++ packages/plugin/__test__/options.js | 11 ++++++++ packages/plugin/src/index.js | 10 +++++-- 6 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 packages/plugin/__test__/fixtures/imports/import-modules-map-fn.js create mode 100644 packages/plugin/__test__/fixtures/imports/import-modules-map.js diff --git a/README.md b/README.md index 334d8bb..dc427d0 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,8 @@ import * as Name from "module"; ``` The plugin uses a temporary name (as needed) for the initial imported variable, and then extracts the properties from it as needed. -This allows importing ES Modules which have a 'default' value, and also non-ES modules which don't. The plugin also allows for merged imports statements from the same source path into a single require and then deconstructs it accordingly. +This allows importing ES Modules which have a 'default' value, and also non-ES modules which don't. +The plugin also allows for merged imports statements from the same source path into a single require and then deconstructs it accordingly. This: @@ -102,7 +103,7 @@ import * as File from "app/File"; Becomes: ```js -sap.ui.define(['app/file'], function(__File) { +sap.ui.define(['app/File'], function(__File) { function _interopRequireDefault(obj) { return (obj && obj.__esModule && (typeof obj.default !== "undefined")) ? obj.default : obj; } @@ -120,9 +121,11 @@ Also refer to the `noImportInteropPrefixes` option below. ECMAScript allows for dynamic imports calls like `import(path)` that return a Promise which resolves with an ES Module. This plugin will convert that to an async `sap.ui.require` wrapped in a Promise. -The resolved object will be a ES module or pseudo ES module having a 'default' property on it to reference the module by, to match the format used by `import()`. If the module is not a real ES module and already has a default property, the promise will be rejected with an error. +The resolved object will be a ES module or pseudo ES module having a 'default' property on it to reference the module by, to match the format used by `import()`. +If the module is not a real ES module and already has a default property, the promise will be rejected with an error. -For JavaScript projects, this syntax doesn't provide much advantage over a small utility function and has the downside of not working if your module has a 'default' property. The main advantage of this syntax is with TypeScript projects, where the TypeScript compiler will know the type of the imported module, so there his no need to define a separate interface for it. +For JavaScript projects, this syntax doesn't provide much advantage over a small utility function and has the downside of not working if your module has a 'default' property. +The main advantage of this syntax is with TypeScript projects, where the TypeScript compiler will know the type of the imported module, so there is no need to define a separate interface for it. Also note that while the ES dynamic import specification requires a relative path, `sap.ui.require` works with absolute paths using a module prefix. @@ -599,6 +602,7 @@ const MyControl = SAPClass.extend('MyControl', { ### Imports - `noImportInteropPrefixes` (Default `['sap/']`) A list of import path prefixes which never need an import inter-opt. +- `modulesMap` (Default {}) Mapping for an import's path. Accepts object or function. ### Exports @@ -661,7 +665,7 @@ Some preload plugins: - Export interop control - Others.. -Contribute +## Contribute Please do! Open an issue, or file a PR. Issues also welcome for feature requests. diff --git a/packages/plugin/__test__/__snapshots__/test.js.snap b/packages/plugin/__test__/__snapshots__/test.js.snap index b4d958c..ef1e06d 100644 --- a/packages/plugin/__test__/__snapshots__/test.js.snap +++ b/packages/plugin/__test__/__snapshots__/test.js.snap @@ -1041,6 +1041,34 @@ exports[`imports import-dynamic.js 1`] = ` });" `; +exports[`imports import-modules-map.js 1`] = ` +"sap.ui.define([\\"./vendor/browser-polyfill\\"], function (__X) { + function _interopRequireDefault(obj) { + return obj && obj.__esModule && typeof obj.default !== \\"undefined\\" ? obj.default : obj; + } + + const X = _interopRequireDefault(__X); + + const Named1 = __X[\\"Named1\\"]; + const Named2 = __X[\\"Named2\\"]; + const X2 = __X; +});" +`; + +exports[`imports import-modules-map-fn.js 1`] = ` +"sap.ui.define([\\"./vendor/browser-polyfill\\"], function (__X) { + function _interopRequireDefault(obj) { + return obj && obj.__esModule && typeof obj.default !== \\"undefined\\" ? obj.default : obj; + } + + const X = _interopRequireDefault(__X); + + const Named1 = __X[\\"Named1\\"]; + const Named2 = __X[\\"Named2\\"]; + const X2 = __X; +});" +`; + exports[`imports import-multiple.js 1`] = ` "sap.ui.define([\\"./../a/b\\", \\"path/having-dash\\", \\"A\\", \\"BC\\", \\"DEF\\", \\"G\\", \\"HI\\"], function (____a_b, __path_having_dash, __A, __BC, __D, G, __H) { function _interopRequireDefault(obj) { diff --git a/packages/plugin/__test__/fixtures/imports/import-modules-map-fn.js b/packages/plugin/__test__/fixtures/imports/import-modules-map-fn.js new file mode 100644 index 0000000..61d0c28 --- /dev/null +++ b/packages/plugin/__test__/fixtures/imports/import-modules-map-fn.js @@ -0,0 +1,4 @@ +import "@babel/polyfill"; +import X, { Named1 } from "@babel/polyfill"; +import { Named2 } from "@babel/polyfill"; +import * as X2 from "@babel/polyfill"; diff --git a/packages/plugin/__test__/fixtures/imports/import-modules-map.js b/packages/plugin/__test__/fixtures/imports/import-modules-map.js new file mode 100644 index 0000000..61d0c28 --- /dev/null +++ b/packages/plugin/__test__/fixtures/imports/import-modules-map.js @@ -0,0 +1,4 @@ +import "@babel/polyfill"; +import X, { Named1 } from "@babel/polyfill"; +import { Named2 } from "@babel/polyfill"; +import * as X2 from "@babel/polyfill"; diff --git a/packages/plugin/__test__/options.js b/packages/plugin/__test__/options.js index 2310f90..26fdf50 100644 --- a/packages/plugin/__test__/options.js +++ b/packages/plugin/__test__/options.js @@ -1,5 +1,8 @@ import { parse } from "path"; +/** + * Provides the ability to set options per test file or directory. + */ const Options = { default: { namespacePrefix: undefined, @@ -36,6 +39,14 @@ const Options = { "class-convert-constructor-keep-annot.controller": { moveControllerConstructorToOnInit: true, }, + "import-modules-map": { + modulesMap: { + ["@babel/polyfill"]: "./vendor/browser-polyfill", + }, + }, + "import-modules-map-fn": { + modulesMap: src => Options.files["import-modules-map"].modulesMap[src], + }, }, dirs: { "min-wrap": { diff --git a/packages/plugin/src/index.js b/packages/plugin/src/index.js index a446ee0..a71744e 100644 --- a/packages/plugin/src/index.js +++ b/packages/plugin/src/index.js @@ -98,11 +98,17 @@ module.exports = () => { const name = cleanImportSource(src); // default to the src for import without named var + const { modulesMap = {} } = opts; + const mappedSrc = + (typeof modulesMap === "function" + ? modulesMap(src) + : modulesMap[src]) || src; + // Note that existingImport may get mutated if there are multiple import lines from the same module. - const existingImport = this.imports.find(imp => imp.src === src); + const existingImport = this.imports.find(imp => imp.src === mappedSrc); const imp = existingImport || { - src, // url + src: mappedSrc, // url name, // isLib, // for future use separating UI5 imports from npm/webpack imports // isUi5Src, // not used yet