index.js 4.6 KB

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