UNPKG

4.48 kBJavaScriptView Raw
1var _ = require("lodash");
2var path = require("path");
3var babel = require("babel-standalone");
4
5/**
6 * A Babel plugin as defined in `babelOptions.plugins`
7 * @typedef {string|Function|<string, Object>[]|<Function, Object>[]} BabelPlugin
8 */
9
10/**
11 * The options needed to load the babel plugins not bundled in babel-standalone
12 * @typedef {Object} LoadCustomPluginsOptions
13 * @property {string} baseURL The loader baseURL value
14 * @property {string} loaderEnv The loader env value
15 * @property {Object} babelOptions The babel configuration options
16 */
17
18/**
19 * Returns a list of babel plugins to be used by transpile
20 * @param {LoadCustomPluginsOptions} opts The options object
21 * @return {BabelPlugin[]} The list of plugins to be used by transpile
22 */
23module.exports = function(opts) {
24 var processed = [];
25 var babelOptions = opts.babelOptions || {};
26 var babelEnvConfig = babelOptions.env || {};
27
28 var babelEnv = process.env.BABEL_ENV ||
29 process.env.NODE_ENV ||
30 opts.loaderEnv;
31
32 // process plugins in babelOptions.plugins
33 processed = processed.concat(processPlugins(opts.baseURL, babelOptions.plugins));
34
35 // process environment dependant plugins
36 _.keys(babelEnvConfig).forEach(function(envName) {
37 if (envName === babelEnv) {
38 var plugins = babelEnvConfig[envName].plugins || [];
39 processed = processed.concat(processPlugins(opts.baseURL, plugins));
40 }
41 });
42
43 return processed;
44};
45
46/**
47 * Collect builtin plugin names and non builtin plugin functions
48 * @param {string} baseURL The loader baseURL value
49 * @param {BabelPlugin[]} plugins An array of babel plugins
50 * @return {BabelPlugin[]} An array of babel plugins filtered by the babel
51 * environment name and with non-builtins replaced
52 * by their respective functions
53 */
54function processPlugins(baseURL, plugins) {
55 var normalized = [];
56
57 // path.resolve does not work correctly if baseURL starts with "file:"
58 baseURL = baseURL.replace("file:", "");
59 plugins = plugins || [];
60
61 plugins.forEach(function(plugin) {
62 var name = getPluginName(plugin);
63
64 if (isPluginFunction(plugin) || isBuiltinPlugin(name)) {
65 normalized.push(plugin);
66 }
67 else if (!isBuiltinPlugin(name)) {
68 var npmPluginNameOrPath = getNpmPluginNameOrPath(baseURL, name);
69
70 // load the plugin!
71 var pluginFn = require(npmPluginNameOrPath);
72
73 if (_.isString(plugin)) {
74 normalized.push(pluginFn);
75 }
76 else if (_.isArray(plugin)) {
77 // [ pluginName, pluginOptions ]
78 normalized.push([pluginFn, plugin[1]]);
79 }
80 }
81 });
82
83 return normalized;
84}
85
86/**
87 * Whether the plugin function was provided instead of the plugin name
88 * @param {BabelPlugin} plugin
89 * @return {boolean} `true` if a plugin function was provided, `false` otherwise
90 */
91function isPluginFunction(plugin) {
92 return _.isFunction(plugin) || _.isFunction(_.head(plugin));
93}
94
95function getNpmPluginNameOrPath(baseURL, name) {
96 var isPath = /\//;
97 var isNpmPluginName = /^(?:babel-plugin-)/;
98
99 if (isPath.test(name)) {
100 return path.resolve(baseURL, name);
101 }
102 else if (!isNpmPluginName.test(name)) {
103 return "babel-plugin-" + name;
104 }
105
106 return name;
107}
108
109/**
110 * Gets the plugin name
111 * @param {BabelPlugin} plugin An item inside of `babelOptions.plugins`
112 * @return {?string} The plugin name
113 */
114function getPluginName(plugin) {
115 if (isPluginFunction(plugin)) return null;
116
117 return _.isString(plugin) ? plugin : _.head(plugin);
118}
119
120/**
121 * Whether the plugin is built in babel-standalone
122 *
123 * @param {string} name A plugin path or shorthand name.
124 * @return {boolean} `true` if plugin is bundled, `false` otherwise
125 *
126 * Babel plugins can be set using the following variations:
127 *
128 * 1) the npm plugin name, which by convention starts with `babel-plugin-`
129 * (e.g babel-plugin-transform-decorators).
130 * 2) A shorthand name, which is the npm name without the `babel-plugin-` prefix
131 * 3) A path to where the plugin function is defined
132 *
133 * babel-standalone registers the plugins bundled with it using the shorthand
134 * version.
135 */
136function isBuiltinPlugin(name) {
137 var isNpmPluginName = /^(?:babel-plugin-)/;
138 var availablePlugins = babel.availablePlugins;
139
140 // if the full npm plugin name was set in `babelOptions.plugins`, use the
141 // shorthand to check whether the plugin is included in babel-standalone;
142 // shorthand plugin names are used internally by babel-standalone
143 var shorthand = isNpmPluginName.test(name) ?
144 name.replace("babel-plugin-", "") :
145 name;
146
147 return !!availablePlugins[shorthand];
148}