UNPKG

14.3 kBJavaScriptView Raw
1import * as Babel from 'babel-core';
2
3import {runScripts} from './transformScriptTags';
4
5const isArray = Array.isArray || (arg => Object.prototype.toString.call(arg) === '[object Array]');
6
7/**
8 * Loads the given name (or [name, options] pair) from the given table object
9 * holding the available presets or plugins.
10 *
11 * Returns undefined if the preset or plugin is not available; passes through
12 * name unmodified if it (or the first element of the pair) is not a string.
13 */
14function loadBuiltin(builtinTable, name) {
15 if (isArray(name) && typeof name[0] === 'string') {
16 if (builtinTable.hasOwnProperty(name[0])) {
17 return [builtinTable[name[0]]].concat(name.slice(1));
18 }
19 return;
20 } else if (typeof name === 'string') {
21 return builtinTable[name];
22 }
23 // Could be an actual preset/plugin module
24 return name;
25}
26
27/**
28 * Parses plugin names and presets from the specified options.
29 */
30function processOptions(options) {
31 // Parse preset names
32 const presets = (options.presets || []).map(presetName => {
33 const preset = loadBuiltin(availablePresets, presetName);
34
35 if (preset) {
36 // workaround for babel issue
37 // at some point, babel copies the preset, losing the non-enumerable
38 // buildPreset key; convert it into an enumerable key.
39 if (isArray(preset) && typeof preset[0] === 'object' && preset[0].hasOwnProperty('buildPreset')) {
40 preset[0] = { ...preset[0], buildPreset: preset[0].buildPreset }
41 }
42 } else {
43 throw new Error(`Invalid preset specified in Babel options: "${presetName}"`);
44 }
45 return preset;
46 });
47
48 // Parse plugin names
49 const plugins = (options.plugins || []).map(pluginName => {
50 const plugin = loadBuiltin(availablePlugins, pluginName);
51
52 if (!plugin) {
53 throw new Error(`Invalid plugin specified in Babel options: "${pluginName}"`);
54 }
55 return plugin;
56 });
57
58 return {
59 babelrc: false,
60 ...options,
61 presets,
62 plugins,
63 }
64}
65
66export function transform(code, options) {
67 return Babel.transform(code, processOptions(options));
68}
69
70export function transformFromAst(ast, code, options) {
71 return Babel.transformFromAst(ast, code, processOptions(options));
72}
73export const availablePlugins = {};
74export const availablePresets = {};
75export const buildExternalHelpers = Babel.buildExternalHelpers;
76/**
77 * Registers a named plugin for use with Babel.
78 */
79export function registerPlugin(name, plugin) {
80 if (availablePlugins.hasOwnProperty(name)) {
81 console.warn(`A plugin named "${name}" is already registered, it will be overridden`);
82 }
83 availablePlugins[name] = plugin;
84}
85/**
86 * Registers multiple plugins for use with Babel. `newPlugins` should be an object where the key
87 * is the name of the plugin, and the value is the plugin itself.
88 */
89export function registerPlugins(newPlugins) {
90 Object.keys(newPlugins).forEach(name => registerPlugin(name, newPlugins[name]));
91}
92
93/**
94 * Registers a named preset for use with Babel.
95 */
96export function registerPreset(name, preset) {
97 if (availablePresets.hasOwnProperty(name)) {
98 console.warn(`A preset named "${name}" is already registered, it will be overridden`);
99 }
100 availablePresets[name] = preset;
101}
102/**
103 * Registers multiple presets for use with Babel. `newPresets` should be an object where the key
104 * is the name of the preset, and the value is the preset itself.
105 */
106export function registerPresets(newPresets) {
107 Object.keys(newPresets).forEach(name => registerPreset(name, newPresets[name]));
108}
109
110
111// All the plugins we should bundle
112registerPlugins({
113 'check-es2015-constants': require('babel-plugin-check-es2015-constants'),
114 'external-helpers': require('babel-plugin-external-helpers'),
115 'inline-replace-variables': require('babel-plugin-inline-replace-variables'),
116 'syntax-async-functions': require('babel-plugin-syntax-async-functions'),
117 'syntax-async-generators': require('babel-plugin-syntax-async-generators'),
118 'syntax-class-constructor-call': require('babel-plugin-syntax-class-constructor-call'),
119 'syntax-class-properties': require('babel-plugin-syntax-class-properties'),
120 'syntax-decorators': require('babel-plugin-syntax-decorators'),
121 'syntax-do-expressions': require('babel-plugin-syntax-do-expressions'),
122 'syntax-exponentiation-operator': require('babel-plugin-syntax-exponentiation-operator'),
123 'syntax-export-extensions': require('babel-plugin-syntax-export-extensions'),
124 'syntax-flow': require('babel-plugin-syntax-flow'),
125 'syntax-function-bind': require('babel-plugin-syntax-function-bind'),
126 'syntax-function-sent': require('babel-plugin-syntax-function-sent'),
127 'syntax-jsx': require('babel-plugin-syntax-jsx'),
128 'syntax-object-rest-spread': require('babel-plugin-syntax-object-rest-spread'),
129 'syntax-trailing-function-commas': require('babel-plugin-syntax-trailing-function-commas'),
130 'transform-async-functions': require('babel-plugin-transform-async-functions'),
131 'transform-async-to-generator': require('babel-plugin-transform-async-to-generator'),
132 'transform-async-to-module-method': require('babel-plugin-transform-async-to-module-method'),
133 'transform-class-constructor-call': require('babel-plugin-transform-class-constructor-call'),
134 'transform-class-properties': require('babel-plugin-transform-class-properties'),
135 'transform-decorators': require('babel-plugin-transform-decorators'),
136 'transform-decorators-legacy': require('babel-plugin-transform-decorators-legacy').default, // <- No clue. Nope.
137 'transform-do-expressions': require('babel-plugin-transform-do-expressions'),
138 'transform-es2015-arrow-functions': require('babel-plugin-transform-es2015-arrow-functions'),
139 'transform-es2015-block-scoped-functions': require('babel-plugin-transform-es2015-block-scoped-functions'),
140 'transform-es2015-block-scoping': require('babel-plugin-transform-es2015-block-scoping'),
141 'transform-es2015-classes': require('babel-plugin-transform-es2015-classes'),
142 'transform-es2015-computed-properties': require('babel-plugin-transform-es2015-computed-properties'),
143 'transform-es2015-destructuring': require('babel-plugin-transform-es2015-destructuring'),
144 'transform-es2015-duplicate-keys': require('babel-plugin-transform-es2015-duplicate-keys'),
145 'transform-es2015-for-of': require('babel-plugin-transform-es2015-for-of'),
146 'transform-es2015-function-name': require('babel-plugin-transform-es2015-function-name'),
147 'transform-es2015-instanceof': require('babel-plugin-transform-es2015-instanceof'),
148 'transform-es2015-literals': require('babel-plugin-transform-es2015-literals'),
149 'transform-es2015-modules-amd': require('babel-plugin-transform-es2015-modules-amd'),
150 'transform-es2015-modules-commonjs': require('babel-plugin-transform-es2015-modules-commonjs'),
151 'transform-es2015-modules-systemjs': require('babel-plugin-transform-es2015-modules-systemjs'),
152 'transform-es2015-modules-umd': require('babel-plugin-transform-es2015-modules-umd'),
153 'transform-es2015-object-super': require('babel-plugin-transform-es2015-object-super'),
154 'transform-es2015-parameters': require('babel-plugin-transform-es2015-parameters'),
155 'transform-es2015-shorthand-properties': require('babel-plugin-transform-es2015-shorthand-properties'),
156 'transform-es2015-spread': require('babel-plugin-transform-es2015-spread'),
157 'transform-es2015-sticky-regex': require('babel-plugin-transform-es2015-sticky-regex'),
158 'transform-es2015-template-literals': require('babel-plugin-transform-es2015-template-literals'),
159 'transform-es2015-typeof-symbol': require('babel-plugin-transform-es2015-typeof-symbol'),
160 'transform-es2015-unicode-regex': require('babel-plugin-transform-es2015-unicode-regex'),
161 'transform-es3-member-expression-literals': require('babel-plugin-transform-es3-member-expression-literals'),
162 'transform-es3-property-literals': require('babel-plugin-transform-es3-property-literals'),
163 'transform-es5-property-mutators': require('babel-plugin-transform-es5-property-mutators'),
164 'transform-eval': require('babel-plugin-transform-eval'),
165 'transform-exponentiation-operator': require('babel-plugin-transform-exponentiation-operator'),
166 'transform-export-extensions': require('babel-plugin-transform-export-extensions'),
167 'transform-flow-comments': require('babel-plugin-transform-flow-comments'),
168 'transform-flow-strip-types': require('babel-plugin-transform-flow-strip-types'),
169 'transform-function-bind': require('babel-plugin-transform-function-bind'),
170 'transform-jscript': require('babel-plugin-transform-jscript'),
171 'transform-object-assign': require('babel-plugin-transform-object-assign'),
172 'transform-object-rest-spread': require('babel-plugin-transform-object-rest-spread'),
173 'transform-object-set-prototype-of-to-assign': require('babel-plugin-transform-object-set-prototype-of-to-assign'),
174 'transform-proto-to-assign': require('babel-plugin-transform-proto-to-assign'),
175 'transform-react-constant-elements': require('babel-plugin-transform-react-constant-elements'),
176 'transform-react-display-name': require('babel-plugin-transform-react-display-name'),
177 'transform-react-inline-elements': require('babel-plugin-transform-react-inline-elements'),
178 'transform-react-jsx': require('babel-plugin-transform-react-jsx'),
179 'transform-react-jsx-compat': require('babel-plugin-transform-react-jsx-compat'),
180 'transform-react-jsx-self': require('babel-plugin-transform-react-jsx-self'),
181 'transform-react-jsx-source': require('babel-plugin-transform-react-jsx-source'),
182 'transform-regenerator': require('babel-plugin-transform-regenerator'),
183 'transform-runtime': require('babel-plugin-transform-runtime'),
184 'transform-strict-mode': require('babel-plugin-transform-strict-mode'),
185 'undeclared-variables-check': require('babel-plugin-undeclared-variables-check'),
186});
187
188// All the presets we should bundle
189registerPresets({
190 es2015: require('babel-preset-es2015'),
191 es2016: require('babel-preset-es2016'),
192 es2017: require('babel-preset-es2017'),
193 latest: require('babel-preset-latest'),
194 react: require('babel-preset-react'),
195 'stage-0': require('babel-preset-stage-0'),
196 'stage-1': require('babel-preset-stage-1'),
197 'stage-2': require('babel-preset-stage-2'),
198 'stage-3': require('babel-preset-stage-3'),
199
200 // ES2015 preset with es2015-modules-commonjs removed
201 // Plugin list copied from babel-preset-es2015/index.js
202 'es2015-no-commonjs': {
203 plugins: [
204 require("babel-plugin-transform-es2015-template-literals"),
205 require("babel-plugin-transform-es2015-literals"),
206 require("babel-plugin-transform-es2015-function-name"),
207 require("babel-plugin-transform-es2015-arrow-functions"),
208 require("babel-plugin-transform-es2015-block-scoped-functions"),
209 require("babel-plugin-transform-es2015-classes"),
210 require("babel-plugin-transform-es2015-object-super"),
211 require("babel-plugin-transform-es2015-shorthand-properties"),
212 require("babel-plugin-transform-es2015-computed-properties"),
213 require("babel-plugin-transform-es2015-for-of"),
214 require("babel-plugin-transform-es2015-sticky-regex"),
215 require("babel-plugin-transform-es2015-unicode-regex"),
216 require("babel-plugin-check-es2015-constants"),
217 require("babel-plugin-transform-es2015-spread"),
218 require("babel-plugin-transform-es2015-parameters"),
219 require("babel-plugin-transform-es2015-destructuring"),
220 require("babel-plugin-transform-es2015-block-scoping"),
221 require("babel-plugin-transform-es2015-typeof-symbol"),
222 [require("babel-plugin-transform-regenerator"), { async: false, asyncGenerators: false }],
223 ]
224 },
225
226 // ES2015 preset with plugins set to loose mode.
227 // Based off https://github.com/bkonkle/babel-preset-es2015-loose/blob/master/index.js
228 'es2015-loose': {
229 plugins: [
230 [require("babel-plugin-transform-es2015-template-literals"), { loose: true }],
231 require("babel-plugin-transform-es2015-literals"),
232 require("babel-plugin-transform-es2015-function-name"),
233 require("babel-plugin-transform-es2015-arrow-functions"),
234 require("babel-plugin-transform-es2015-block-scoped-functions"),
235 [require("babel-plugin-transform-es2015-classes"), { loose: true }],
236 require("babel-plugin-transform-es2015-object-super"),
237 require("babel-plugin-transform-es2015-shorthand-properties"),
238 require("babel-plugin-transform-es2015-duplicate-keys"),
239 [require("babel-plugin-transform-es2015-computed-properties"), { loose: true }],
240 [require("babel-plugin-transform-es2015-for-of"), { loose: true }],
241 require("babel-plugin-transform-es2015-sticky-regex"),
242 require("babel-plugin-transform-es2015-unicode-regex"),
243 require("babel-plugin-check-es2015-constants"),
244 [require("babel-plugin-transform-es2015-spread"), { loose: true }],
245 require("babel-plugin-transform-es2015-parameters"),
246 [require("babel-plugin-transform-es2015-destructuring"), { loose: true }],
247 require("babel-plugin-transform-es2015-block-scoping"),
248 require("babel-plugin-transform-es2015-typeof-symbol"),
249 [require("babel-plugin-transform-es2015-modules-commonjs"), { loose: true }],
250 [require("babel-plugin-transform-regenerator"), { async: false, asyncGenerators: false }],
251 ]
252 },
253});
254
255export const version = VERSION;
256
257// Listen for load event if we're in a browser and then kick off finding and
258// running of scripts with "text/babel" type.
259if (typeof window !== 'undefined' && window && window.addEventListener) {
260 window.addEventListener('DOMContentLoaded', () => transformScriptTags(), false);
261}
262
263/**
264 * Transform <script> tags with "text/babel" type.
265 * @param {Array} scriptTags specify script tags to transform, transform all in the <head> if not given
266 */
267export function transformScriptTags(scriptTags) {
268 runScripts(transform, scriptTags);
269}
270
271/**
272 * Disables automatic transformation of <script> tags with "text/babel" type.
273 */
274export function disableScriptTags() {
275 window.removeEventListener('DOMContentLoaded', transformScriptTags);
276}