babel-plugin-zent
Advanced tools
Comparing version 1.0.0-beta10 to 1.0.0-beta11
218
lib/index.js
'use strict'; | ||
var _isEmpty = require('lodash/isEmpty'); | ||
var MODULE_NAME = 'zent'; | ||
var _isEmpty2 = _interopRequireDefault(_isEmpty); | ||
// Errors: | ||
// import 'zent'; | ||
// import * as Zent from 'zent'; | ||
// import Zent from 'zent'; | ||
// require('zent'); | ||
// | ||
// | ||
// Ingore: | ||
// import Button from 'zent/button'; | ||
// import Button from 'zent-button'; | ||
// require('zent-button') | ||
module.exports = function (babel) { | ||
var t = babel.types; | ||
var _flatten = require('lodash/flatten'); | ||
var _flatten2 = _interopRequireDefault(_flatten); | ||
return { | ||
visitor: { | ||
CallExpression(path) { | ||
var node = path.node; | ||
var _uniq = require('lodash/uniq'); | ||
// no require('zent') calls | ||
var _uniq2 = _interopRequireDefault(_uniq); | ||
if (t.isIdentifier(node.callee, { name: 'require' }) && node.arguments && node.arguments.length === 1) { | ||
var source = node.arguments[0]; | ||
if (t.isStringLiteral(source, { value: MODULE_NAME })) { | ||
throw path.buildCodeFrameError(`require('${MODULE_NAME}') is not allowed, use import { ... } from '${MODULE_NAME}'`); | ||
} | ||
} | ||
}, | ||
var _sortBy = require('lodash/sortBy'); | ||
ImportDeclaration(path, state) { | ||
var node = path.node; | ||
var _sortBy2 = _interopRequireDefault(_sortBy); | ||
var _sortedIndexOf = require('lodash/sortedIndexOf'); | ||
if (t.isStringLiteral(node.source, { value: MODULE_NAME })) { | ||
var specifiers = node.specifiers; | ||
var _sortedIndexOf2 = _interopRequireDefault(_sortedIndexOf); | ||
var specifierCount = specifiers.length; | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
// no import 'zent'; | ||
if (specifierCount === 0) { | ||
throw path.buildCodeFrameError(`Side-effect only import is allowed in ${MODULE_NAME}.'`); | ||
} | ||
var moduleName = 'zent'; | ||
var moduleMapping = {}; | ||
var requireWhitelist = []; | ||
var replacement = specifiers.reduce(function (r, sp) { | ||
// no import * as Zent from 'zent' | ||
if (t.isImportNamespaceSpecifier(sp)) { | ||
throw path.buildCodeFrameError(`Namespace import is not allowd in ${MODULE_NAME}, pick the components you need.`); | ||
} | ||
function replaceRules(name) { | ||
if (moduleMapping.hasOwnProperty(name)) { | ||
return moduleMapping[name].js; | ||
} | ||
return name; | ||
} | ||
// no import Zent from 'zent' | ||
if (t.isImportDefaultSpecifier(sp)) { | ||
throw path.buildCodeFrameError(`There is no default export in ${MODULE_NAME}.`); | ||
} | ||
function initModuleMapping(options) { | ||
var moduleMappingFile = options.moduleMappingFile || 'zent/lib/module-mapping.json'; | ||
if (t.isImportSpecifier(sp)) { | ||
return r.concat(buildImportReplacement(sp.imported.name, t, state)); | ||
} | ||
// eslint-disable-next-line | ||
moduleMapping = require(moduleMappingFile); | ||
requireWhitelist = (0, _sortBy2.default)((0, _uniq2.default)((0, _flatten2.default)(Object.keys(moduleMapping).map(function (k) { | ||
var v = moduleMapping[k]; | ||
return [].concat(v.js, v.css); | ||
})))); | ||
} | ||
throw path.buildCodeFrameError('Unexpected import type'); | ||
}, []); | ||
function isRequireInWhitelist(path) { | ||
return (0, _sortedIndexOf2.default)(requireWhitelist, path) !== -1; | ||
} | ||
path.replaceWithMultiple(replacement); | ||
} | ||
} | ||
} | ||
}; | ||
}; | ||
function capitalizeFirstLetter(string) { | ||
return string.charAt(0).toUpperCase() + string.slice(1); | ||
} | ||
function buildImportReplacement(name, types, state) { | ||
initModuleMapppingAsNecessary(state); | ||
// "Error: require('zent') is not allowed, use ES6 import instead." + "\n" + | ||
// "Error: namespace import is not allowed for zent, specify the components you need." + "\n" + | ||
// "Error: zent-button is no longer maintained, use `import { Button } from 'zent'` instead." + "\n" + | ||
// "Error: zent/button is no longer supported, use `import { Button } from 'zent'` instead." + "\n" + | ||
function log(value, path, isRequire) { | ||
var regexpZent = /^zent$/gi; | ||
var regexpSubPackage = /zent-/gi; | ||
var regexpSubDir = /^zent\/(?!lib\/)/gi; | ||
var replacement = []; | ||
var options = state.opts, | ||
data = state.data; | ||
if (isRequire) { | ||
if (regexpZent.test(value)) { | ||
throw path.buildCodeFrameError(`\nError: require('zent') is not allowed, use ES6 import instead.\n`); | ||
} else if (!isRequireInWhitelist(value)) { | ||
throw path.buildCodeFrameError(`\nError: require('${value}') incorrect require from zent.\n`); | ||
if (data.MODULE_MAPPING.hasOwnProperty(name)) { | ||
var rule = data.MODULE_MAPPING[name]; | ||
// js | ||
replacement.push(types.importDeclaration([types.importDefaultSpecifier(types.identifier(name))], types.stringLiteral(rule.js))); | ||
// css | ||
if (options.automaticStyleImport) { | ||
rule.css.forEach(function (path) { | ||
if (data.CSS_IMPORT_MAPPING[path] === 0) { | ||
replacement.push(types.importDeclaration([], types.stringLiteral(path))); | ||
data.CSS_IMPORT_MAPPING[path] += 1; | ||
} | ||
}); | ||
} | ||
} else { | ||
// eslint-disable-next-line | ||
if (regexpZent.test(value)) { | ||
throw path.buildCodeFrameError(`\nError: namespace import is not allowed for Zent, pick the components you need.\n`); | ||
} else if (regexpSubPackage.test(value)) { | ||
var idx = value.indexOf('-'); | ||
var name = value.substr(idx + 1); | ||
var newName = capitalizeFirstLetter(name); | ||
throw path.buildCodeFrameError(`\nError: ${value} is no longer maintained, use " import { ${newName} } from 'zent' " instead.\n`); | ||
} else if (regexpSubDir.test(value)) { | ||
var _idx = value.indexOf('/'); | ||
var _name = value.substr(_idx + 1); | ||
var _newName = capitalizeFirstLetter(_name); | ||
throw path.buildCodeFrameError(`\nError: ${value} is no longer supported, use " import { ${_newName} } from 'zent' " instead.\n`); | ||
} | ||
} | ||
return replacement; | ||
} | ||
module.exports = function (babel) { | ||
var types = babel.types; | ||
function initModuleMapppingAsNecessary(state) { | ||
var options = state.opts; | ||
return { | ||
visitor: { | ||
CallExpression(path) { | ||
var node = path.node; | ||
var callee = node.callee; | ||
var arg = node.arguments[0]; | ||
if (callee.type !== 'Identifier' || callee.name !== 'require' || !arg) { | ||
return; | ||
} | ||
var args = node.arguments || []; | ||
if (callee.name === 'require' && args.length === 1 && types.isStringLiteral(args[0])) { | ||
var reg = /(^zent\/)/gi; | ||
if (args[0].value === moduleName) { | ||
log(`${args[0].value}`, path, true); | ||
} else if (reg.test(args[0].value)) { | ||
log(`${args[0].value}`, path, true); | ||
} | ||
} | ||
}, | ||
if (!state.data) { | ||
state.data = {}; | ||
} | ||
ImportDeclaration(path, state) { | ||
if ((0, _isEmpty2.default)(moduleMapping)) { | ||
initModuleMapping(state.opts); | ||
} | ||
var data = state.data; | ||
if (!data.MODULE_MAPPING) { | ||
var moduleMappingFile = options.moduleMappingFile || 'zent/lib/module-mapping.json'; | ||
var source = path.node.source; | ||
var fullImports = path.node.specifiers.filter(function (specifier) { | ||
return specifier.type !== 'ImportSpecifier'; | ||
// eslint-disable-next-line | ||
data.MODULE_MAPPING = require(moduleMappingFile); | ||
if (options.automaticStyleImport) { | ||
data.CSS_IMPORT_MAPPING = Object.keys(data.MODULE_MAPPING).reduce(function (mapping, key) { | ||
data.MODULE_MAPPING[key].css.forEach(function (path) { | ||
mapping[path] = 0; | ||
}); | ||
var importSpecifiers = path.node.specifiers.filter(function (specifier) { | ||
return specifier.type === 'ImportSpecifier'; | ||
}); | ||
if (fullImports.length > 0) { | ||
if (importSpecifiers.length === 0) { | ||
var reg = /(^zent$|^zent-|^zent\/)/gi; | ||
if (reg.test(source.value)) { | ||
log(source.value, path); | ||
} | ||
} | ||
} | ||
var newImportDeclarations = []; | ||
if (importSpecifiers.length > 0 && source.value === moduleName) { | ||
importSpecifiers.forEach(function (importSpecifier) { | ||
var importedName = importSpecifier.imported.name; | ||
if (moduleMapping.hasOwnProperty(importedName)) { | ||
var newImportedName = replaceRules(importedName); | ||
var newImportDeclaration = types.importDeclaration([types.importDefaultSpecifier(types.identifier(importedName))], types.stringLiteral(newImportedName)); | ||
newImportDeclarations.push(newImportDeclaration); | ||
} | ||
}); | ||
} | ||
if (newImportDeclarations.length > 0) { | ||
path.replaceWithMultiple(newImportDeclarations); | ||
} | ||
} | ||
return mapping; | ||
}, {}); | ||
} | ||
}; | ||
}; | ||
} | ||
} |
{ | ||
"name": "babel-plugin-zent", | ||
"version": "1.0.0-beta10", | ||
"version": "1.0.0-beta11", | ||
"main": "lib/index.js", | ||
@@ -8,4 +8,3 @@ "license": "MIT", | ||
"build": "rm -rf lib && babel src --out-dir lib", | ||
"watch": "rm -rf lib && babel src --out-dir lib --watch", | ||
"test": "babel spec/index.js --out-file spec/index-compiled.js", | ||
"test": "./scripts/test.sh", | ||
"prepublish": "yarn build" | ||
@@ -18,9 +17,10 @@ }, | ||
"babel-cli": "^6.24.1", | ||
"babel-core": "^6.24.1", | ||
"babel-plugin-transform-runtime": "^6.23.0", | ||
"babel-preset-env": "^1.4.0" | ||
"babel-preset-env": "^1.4.0", | ||
"jest": "^19.0.2" | ||
}, | ||
"dependencies": { | ||
"babel-runtime": "^6.23.0", | ||
"lodash": "^4.17.4" | ||
"babel-runtime": "^6.23.0" | ||
} | ||
} |
@@ -15,7 +15,7 @@ ## babel-plugin-zent | ||
- Automatic component JavaScript import rewrite | ||
- [TODO] Automatically import styles for the components you use | ||
- Automatically import styles for the components you use | ||
### Usage | ||
`yarn add babel-plugin-zent -D` | ||
`yarn add zent babel-plugin-zent -D` | ||
@@ -48,3 +48,1 @@ Configuration example: | ||
If `automaticStyleImport` is `true`, import styles for component. | ||
**Note:** `automaticStyleImport` is not implemented yet. |
1
4880
5
96
47
- Removedlodash@^4.17.4
- Removedlodash@4.17.21(transitive)