UNPKG

4.71 kBJavaScriptView Raw
1"use strict";
2
3var stream = require("stream");
4var util = require("util");
5var path = require("path");
6
7let babel;
8try {
9 babel = require("@babel/core");
10} catch (err) {
11 if (err.code === "MODULE_NOT_FOUND") {
12 err.message +=
13 "\n babelify@10 requires Babel 7.x (the package '@babel/core'). " +
14 "If you'd like to use Babel 6.x ('babel-core'), you should install 'babelify@8'.";
15 }
16 throw err;
17}
18
19// Since we've got the reverse bridge package at @babel/core@6.x, give
20// people useful feedback if they try to use it alongside babel-loader.
21if (/^6\./.test(babel.version)) {
22 throw new Error(
23 "\n babelify@10 will not work with the '@babel/core@6' bridge package. " +
24 "If you want to use Babel 6.x, install 'babelify@8'."
25 );
26}
27
28module.exports = buildTransform();
29module.exports.configure = buildTransform;
30
31// Allow projects to import this module and check `foo instanceof babelify`
32// to see if the current stream they are working with is one created
33// by Babelify.
34Object.defineProperty(module.exports, Symbol.hasInstance, {
35 value: function hasInstance(obj) {
36 return obj instanceof BabelifyStream;
37 },
38});
39
40function buildTransform(opts) {
41 return function (filename, transformOpts) {
42 const babelOpts = normalizeOptions(opts, transformOpts, filename);
43 if (babelOpts === null) {
44 return stream.PassThrough();
45 }
46
47 return new BabelifyStream(babelOpts);
48 };
49}
50
51function normalizeOptions(preconfiguredOpts, transformOpts, filename) {
52 const basedir = normalizeTransformBasedir(transformOpts);
53 const opts = normalizeTransformOpts(transformOpts);
54
55 // Transform options override preconfigured options unless they are undefined.
56 if (preconfiguredOpts) {
57 for (const key of Object.keys(preconfiguredOpts)) {
58 if (opts[key] === undefined) {
59 opts[key] = preconfiguredOpts[key];
60 }
61 }
62 }
63
64 // babelify specific options
65 var extensions = opts.extensions || babel.DEFAULT_EXTENSIONS;
66 var sourceMapsAbsolute = opts.sourceMapsAbsolute;
67 delete opts.sourceMapsAbsolute;
68 delete opts.extensions;
69
70 var extname = path.extname(filename);
71 if (extensions.indexOf(extname) === -1) {
72 return null;
73 }
74
75 // Browserify doesn't actually always normalize the filename passed
76 // to transforms, so we manually ensure that the filename is relative
77 const absoluteFilename = path.resolve(basedir, filename);
78
79 Object.assign(opts, {
80 cwd: opts.cwd === undefined ? basedir : opts.cwd,
81 caller: Object.assign(
82 {
83 name: "babelify",
84 },
85 opts.caller
86 ),
87 filename: absoluteFilename,
88
89 sourceFileName:
90 sourceMapsAbsolute
91 ? absoluteFilename
92 : undefined,
93 });
94
95 return opts;
96}
97
98function normalizeTransformBasedir(opts) {
99 return path.resolve(opts._flags && opts._flags.basedir || ".");
100}
101
102function normalizeTransformOpts(opts) {
103 opts = Object.assign({}, opts);
104
105 // browserify cli options
106 delete opts._;
107 // "--opt [ a b ]" and "--opt a --opt b" are allowed:
108 if (opts.ignore && opts.ignore._) opts.ignore = opts.ignore._;
109 if (opts.only && opts.only._) opts.only = opts.only._;
110 if (opts.plugins && opts.plugins._) opts.plugins = opts.plugins._;
111 if (opts.presets && opts.presets._) opts.presets = opts.presets._;
112
113 // browserify specific options
114 delete opts._flags;
115 delete opts.basedir;
116 delete opts.global;
117
118 return opts;
119}
120
121class BabelifyStream extends stream.Transform {
122 constructor(opts) {
123 super();
124 this._data = [];
125 this._opts = opts;
126 }
127
128 _transform(buf, enc, callback) {
129 this._data.push(buf);
130 callback();
131 }
132
133 _flush(callback) {
134 // Merge the buffer pieces after all are available, instead of one at a time,
135 // to avoid corrupting multibyte characters.
136 const data = Buffer.concat(this._data).toString();
137
138 transform(data, this._opts, (err, result) => {
139 if (err) {
140 callback(err);
141 } else {
142 this.emit("babelify", result, this._opts.filename);
143 var code = result !== null ? result.code : data;
144
145 // Note: Node 8.x allows passing 'code' to the callback instead of
146 // manually pushing, but we need to support Node 6.x.
147 this.push(code);
148 callback();
149 }
150 });
151 }
152}
153
154function transform(data, inputOpts, done) {
155 let cfg;
156 try {
157 cfg = babel.loadPartialConfig(inputOpts);
158 if (!cfg) return done(null, null);
159 } catch (err) {
160 return done(err);
161 }
162 const opts = cfg.options;
163
164 // Since Browserify can only handle inline sourcemaps, we override any other
165 // values to force inline sourcemaps unless they've been disabled.
166 if (opts.sourceMaps !== false) {
167 opts.sourceMaps = "inline";
168 }
169
170 babel.transform(data, opts, done);
171}