babel-plugin-transform-imports
Advanced tools
Comparing version 1.5.1 to 2.0.0
212
index.js
@@ -1,157 +0,135 @@ | ||
var types = require('babel-types'); | ||
var types = require('@babel/types'); | ||
var isValidPath = require('is-valid-path'); | ||
var camel = require('lodash.camelcase'); | ||
var findKey = require('lodash.findkey'); | ||
var kebab = require('lodash.kebabcase'); | ||
var snake = require('lodash.snakecase'); | ||
var pathLib = require('path'); | ||
function findOptionFromSource(source, state) { | ||
var opts = state.opts; | ||
if (opts[source]) return source; | ||
var opts = state.opts; | ||
if (opts[source]) return source; | ||
var opt = findKey(opts, function (o, _opt) { | ||
return !isValidPath(_opt) && new RegExp(_opt).test(source); | ||
}); | ||
if (opt) return opt; | ||
var opt = Object.keys(opts).find(function (key) { | ||
return !isValidPath(key) && new RegExp(key).test(source); | ||
}); | ||
if (opt) return opt; | ||
var isRelativePath = source.match(/^\.{0,2}\//); | ||
// This block handles relative paths, such as ./components, ../../components, etc. | ||
if (isRelativePath) { | ||
var _source = pathLib.resolve(pathLib.join( | ||
source[0] === '/' ? '' : pathLib.dirname(state.file.opts.filename), | ||
source | ||
)); | ||
var isRelativePath = source.match(/^\.{0,2}\//); | ||
// This block handles relative paths, such as ./components, ../../components, etc. | ||
if (isRelativePath) { | ||
var dirname = source[0] === '/' ? '' : state.file.opts.filename ? pathLib.dirname(state.file.opts.filename) : '.' | ||
var _source = pathLib.resolve(pathLib.join(dirname, source)); | ||
if (opts[_source]) { | ||
return _source; | ||
} | ||
if (opts[_source]) { | ||
return _source; | ||
} | ||
} | ||
} | ||
function getMatchesFromSource(opt, source) { | ||
var regex = new RegExp(opt, 'g'); | ||
var matches = []; | ||
var m; | ||
while ((m = regex.exec(source)) !== null) { | ||
if (m.index === regex.lastIndex) regex.lastIndex++; | ||
m.forEach(function(match) { | ||
matches.push(match); | ||
}); | ||
} | ||
return matches; | ||
var regex = new RegExp(opt, 'g'); | ||
var matches = []; | ||
var m; | ||
while ((m = regex.exec(source)) !== null) { | ||
if (m.index === regex.lastIndex) regex.lastIndex++; | ||
m.forEach(function (match) { | ||
matches.push(match); | ||
}); | ||
} | ||
return matches; | ||
} | ||
function barf(msg) { | ||
throw new Error('babel-plugin-transform-imports: ' + msg); | ||
throw new Error('babel-plugin-transform-imports: ' + msg); | ||
} | ||
function transform(transformOption, importName, matches) { | ||
var isFunction = typeof transformOption === 'function'; | ||
if (/\.js$/i.test(transformOption) || isFunction) { | ||
var transformFn; | ||
if (typeof transformOption === 'function') { | ||
return transformOption(importName, matches); | ||
} | ||
try { | ||
transformFn = isFunction ? transformOption : require(transformOption); | ||
} catch (error) { | ||
barf('failed to require transform file ' + transformOption); | ||
} | ||
if (typeof transformFn !== 'function') { | ||
barf('expected transform function to be exported from ' + transformOption); | ||
} | ||
return transformFn(importName, matches); | ||
} | ||
return transformOption.replace(/\$\{\s?([\w\d]*)\s?\}/ig, function(str, g1) { | ||
if (g1 === 'member') return importName; | ||
return matches[g1]; | ||
}); | ||
return transformOption.replace(/\$\{\s?([\w\d]*)\s?\}/ig, function (str, g1) { | ||
if (g1 === 'member') return importName; | ||
return matches[g1]; | ||
}); | ||
} | ||
module.exports = function() { | ||
return { | ||
visitor: { | ||
ImportDeclaration: function (path, state) { | ||
// https://github.com/babel/babel/tree/master/packages/babel-types#timportdeclarationspecifiers-source | ||
module.exports = function () { | ||
return { | ||
visitor: { | ||
ImportDeclaration: function (path, state) { | ||
// https://github.com/babel/babel/tree/master/packages/babel-types#timportdeclarationspecifiers-source | ||
// path.node has properties 'source' and 'specifiers' attached. | ||
// path.node.source is the library/module name, aka 'react-bootstrap'. | ||
// path.node.specifiers is an array of ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier | ||
// path.node has properties 'source' and 'specifiers' attached. | ||
// path.node.source is the library/module name, aka 'react-bootstrap'. | ||
// path.node.specifiers is an array of ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier | ||
var source = path.node.source.value; | ||
var source = path.node.source.value; | ||
var opt = findOptionFromSource(source, state); | ||
var isRegexp = opt && !isValidPath(opt); | ||
var opts = state.opts[opt]; | ||
var hasOpts = !!opts; | ||
var opt = findOptionFromSource(source, state); | ||
var isRegexp = opt && !isValidPath(opt); | ||
var opts = state.opts[opt]; | ||
var hasOpts = !!opts; | ||
if (hasOpts) { | ||
if (!opts.transform) { | ||
barf('transform option is required for module ' + source); | ||
} | ||
if (hasOpts) { | ||
if (!opts.transform) { | ||
barf('transform option is required for module ' + source); | ||
} | ||
var transforms = []; | ||
var transforms = []; | ||
var fullImports = path.node.specifiers.filter(function(specifier) { return specifier.type !== 'ImportSpecifier' }); | ||
var memberImports = path.node.specifiers.filter(function(specifier) { return specifier.type === 'ImportSpecifier' }); | ||
var fullImports = path.node.specifiers.filter(function (specifier) { return specifier.type !== 'ImportSpecifier' }); | ||
var memberImports = path.node.specifiers.filter(function (specifier) { return specifier.type === 'ImportSpecifier' }); | ||
if (fullImports.length > 0) { | ||
// Examples of "full" imports: | ||
// import * as name from 'module'; (ImportNamespaceSpecifier) | ||
// import name from 'module'; (ImportDefaultSpecifier) | ||
if (fullImports.length > 0) { | ||
// Examples of "full" imports: | ||
// import * as name from 'module'; (ImportNamespaceSpecifier) | ||
// import name from 'module'; (ImportDefaultSpecifier) | ||
if (opts.preventFullImport) { | ||
barf('import of entire module ' + source + ' not allowed due to preventFullImport setting'); | ||
} | ||
if (opts.preventFullImport) { | ||
barf('import of entire module ' + source + ' not allowed due to preventFullImport setting'); | ||
} | ||
if (memberImports.length > 0) { | ||
// Swap out the import with one that doesn't include member imports. Member imports should each get their own import line | ||
// transform this: | ||
// import Bootstrap, { Grid } from 'react-bootstrap'; | ||
// into this: | ||
// import Bootstrap from 'react-bootstrap'; | ||
transforms.push(types.importDeclaration(fullImports, types.stringLiteral(source))); | ||
} | ||
} | ||
if (memberImports.length > 0) { | ||
// Swap out the import with one that doesn't include member imports. Member imports should each get their own import line | ||
// transform this: | ||
// import Bootstrap, { Grid } from 'react-bootstrap'; | ||
// into this: | ||
// import Bootstrap from 'react-bootstrap'; | ||
transforms.push(types.importDeclaration(fullImports, types.stringLiteral(source))); | ||
} | ||
} | ||
var matches = isRegexp ? getMatchesFromSource(opt, source) : []; | ||
var matches = isRegexp ? getMatchesFromSource(opt, source) : []; | ||
memberImports.forEach(function(memberImport) { | ||
// Examples of member imports: | ||
// import { member } from 'module'; (ImportSpecifier) | ||
// import { member as alias } from 'module' (ImportSpecifier) | ||
memberImports.forEach(function (memberImport) { | ||
// Examples of member imports: | ||
// import { member } from 'module'; (ImportSpecifier) | ||
// import { member as alias } from 'module' (ImportSpecifier) | ||
// transform this: | ||
// import { Grid as gird } from 'react-bootstrap'; | ||
// into this: | ||
// import gird from 'react-bootstrap/lib/Grid'; | ||
// or this, if skipDefaultConversion = true: | ||
// import { Grid as gird } from 'react-bootstrap/lib/Grid'; | ||
// transform this: | ||
// import { Grid as gird } from 'react-bootstrap'; | ||
// into this: | ||
// import gird from 'react-bootstrap/lib/Grid'; | ||
// or this, if skipDefaultConversion = true: | ||
// import { Grid as gird } from 'react-bootstrap/lib/Grid'; | ||
var importName = memberImport.imported.name; | ||
if (opts.camelCase) importName = camel(importName); | ||
if (opts.kebabCase) importName = kebab(importName); | ||
if (opts.snakeCase) importName = snake(importName); | ||
var importName = memberImport.imported.name; | ||
var replace = transform(opts.transform, importName, matches); | ||
var replace = transform(opts.transform, importName, matches); | ||
var newImportSpecifier = (opts.skipDefaultConversion) | ||
? memberImport | ||
: types.importDefaultSpecifier(types.identifier(memberImport.local.name)); | ||
var newImportSpecifier = (opts.skipDefaultConversion) | ||
? memberImport | ||
: types.importDefaultSpecifier(types.identifier(memberImport.local.name)); | ||
transforms.push(types.importDeclaration( | ||
[newImportSpecifier], | ||
types.stringLiteral(replace) | ||
)); | ||
}); | ||
transforms.push(types.importDeclaration( | ||
[newImportSpecifier], | ||
types.stringLiteral(replace) | ||
)); | ||
}); | ||
if (transforms.length > 0) { | ||
path.replaceWithMultiple(transforms); | ||
} | ||
} | ||
} | ||
if (transforms.length > 0) { | ||
path.replaceWithMultiple(transforms); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
{ | ||
"name": "babel-plugin-transform-imports", | ||
"version": "1.5.1", | ||
"version": "2.0.0", | ||
"description": "Transforms member style imports (import {x} from 'y') into default style imports (import x from 'y/lib/x')", | ||
@@ -19,3 +19,3 @@ "keywords": [ | ||
"scripts": { | ||
"test": "node_modules/.bin/mocha --compilers js:babel-register" | ||
"test": "mocha --require @babel/register" | ||
}, | ||
@@ -25,14 +25,11 @@ "author": "AMC Theatres", | ||
"dependencies": { | ||
"babel-types": "^6.6.0", | ||
"is-valid-path": "^0.1.1", | ||
"lodash.camelcase": "^4.3.0", | ||
"lodash.findkey": "^4.6.0", | ||
"lodash.kebabcase": "^4.1.1", | ||
"lodash.snakecase": "^4.1.1" | ||
"@babel/types": "^7.4", | ||
"is-valid-path": "^0.1.1" | ||
}, | ||
"devDependencies": { | ||
"babel-core": "^6.6.0", | ||
"babel-preset-es2015": "^6.6.0", | ||
"mocha": "^2.4.5" | ||
"@babel/core": "^7.4", | ||
"@babel/preset-env": "^7.4", | ||
"@babel/register": "^7.4.4", | ||
"mocha": "^6.1" | ||
} | ||
} |
159
README.md
@@ -68,18 +68,18 @@ # babel-plugin-transform-imports | ||
*In .babelrc:* | ||
`.babelrc`: | ||
```json | ||
{ | ||
"plugins": [ | ||
["transform-imports", { | ||
"react-bootstrap": { | ||
"transform": "react-bootstrap/lib/${member}", | ||
"preventFullImport": true | ||
}, | ||
"lodash": { | ||
"transform": "lodash/${member}", | ||
"preventFullImport": true | ||
} | ||
}] | ||
] | ||
"plugins": [ | ||
["transform-imports", { | ||
"react-bootstrap": { | ||
"transform": "react-bootstrap/lib/${member}", | ||
"preventFullImport": true | ||
}, | ||
"lodash": { | ||
"transform": "lodash/${member}", | ||
"preventFullImport": true | ||
} | ||
}] | ||
] | ||
} | ||
@@ -96,14 +96,14 @@ ``` | ||
.babelrc: | ||
`.babelrc`: | ||
```json | ||
{ | ||
"plugins": [ | ||
["transform-imports", { | ||
"my-library\/?(((\\w*)?\/?)*)": { | ||
"transform": "my-library/${1}/${member}", | ||
"preventFullImport": true | ||
} | ||
}] | ||
] | ||
"plugins": [ | ||
["transform-imports", { | ||
"my-library\/?(((\\w*)?\/?)*)": { | ||
"transform": "my-library/${1}/${member}", | ||
"preventFullImport": true | ||
} | ||
}] | ||
] | ||
} | ||
@@ -132,55 +132,28 @@ ``` | ||
If you need more advanced or more specific transformation logic, and are using | ||
Babel 7+ with a `.babelrc.js` file, you may provide a function instead of a | ||
Babel 7+ with a `babel.config.js` file, you may provide a function instead of a | ||
string for the `transform` option: | ||
.babelrc.js: | ||
`babel.config.js`: | ||
```javascript | ||
module.exports = { | ||
presets: ['@babel/env'], | ||
plugins: [ | ||
['transform-imports', { | ||
'my-library': { | ||
transform: function(importName, matches) { | ||
return `my-library/etc/${importName.toUpperCase()}`; | ||
}, | ||
preventFullImport: true, | ||
} | ||
}] | ||
] | ||
presets: ['@babel/env'], | ||
plugins: [ | ||
['transform-imports', { | ||
'my-library': { | ||
transform: (importName, matches) => `my-library/etc/${importName.toUpperCase()}`, | ||
preventFullImport: true, | ||
}, | ||
'date-fns': { | ||
transform: importName => `date-fns/${camelCase(importName)}`, | ||
preventFullImport: true, | ||
}, | ||
}] | ||
] | ||
}; | ||
``` | ||
### Using a transformation file | ||
You may combine a regular expression in the library name with a function | ||
transform, and any captures of the regex will be passed as a second argument. | ||
If you need the above flexibility of using a function as a transformer, but | ||
are still on Babel 6 or cannot use a `.babelrc.js` file for some reason, you | ||
may provide a path to a .js file which exports a function to run instead. | ||
Keep in mind that the .js file will be `require`d relative from this plugin's | ||
path, likely located in `/node_modules/babel-plugin-transform-imports`. You | ||
may provide any filename, as long as it ends with `.js`. | ||
.babelrc: | ||
```json | ||
{ | ||
"plugins": [ | ||
["transform-imports", { | ||
"my-library": { | ||
"transform": "../../path/to/transform.js", | ||
"preventFullImport": true | ||
} | ||
}] | ||
] | ||
} | ||
``` | ||
/path/to/transform.js: | ||
```javascript | ||
module.exports = function(importName, matches) { | ||
return 'my-library/etc/' + importName.toUpperCase(); | ||
}; | ||
``` | ||
## Webpack | ||
@@ -193,24 +166,37 @@ | ||
module: { | ||
rules: [{ | ||
test: /\.js$/, | ||
exclude: /(node_modules|bower_components)/, | ||
use: { | ||
loader: 'babel-loader', | ||
query: { | ||
plugins: [ | ||
[require('babel-plugin-transform-imports'), { | ||
'my-library': { | ||
transform: function(importName, matches) { | ||
return 'my-library/etc/' + importName.toUpperCase(); | ||
}, | ||
preventFullImport: true | ||
} | ||
}] | ||
] | ||
rules: [{ | ||
test: /\.js$/, | ||
exclude: /(node_modules|bower_components)/, | ||
use: { | ||
loader: 'babel-loader', | ||
query: { | ||
plugins: [ | ||
[require('babel-plugin-transform-imports'), { | ||
'my-library': { | ||
transform: function(importName, matches) { | ||
return 'my-library/etc/' + importName.toUpperCase(); | ||
}, | ||
preventFullImport: true | ||
} | ||
} | ||
}] | ||
}] | ||
] | ||
} | ||
} | ||
}] | ||
} | ||
``` | ||
## Version 2.0 Breaking Changes | ||
Version 2.0 of this plugin targets Babel 7. Since Babel 7 allows for JS inside | ||
the config via `.babelrc.js` or `babel.config.js`, the specialized transforms | ||
`camelCase`, `kebabCase`, and `snakeCase` have been dropped. If you still need | ||
this functionality, you can import `lodash` directly in your config file and | ||
use those functions as part of a return value passed to the `transform` function | ||
(see *Using a function as the transformer* above). | ||
If you are on Babel 6, this plugin should still work, but if you need the prior | ||
specialized functionality, please use the ^1.0.0 version of this library and | ||
see the documentation located [here](https://bitbucket.org/amctheatres/babel-transform-imports/src/babel6/README.md). | ||
## Options | ||
@@ -220,7 +206,4 @@ | ||
| --- | --- | --- | --- | --- | | ||
| `transform` | `string | function` | yes | `undefined` | The library name to use instead of the one specified in the import statement. ${member} will be replaced with the import name, aka Grid/Row/Col/etc., and ${1-n} will be replaced by any matched regular expression groups. Alternatively, pass a path to a .js file which exports a function to process the transform, which is invoked with parameters: (importName, matches). If using Babel 7+, a function may be passed directly. (see Advanced Transformations) | | ||
| `transform` | `string or function` | yes | `undefined` | The library name to use instead of the one specified in the import statement. ${member} will be replaced with the import name, aka Grid/Row/Col/etc., and ${1-n} will be replaced by any matched regular expression groups. If using a JS Babel config file, a function may be passed directly. (see Advanced Transformations) | | ||
| `preventFullImport` | `boolean` | no | `false` | Whether or not to throw when an import is encountered which would cause the entire module to be imported. | | ||
| `camelCase` | `boolean` | no | `false` | When set to true, runs ${member} through _.camelCase. | | ||
| `kebabCase` | `boolean` | no | `false` | When set to true, runs ${member} through _.kebabCase. | | ||
| `snakeCase` | `boolean` | no | `false` | When set to true, runs ${member} through _.snakeCase. | | ||
| `skipDefaultConversion` | `boolean` | no | `false` | When set to true, will preserve `import { X }` syntax instead of converting to `import X`. | |
import assert from 'assert'; | ||
import * as babel from 'babel-core'; | ||
import * as babel from '@babel/core'; | ||
import path from 'path'; | ||
function createOptions({ | ||
preventFullImport = false, | ||
transform = 'react-bootstrap/lib/${member}', | ||
camelCase = false, | ||
kebabCase = false, | ||
snakeCase = false, | ||
skipDefaultConversion = false, | ||
libraryName = 'react-bootstrap' | ||
preventFullImport, | ||
transform = 'react-bootstrap/lib/${member}', | ||
skipDefaultConversion, | ||
libraryName = 'react-bootstrap' | ||
}) { | ||
return { | ||
[libraryName]: { transform, preventFullImport, camelCase, kebabCase, snakeCase, skipDefaultConversion } | ||
}; | ||
return { | ||
[libraryName]: { transform, preventFullImport, skipDefaultConversion } | ||
}; | ||
}; | ||
const fullImportRegex = /require\('react-bootstrap'\);$/gm; | ||
const memberImportRegex = /require\('react-bootstrap\/lib\/.+'\);$/gm; | ||
function occurrences(regex, test) { | ||
return (test.match(regex) || []).length; | ||
} | ||
function transform(code, options = createOptions({})) { | ||
return babel.transform(code, { | ||
presets: ['es2015'], | ||
plugins: [['./index', options]] | ||
}).code; | ||
return babel.transform(code, { | ||
presets: [['@babel/preset-env', { modules: false }]], | ||
plugins: [['./index', options]] | ||
}).code; | ||
} | ||
describe('import transformations', function() { | ||
it('should handle default imports', function() { | ||
const code = transform(`import Bootstrap from 'react-bootstrap';`); | ||
describe('import transformations', function () { | ||
it('should handle default imports', function () { | ||
const code = transform(`import Bootstrap from 'react-bootstrap';`); | ||
assert.equal(code, "import Bootstrap from 'react-bootstrap';"); | ||
}); | ||
assert.equal(occurrences(fullImportRegex, code), 1, 'number of full imports should be 1'); | ||
assert.equal(occurrences(memberImportRegex, code), 0, 'number of member imports should be 0'); | ||
}); | ||
it('should handle namespace imports', function () { | ||
const code = transform(`import * as Bootstrap from 'react-bootstrap';`); | ||
assert.equal(code, "import * as Bootstrap from 'react-bootstrap';"); | ||
}); | ||
it('should handle namespace imports', function() { | ||
const code = transform(`import * as Bootstrap from 'react-bootstrap';`); | ||
it('should handle member imports', function () { | ||
const code = transform(`import { Grid, Row as row } from 'react-bootstrap';`); | ||
assert.equal(code, [ | ||
'import Grid from "react-bootstrap/lib/Grid";', | ||
'import row from "react-bootstrap/lib/Row";', | ||
].join("\n")) | ||
}); | ||
assert.equal(occurrences(fullImportRegex, code), 1, 'number of full imports should be 1'); | ||
assert.equal(occurrences(memberImportRegex, code), 0, 'number of member imports should be 0'); | ||
}); | ||
it('should handle a mix of member and default import styles', function () { | ||
const code = transform(`import Bootstrap, { Grid, Row as row } from 'react-bootstrap';`); | ||
assert.equal(code, [ | ||
'import Bootstrap from "react-bootstrap";', | ||
'import Grid from "react-bootstrap/lib/Grid";', | ||
'import row from "react-bootstrap/lib/Row";', | ||
].join("\n")) | ||
}); | ||
it('should handle member imports', function() { | ||
const code = transform(`import { Grid, Row as row } from 'react-bootstrap';`); | ||
it('should handle relative filenames', function () { | ||
const libraryName = path.join(__dirname, '../local/path'); | ||
const _transform = path.join(__dirname, '../local/path/${member}'); | ||
const options = createOptions({ libraryName, transform: _transform }) | ||
const code = transform(`import { LocalThing } from './local/path'`, options); | ||
assert.equal(occurrences(fullImportRegex, code), 0, 'number of full imports should be 0'); | ||
assert.equal(occurrences(memberImportRegex, code), 2, 'number of member imports should be 2'); | ||
}); | ||
// The slash replaces below are for cross platform compatibility | ||
assert.equal(code.replace(/\\\\/g, '/'), `import LocalThing from "${libraryName.replace(/\\/g, '/')}/LocalThing";`); | ||
}); | ||
it('should handle a mix of member and default import styles', function() { | ||
const code = transform(`import Bootstrap, { Grid, Row as row } from 'react-bootstrap';`); | ||
it('should handle relative files with regex expressions', function () { | ||
const libraryName = '((\.{1,2}\/?)*)\/local\/path'; | ||
const _transform = '${1}/local/path/${member}'; | ||
const options = createOptions({ libraryName, transform: _transform }) | ||
const code = transform(`import { LocalThing } from '../../local/path'`, options); | ||
assert.equal(code, 'import LocalThing from "../../local/path/LocalThing";'); | ||
}); | ||
assert.equal(occurrences(fullImportRegex, code), 1, 'number of full imports should be 1'); | ||
assert.equal(occurrences(memberImportRegex, code), 2, 'number of member imports should be 2'); | ||
}); | ||
it('should handle relative filenames', function() { | ||
const libraryName = path.join(__dirname, '../local/path'); | ||
const _transform = path.join(__dirname, '../local/path/${member}'); | ||
const options = createOptions({ libraryName, transform: _transform }) | ||
const code = transform(`import { LocalThing } from './local/path'`, options); | ||
assert.equal(/require\('.*LocalThing'\);$/m.test(code), true, 'LocalThing should be directly required'); | ||
}); | ||
it('should handle relative files with regex expressions', function() { | ||
const libraryName = '((\.{1,2}\/?)*)\/local\/path'; | ||
const _transform = '${1}/local/path/${member}'; | ||
const options = createOptions({ libraryName, transform: _transform }) | ||
const code = transform(`import { LocalThing } from '../../local/path'`, options); | ||
assert.equal(/require\('\.\.\/\.\.\/local\/path\/LocalThing'\);$/m.test(code), true, 'regex is transformed'); | ||
}); | ||
it('should handle regex expressions', function() { | ||
const libraryName = 'package-(\\w+)\/?(((\\w*)?\/?)*)'; | ||
const _transform = 'package-${1}/${2}/${member}'; | ||
const options = createOptions({ libraryName, transform: _transform }) | ||
const code = transform(`import { LocalThing } from 'package-one/local/path'`, options); | ||
assert.equal(/require\('package-one\/local\/path\/LocalThing'\);$/m.test(code), true, 'regex is transformed'); | ||
}); | ||
it('should handle regex expressions', function () { | ||
const libraryName = 'package-(\\w+)\/?(((\\w*)?\/?)*)'; | ||
const _transform = 'package-${1}/${2}/${member}'; | ||
const options = createOptions({ libraryName, transform: _transform }) | ||
const code = transform(`import { LocalThing } from 'package-one/local/path'`, options); | ||
assert.equal(code, 'import LocalThing from "package-one/local/path/LocalThing";') | ||
}); | ||
}); | ||
describe('camelCase plugin option', function() { | ||
it('should use camel casing when set', function() { | ||
const options = createOptions({ camelCase: true }); | ||
describe('transform as function', function () { | ||
it('should call the transform as a function when provided as so', function () { | ||
const options = createOptions({ transform: function (input) { return `path/${input}`; } }); | ||
const code = transform(`import { CamelMe } from 'react-bootstrap';`, options); | ||
const code = transform(`import { somePath } from 'react-bootstrap';`, options); | ||
assert.notEqual(code.indexOf('camelMe'), -1, 'member name CamelMe should be transformed to camelMe'); | ||
}); | ||
assert.notEqual(code.indexOf('path/somePath'), -1, 'function should transform somePath to path/somePath'); | ||
}); | ||
}); | ||
describe('kebabCase plugin option', function() { | ||
it('should use kebab casing when set', function() { | ||
const options = createOptions({ kebabCase: true }); | ||
describe('preventFullImport plugin option', function () { | ||
it('should throw on default imports when truthy', function () { | ||
const options = createOptions({ preventFullImport: true }); | ||
const code = transform(`import { KebabMe } from 'react-bootstrap';`, options); | ||
assert.throws(() => { transform(`import Bootstrap from 'react-bootstrap';`, options) }); | ||
}); | ||
assert.notEqual(code.indexOf('kebab-me'), -1, 'member name KababMe should be transformed to kebab-me'); | ||
}); | ||
}); | ||
it('should throw on namespace imports when truthy', function () { | ||
const options = createOptions({ preventFullImport: true }); | ||
describe('snakeCase plugin option', function() { | ||
it('should use snake casing when set', function() { | ||
const options = createOptions({ snakeCase: true }); | ||
assert.throws(() => { transform(`import * as Bootstrap from 'react-bootstrap';`, options) }); | ||
}); | ||
const code = transform(`import { SnakeMe } from 'react-bootstrap';`, options); | ||
it('should not throw on member imports when truthy', function () { | ||
const options = createOptions({ preventFullImport: true }); | ||
assert.notEqual(code.indexOf('snake_me'), -1, 'member name SnakeMe should be transformed to snake_me'); | ||
}); | ||
assert.doesNotThrow(() => { transform(`import { Grid, Row as row } from 'react-bootstrap';`, options) }); | ||
}); | ||
}); | ||
describe('transform as function', function() { | ||
it('should throw when provided filename is invalid', function() { | ||
const options = createOptions({ transform: 'missingFile.js' }); | ||
describe('skipDefaultConversion plugin option', function () { | ||
it('should retain named import syntax when enabled', function () { | ||
const options = createOptions({ skipDefaultConversion: true }); | ||
assert.throws(() => {transform(`import { Row } from 'react-bootstrap';`, options)}); | ||
}); | ||
const code = transform(`import { Grid, Row as row } from 'react-bootstrap';`, options); | ||
it('should throw when provided filename does not resolve to a function', function() { | ||
const options = createOptions({ transform: './test/invalidTransform.js' }); | ||
assert.throws(() => {transform(`import { Row } from 'react-bootstrap';`, options)}); | ||
}); | ||
it('should properly execute transform function when provided', function() { | ||
const options = createOptions({ transform: './test/transform.js' }); | ||
const code = transform(`import { upperCaseMe } from 'react-bootstrap';`, options); | ||
assert.notEqual(code.indexOf('UPPERCASEME'), -1, 'member name upperCaseMe should be transformed to UPPERCASEME'); | ||
}); | ||
it('should call the transform as a function when provided as so', function() { | ||
const options = createOptions({ transform: function(input) { return `path/${input}`; } }); | ||
const code = transform(`import { somePath } from 'react-bootstrap';`, options); | ||
assert.notEqual(code.indexOf('path/somePath'), -1, 'function should transform somePath to path/somePath'); | ||
}); | ||
assert.equal(code.indexOf('_interopRequireDefault'), -1, 'skipDefaultConversion should not allow conversion to default import'); | ||
}) | ||
}); | ||
describe('preventFullImport plugin option', function() { | ||
it('should throw on default imports when truthy', function() { | ||
const options = createOptions({ preventFullImport: true }); | ||
describe('edge cases', function () { | ||
it('should throw when transform plugin option is missing', function () { | ||
const options = createOptions({ transform: null }); | ||
assert.throws(() => {transform(`import Bootstrap from 'react-bootstrap';`, options)}); | ||
}); | ||
it('should throw on namespace imports when truthy', function() { | ||
const options = createOptions({ preventFullImport: true }); | ||
assert.throws(() => {transform(`import * as Bootstrap from 'react-bootstrap';`, options)}); | ||
}); | ||
it('should not throw on member imports when truthy', function() { | ||
const options = createOptions({ preventFullImport: true }); | ||
assert.doesNotThrow(() => {transform(`import { Grid, Row as row } from 'react-bootstrap';`, options)}); | ||
}); | ||
assert.throws(() => { transform(`import Bootstrap from 'react-bootstrap';`, options) }); | ||
}); | ||
}); | ||
describe('skipDefaultConversion plugin option', function() { | ||
it('should retain named import syntax when enabled', function() { | ||
const options = createOptions({ skipDefaultConversion: true }); | ||
const code = transform(`import { Grid, Row as row } from 'react-bootstrap';`, options); | ||
assert.equal(code.indexOf('_interopRequireDefault'), -1, 'skipDefaultConversion should not allow conversion to default import'); | ||
}) | ||
}); | ||
describe('edge cases', function() { | ||
it('should throw when transform plugin option is missing', function() { | ||
const options = createOptions({ transform: null }); | ||
assert.throws(() => {transform(`import Bootstrap from 'react-bootstrap';`, options)}); | ||
}); | ||
}); |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
2
0
17073
4
5
214
205
+ Added@babel/types@^7.4
+ Added@babel/helper-string-parser@7.25.9(transitive)
+ Added@babel/helper-validator-identifier@7.25.9(transitive)
+ Added@babel/types@7.26.5(transitive)
- Removedbabel-types@^6.6.0
- Removedlodash.camelcase@^4.3.0
- Removedlodash.findkey@^4.6.0
- Removedlodash.kebabcase@^4.1.1
- Removedlodash.snakecase@^4.1.1
- Removedbabel-runtime@6.26.0(transitive)
- Removedbabel-types@6.26.0(transitive)
- Removedcore-js@2.6.12(transitive)
- Removedesutils@2.0.3(transitive)
- Removedlodash@4.17.21(transitive)
- Removedlodash.camelcase@4.3.0(transitive)
- Removedlodash.findkey@4.6.0(transitive)
- Removedlodash.kebabcase@4.1.1(transitive)
- Removedlodash.snakecase@4.1.1(transitive)
- Removedregenerator-runtime@0.11.1(transitive)
- Removedto-fast-properties@1.0.3(transitive)