Break apart the File class into multiple files and add type definitions.
This commit is contained in:
parent
c1df126b83
commit
eae76e5b89
@ -15,3 +15,4 @@ lib/third-party-libs.js.flow
|
||||
[options]
|
||||
suppress_comment= \\(.\\|\n\\)*\\$FlowFixMe
|
||||
suppress_comment= \\(.\\|\n\\)*\\$FlowIssue
|
||||
esproposal.export_star_as=enable
|
||||
|
||||
@ -31,3 +31,36 @@ declare module "lodash/clone" {
|
||||
declare module "lodash/merge" {
|
||||
declare export default <T: Object>(T, Object) => T;
|
||||
}
|
||||
|
||||
declare module "convert-source-map" {
|
||||
declare export type SourceMap = {
|
||||
version: 3,
|
||||
file: ?string,
|
||||
sources: [?string],
|
||||
sourcesContent: [?string],
|
||||
names: [?string],
|
||||
mappings: string,
|
||||
};
|
||||
|
||||
declare class Converter {
|
||||
toJSON(): string;
|
||||
toBase64(): string;
|
||||
toComment(): string;
|
||||
toObject(): SourceMap
|
||||
}
|
||||
|
||||
declare module.exports: {
|
||||
SourceMap: SourceMap,
|
||||
Converter: Converter,
|
||||
fromObject(obj: SourceMap): Converter,
|
||||
fromJSON(str: string): Converter,
|
||||
fromBase64(str: string): Converter,
|
||||
fromComment(str: string): Converter,
|
||||
fromMapFileComment(str: string): Converter,
|
||||
fromSource(str: string): Converter,
|
||||
fromMapFileSource(str: string): Converter,
|
||||
removeComments(str: string): string,
|
||||
removeMapFileComments(str: string): string,
|
||||
generateMapFileComment(path: string, options?: ?{ multiline: boolean }): string,
|
||||
};
|
||||
}
|
||||
|
||||
@ -5,9 +5,13 @@ import manageOptions from "./option-manager";
|
||||
|
||||
export type ResolvedConfig = {
|
||||
options: Object,
|
||||
passes: Array<Array<[Plugin, ?{}]>>,
|
||||
passes: PluginPasses,
|
||||
};
|
||||
|
||||
export type { Plugin };
|
||||
export type PluginPassList = Array<[Plugin, ?{}]>;
|
||||
export type PluginPasses = Array<PluginPassList>;
|
||||
|
||||
/**
|
||||
* Standard API for loading Babel configuration data. Not for public consumption.
|
||||
*/
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
// @flow
|
||||
|
||||
export default class Plugin {
|
||||
key: ?string;
|
||||
manipulateOptions: ?Function;
|
||||
post: ?Function;
|
||||
pre: ?Function;
|
||||
visitor: ?{};
|
||||
|
||||
constructor(plugin: {}, key?: string) {
|
||||
if (plugin.name != null && typeof plugin.name !== "string") {
|
||||
throw new Error("Plugin .name must be a string, null, or undefined");
|
||||
@ -30,10 +36,4 @@ export default class Plugin {
|
||||
this.pre = plugin.pre;
|
||||
this.visitor = plugin.visitor;
|
||||
}
|
||||
|
||||
key: ?string;
|
||||
manipulateOptions: ?Function;
|
||||
post: ?Function;
|
||||
pre: ?Function;
|
||||
visitor: ?{};
|
||||
}
|
||||
|
||||
@ -1,17 +1,20 @@
|
||||
export File from "./transformation/file";
|
||||
export buildExternalHelpers from "./tools/build-external-helpers";
|
||||
// @flow
|
||||
|
||||
export {
|
||||
default as buildExternalHelpers,
|
||||
} from "./tools/build-external-helpers";
|
||||
export { resolvePlugin, resolvePreset } from "./config/loading/files";
|
||||
|
||||
export { version } from "../package";
|
||||
export { getEnv } from "./config/helpers/environment";
|
||||
|
||||
export * as types from "babel-types";
|
||||
export traverse from "babel-traverse";
|
||||
export template from "babel-template";
|
||||
export { default as traverse } from "babel-traverse";
|
||||
export { default as template } from "babel-template";
|
||||
|
||||
import loadConfig from "./config";
|
||||
|
||||
export function loadOptions(opts): Object | null {
|
||||
export function loadOptions(opts: {}): Object | null {
|
||||
const config = loadConfig(opts);
|
||||
|
||||
return config ? config.options : null;
|
||||
@ -19,21 +22,21 @@ export function loadOptions(opts): Object | null {
|
||||
|
||||
// For easier backward-compatibility, provide an API like the one we exposed in Babel 6.
|
||||
export class OptionManager {
|
||||
init(opts) {
|
||||
init(opts: {}) {
|
||||
return loadOptions(opts);
|
||||
}
|
||||
}
|
||||
|
||||
export function Plugin(alias) {
|
||||
throw new Error(`The (${alias}) Babel 5 plugin is being run with Babel 6.`);
|
||||
export function Plugin(alias: string) {
|
||||
throw new Error(
|
||||
`The (${alias}) Babel 5 plugin is being run with an unsupported Babel version.`,
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
transform,
|
||||
transformFromAst,
|
||||
transformFile,
|
||||
transformFileSync,
|
||||
} from "./transformation";
|
||||
export { default as transform } from "./transform";
|
||||
export { default as transformFromAst } from "./transform-ast";
|
||||
export { default as transformFile } from "./transform-file";
|
||||
export { default as transformFileSync } from "./transform-file-sync";
|
||||
|
||||
/**
|
||||
* Recommended set of compilable extensions. Not used in babel-core directly, but meant as
|
||||
|
||||
21
packages/babel-core/src/transform-ast.js
Normal file
21
packages/babel-core/src/transform-ast.js
Normal file
@ -0,0 +1,21 @@
|
||||
// @flow
|
||||
import * as t from "babel-types";
|
||||
import loadConfig from "./config";
|
||||
import runTransform, { type FileResult } from "./transformation";
|
||||
|
||||
export default function transformFromAst(
|
||||
ast: Object,
|
||||
code: string,
|
||||
opts: Object,
|
||||
): FileResult | null {
|
||||
const config = loadConfig(opts);
|
||||
if (config === null) return null;
|
||||
|
||||
if (ast && ast.type === "Program") {
|
||||
ast = t.file(ast, [], []);
|
||||
} else if (!ast || ast.type !== "File") {
|
||||
throw new Error("Not a valid ast?");
|
||||
}
|
||||
|
||||
return runTransform(config, code, ast);
|
||||
}
|
||||
16
packages/babel-core/src/transform-file-sync.js
Normal file
16
packages/babel-core/src/transform-file-sync.js
Normal file
@ -0,0 +1,16 @@
|
||||
// @flow
|
||||
import fs from "fs";
|
||||
|
||||
import loadConfig from "./config";
|
||||
import runTransform, { type FileResult } from "./transformation";
|
||||
|
||||
export default function transformFileSync(
|
||||
filename: string,
|
||||
opts?: Object = {},
|
||||
): FileResult | null {
|
||||
opts.filename = filename;
|
||||
const config = loadConfig(opts);
|
||||
if (config === null) return null;
|
||||
|
||||
return runTransform(config, fs.readFileSync(filename, "utf8"));
|
||||
}
|
||||
32
packages/babel-core/src/transform-file.js
Normal file
32
packages/babel-core/src/transform-file.js
Normal file
@ -0,0 +1,32 @@
|
||||
// @flow
|
||||
import fs from "fs";
|
||||
|
||||
import loadConfig from "./config";
|
||||
import runTransform, { type FileResult } from "./transformation";
|
||||
|
||||
export default function transformFile(
|
||||
filename: string,
|
||||
opts?: Object = {},
|
||||
callback: (?Error, FileResult | null) => void,
|
||||
) {
|
||||
if (typeof opts === "function") {
|
||||
callback = opts;
|
||||
opts = {};
|
||||
}
|
||||
|
||||
opts.filename = filename;
|
||||
const config = loadConfig(opts);
|
||||
if (config === null) return callback(null, null);
|
||||
|
||||
fs.readFile(filename, "utf8", function(err, code: string) {
|
||||
if (err) return callback(err, null);
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = runTransform(config, code);
|
||||
} catch (_err) {
|
||||
return callback(err, null);
|
||||
}
|
||||
callback(null, result);
|
||||
});
|
||||
}
|
||||
13
packages/babel-core/src/transform.js
Normal file
13
packages/babel-core/src/transform.js
Normal file
@ -0,0 +1,13 @@
|
||||
// @flow
|
||||
import loadConfig from "./config";
|
||||
import runTransform, { type FileResult } from "./transformation";
|
||||
|
||||
export default function transform(
|
||||
code: string,
|
||||
opts?: Object,
|
||||
): FileResult | null {
|
||||
const config = loadConfig(opts);
|
||||
if (config === null) return null;
|
||||
|
||||
return runTransform(config, code);
|
||||
}
|
||||
@ -1,6 +1,28 @@
|
||||
// @flow
|
||||
|
||||
import sortBy from "lodash/sortBy";
|
||||
|
||||
export default {
|
||||
import loadConfig, { type Plugin } from "../config";
|
||||
|
||||
let LOADED_PLUGIN: Plugin | void;
|
||||
|
||||
export default function loadBlockHoistPlugin(): [Plugin, void] {
|
||||
if (!LOADED_PLUGIN) {
|
||||
// Lazy-init the internal plugin to remove the init-time circular
|
||||
// dependency between plugins being passed babel-core's export object,
|
||||
// which loads this file, and this 'loadConfig' loading plugins.
|
||||
const config = loadConfig({
|
||||
babelrc: false,
|
||||
plugins: [blockHoistPlugin],
|
||||
});
|
||||
LOADED_PLUGIN = config ? config.passes[0][0][0] : undefined;
|
||||
if (!LOADED_PLUGIN) throw new Error("Assertion failure");
|
||||
}
|
||||
|
||||
return [LOADED_PLUGIN, undefined];
|
||||
}
|
||||
|
||||
const blockHoistPlugin = {
|
||||
/**
|
||||
* [Please add a description.]
|
||||
*
|
||||
212
packages/babel-core/src/transformation/file/file.js
Normal file
212
packages/babel-core/src/transformation/file/file.js
Normal file
@ -0,0 +1,212 @@
|
||||
// @flow
|
||||
|
||||
import getHelper from "babel-helpers";
|
||||
import { NodePath, Hub, Scope } from "babel-traverse";
|
||||
import { codeFrameColumns } from "babel-code-frame";
|
||||
import traverse from "babel-traverse";
|
||||
import * as t from "babel-types";
|
||||
|
||||
import type { NormalizedFile } from "../normalize-file";
|
||||
|
||||
const errorVisitor = {
|
||||
enter(path, state) {
|
||||
const loc = path.node.loc;
|
||||
if (loc) {
|
||||
state.loc = loc;
|
||||
path.stop();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default class File {
|
||||
_map: Map<any, any> = new Map();
|
||||
opts: Object;
|
||||
declarations: Object = {};
|
||||
path: NodePath = null;
|
||||
ast: Object = {};
|
||||
scope: Scope;
|
||||
metadata: {} = {};
|
||||
hub: Hub = new Hub(this);
|
||||
code: string = "";
|
||||
shebang: string | null = "";
|
||||
inputMap: Object | null = null;
|
||||
|
||||
constructor(options: {}, { code, ast, shebang, inputMap }: NormalizedFile) {
|
||||
this.opts = options;
|
||||
this.code = code;
|
||||
this.ast = ast;
|
||||
this.shebang = shebang;
|
||||
this.inputMap = inputMap;
|
||||
|
||||
this.path = NodePath.get({
|
||||
hub: this.hub,
|
||||
parentPath: null,
|
||||
parent: this.ast,
|
||||
container: this.ast,
|
||||
key: "program",
|
||||
}).setContext();
|
||||
this.scope = this.path.scope;
|
||||
}
|
||||
|
||||
set(key: mixed, val: mixed) {
|
||||
this._map.set(key, val);
|
||||
}
|
||||
|
||||
get(key: mixed): any {
|
||||
return this._map.get(key);
|
||||
}
|
||||
|
||||
getModuleName(): ?string {
|
||||
const opts = this.opts;
|
||||
if (!opts.moduleIds) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// moduleId is n/a if a `getModuleId()` is provided
|
||||
if (opts.moduleId != null && !opts.getModuleId) {
|
||||
return opts.moduleId;
|
||||
}
|
||||
|
||||
let filenameRelative = opts.filenameRelative;
|
||||
let moduleName = "";
|
||||
|
||||
if (opts.moduleRoot != null) {
|
||||
moduleName = opts.moduleRoot + "/";
|
||||
}
|
||||
|
||||
if (!opts.filenameRelative) {
|
||||
return moduleName + opts.filename.replace(/^\//, "");
|
||||
}
|
||||
|
||||
if (opts.sourceRoot != null) {
|
||||
// remove sourceRoot from filename
|
||||
const sourceRootRegEx = new RegExp("^" + opts.sourceRoot + "/?");
|
||||
filenameRelative = filenameRelative.replace(sourceRootRegEx, "");
|
||||
}
|
||||
|
||||
// remove extension
|
||||
filenameRelative = filenameRelative.replace(/\.(\w*?)$/, "");
|
||||
|
||||
moduleName += filenameRelative;
|
||||
|
||||
// normalize path separators
|
||||
moduleName = moduleName.replace(/\\/g, "/");
|
||||
|
||||
if (opts.getModuleId) {
|
||||
// If return is falsy, assume they want us to use our generated default name
|
||||
return opts.getModuleId(moduleName) || moduleName;
|
||||
} else {
|
||||
return moduleName;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove this before 7.x's official release. Leaving it in for now to
|
||||
// prevent unnecessary breakage between beta versions.
|
||||
resolveModuleSource(source: string): string {
|
||||
return source;
|
||||
}
|
||||
|
||||
addImport() {
|
||||
throw new Error(
|
||||
"This API has been removed. If you're looking for this " +
|
||||
"functionality in Babel 7, you should import the " +
|
||||
"'babel-helper-module-imports' module and use the functions exposed " +
|
||||
" from that module, such as 'addNamed' or 'addDefault'.",
|
||||
);
|
||||
}
|
||||
|
||||
addHelper(name: string): Object {
|
||||
const declar = this.declarations[name];
|
||||
if (declar) return declar;
|
||||
|
||||
const generator = this.get("helperGenerator");
|
||||
const runtime = this.get("helpersNamespace");
|
||||
if (generator) {
|
||||
const res = generator(name);
|
||||
if (res) return res;
|
||||
} else if (runtime) {
|
||||
return t.memberExpression(runtime, t.identifier(name));
|
||||
}
|
||||
|
||||
const uid = (this.declarations[name] = this.scope.generateUidIdentifier(
|
||||
name,
|
||||
));
|
||||
|
||||
const { nodes, globals } = getHelper(
|
||||
name,
|
||||
name => this.addHelper(name),
|
||||
uid,
|
||||
() => Object.keys(this.scope.getAllBindings()),
|
||||
);
|
||||
|
||||
globals.forEach(name => {
|
||||
if (this.path.scope.hasBinding(name, true /* noGlobals */)) {
|
||||
this.path.scope.rename(name);
|
||||
}
|
||||
});
|
||||
|
||||
nodes.forEach(node => {
|
||||
node._compact = true;
|
||||
});
|
||||
|
||||
this.path.unshiftContainer("body", nodes);
|
||||
// TODO: NodePath#unshiftContainer should automatically register new
|
||||
// bindings.
|
||||
this.path.get("body").forEach(path => {
|
||||
if (nodes.indexOf(path.node) === -1) return;
|
||||
if (path.isVariableDeclaration()) this.scope.registerDeclaration(path);
|
||||
});
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
addTemplateObject() {
|
||||
throw new Error(
|
||||
"This function has been moved into the template literal transform itself.",
|
||||
);
|
||||
}
|
||||
|
||||
buildCodeFrameError(
|
||||
node: ?{
|
||||
loc?: { line: number, column: number },
|
||||
_loc?: { line: number, column: number },
|
||||
},
|
||||
msg: string,
|
||||
Error: typeof Error = SyntaxError,
|
||||
): Error {
|
||||
let loc = node && (node.loc || node._loc);
|
||||
|
||||
msg = `${this.opts.filename}: ${msg}`;
|
||||
|
||||
if (!loc && node) {
|
||||
const state = {
|
||||
loc: null,
|
||||
};
|
||||
traverse(node, errorVisitor, this.scope, state);
|
||||
loc = state.loc;
|
||||
|
||||
let txt =
|
||||
"This is an error on an internal node. Probably an internal error.";
|
||||
if (loc) txt += " Location has been estimated.";
|
||||
|
||||
msg += ` (${txt})`;
|
||||
}
|
||||
|
||||
if (loc) {
|
||||
msg +=
|
||||
"\n" +
|
||||
codeFrameColumns(
|
||||
this.code,
|
||||
{
|
||||
start: {
|
||||
line: loc.line,
|
||||
column: loc.column + 1,
|
||||
},
|
||||
},
|
||||
this.opts,
|
||||
);
|
||||
}
|
||||
|
||||
return new Error(msg);
|
||||
}
|
||||
}
|
||||
89
packages/babel-core/src/transformation/file/generate.js
Normal file
89
packages/babel-core/src/transformation/file/generate.js
Normal file
@ -0,0 +1,89 @@
|
||||
// @flow
|
||||
|
||||
import convertSourceMap, { type SourceMap } from "convert-source-map";
|
||||
import sourceMap from "source-map";
|
||||
import generate from "babel-generator";
|
||||
|
||||
import type File from "./file";
|
||||
|
||||
export default function generateCode(
|
||||
file: File,
|
||||
): {
|
||||
outputCode: string,
|
||||
outputMap: SourceMap | null,
|
||||
} {
|
||||
const { opts, ast, shebang, code, inputMap } = file;
|
||||
|
||||
let gen = generate;
|
||||
if (opts.generatorOpts && opts.generatorOpts.generator) {
|
||||
gen = opts.generatorOpts.generator;
|
||||
}
|
||||
|
||||
let { code: outputCode, map: outputMap } = gen(
|
||||
ast,
|
||||
opts.generatorOpts ? Object.assign(opts, opts.generatorOpts) : opts,
|
||||
code,
|
||||
);
|
||||
|
||||
if (shebang) {
|
||||
// add back shebang
|
||||
outputCode = `${shebang}\n${outputCode}`;
|
||||
}
|
||||
|
||||
if (outputMap && inputMap) {
|
||||
outputMap = mergeSourceMap(inputMap.toObject(), outputMap);
|
||||
}
|
||||
|
||||
if (opts.sourceMaps === "inline" || opts.sourceMaps === "both") {
|
||||
outputCode += "\n" + convertSourceMap.fromObject(outputMap).toComment();
|
||||
}
|
||||
|
||||
if (opts.sourceMaps === "inline") {
|
||||
outputMap = null;
|
||||
}
|
||||
|
||||
return { outputCode, outputMap };
|
||||
}
|
||||
|
||||
function mergeSourceMap(inputMap: SourceMap, map: SourceMap): SourceMap {
|
||||
const inputMapConsumer = new sourceMap.SourceMapConsumer(inputMap);
|
||||
const outputMapConsumer = new sourceMap.SourceMapConsumer(map);
|
||||
|
||||
const mergedGenerator = new sourceMap.SourceMapGenerator({
|
||||
file: inputMapConsumer.file,
|
||||
sourceRoot: inputMapConsumer.sourceRoot,
|
||||
});
|
||||
|
||||
// This assumes the output map always has a single source, since Babel always compiles a
|
||||
// single source file to a single output file.
|
||||
const source = outputMapConsumer.sources[0];
|
||||
|
||||
inputMapConsumer.eachMapping(function(mapping) {
|
||||
const generatedPosition = outputMapConsumer.generatedPositionFor({
|
||||
line: mapping.generatedLine,
|
||||
column: mapping.generatedColumn,
|
||||
source: source,
|
||||
});
|
||||
if (generatedPosition.column != null) {
|
||||
mergedGenerator.addMapping({
|
||||
source: mapping.source,
|
||||
|
||||
original:
|
||||
mapping.source == null
|
||||
? null
|
||||
: {
|
||||
line: mapping.originalLine,
|
||||
column: mapping.originalColumn,
|
||||
},
|
||||
|
||||
generated: generatedPosition,
|
||||
|
||||
name: mapping.name,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const mergedMap = mergedGenerator.toJSON();
|
||||
inputMap.mappings = mergedMap.mappings;
|
||||
return inputMap;
|
||||
}
|
||||
@ -1,501 +0,0 @@
|
||||
/* global BabelFileResult, BabelParserOptions, BabelFileMetadata */
|
||||
|
||||
import getHelper from "babel-helpers";
|
||||
import convertSourceMap from "convert-source-map";
|
||||
import PluginPass from "../plugin-pass";
|
||||
import { NodePath, Hub, Scope } from "babel-traverse";
|
||||
import sourceMap from "source-map";
|
||||
import generate from "babel-generator";
|
||||
import { codeFrameColumns } from "babel-code-frame";
|
||||
import traverse from "babel-traverse";
|
||||
import { parse } from "babylon";
|
||||
import * as t from "babel-types";
|
||||
import buildDebug from "debug";
|
||||
|
||||
import loadConfig, { type ResolvedConfig } from "../../config";
|
||||
|
||||
import blockHoistPlugin from "../internal-plugins/block-hoist";
|
||||
|
||||
const babelDebug = buildDebug("babel:file");
|
||||
|
||||
export function debug(opts: Object, msg: string) {
|
||||
babelDebug(`${opts.filename || "unknown"}: ${msg}`);
|
||||
}
|
||||
|
||||
const shebangRegex = /^#!.*/;
|
||||
|
||||
let INTERNAL_PLUGINS;
|
||||
|
||||
const errorVisitor = {
|
||||
enter(path, state) {
|
||||
const loc = path.node.loc;
|
||||
if (loc) {
|
||||
state.loc = loc;
|
||||
path.stop();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default class File {
|
||||
constructor({ options, passes }: ResolvedConfig) {
|
||||
if (!INTERNAL_PLUGINS) {
|
||||
// Lazy-init the internal plugin to remove the init-time circular dependency between plugins being
|
||||
// passed babel-core's export object, which loads this file, and this 'loadConfig' loading plugins.
|
||||
INTERNAL_PLUGINS = loadConfig({
|
||||
babelrc: false,
|
||||
plugins: [blockHoistPlugin],
|
||||
}).passes[0];
|
||||
}
|
||||
|
||||
this._map = new Map();
|
||||
this.pluginPasses = passes;
|
||||
this.opts = options;
|
||||
|
||||
this.parserOpts = {
|
||||
sourceType: this.opts.sourceType,
|
||||
sourceFileName: this.opts.filename,
|
||||
plugins: [],
|
||||
};
|
||||
|
||||
for (const pluginPairs of passes) {
|
||||
for (const [plugin] of pluginPairs) {
|
||||
if (plugin.manipulateOptions) {
|
||||
plugin.manipulateOptions(this.opts, this.parserOpts, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.metadata = {};
|
||||
this.declarations = {};
|
||||
|
||||
this.path = null;
|
||||
this.ast = {};
|
||||
|
||||
this.code = "";
|
||||
this.shebang = "";
|
||||
|
||||
this.hub = new Hub(this);
|
||||
}
|
||||
|
||||
pluginPasses: Array<Array<[Plugin, Object]>>;
|
||||
parserOpts: BabelParserOptions;
|
||||
opts: Object;
|
||||
declarations: Object;
|
||||
path: NodePath;
|
||||
ast: Object;
|
||||
scope: Scope;
|
||||
metadata: BabelFileMetadata;
|
||||
hub: Hub;
|
||||
code: string;
|
||||
shebang: string;
|
||||
|
||||
set(key: string, val) {
|
||||
this._map.set(key, val);
|
||||
}
|
||||
|
||||
get(key: string): any {
|
||||
return this._map.get(key);
|
||||
}
|
||||
|
||||
getModuleName(): ?string {
|
||||
const opts = this.opts;
|
||||
if (!opts.moduleIds) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// moduleId is n/a if a `getModuleId()` is provided
|
||||
if (opts.moduleId != null && !opts.getModuleId) {
|
||||
return opts.moduleId;
|
||||
}
|
||||
|
||||
let filenameRelative = opts.filenameRelative;
|
||||
let moduleName = "";
|
||||
|
||||
if (opts.moduleRoot != null) {
|
||||
moduleName = opts.moduleRoot + "/";
|
||||
}
|
||||
|
||||
if (!opts.filenameRelative) {
|
||||
return moduleName + opts.filename.replace(/^\//, "");
|
||||
}
|
||||
|
||||
if (opts.sourceRoot != null) {
|
||||
// remove sourceRoot from filename
|
||||
const sourceRootRegEx = new RegExp("^" + opts.sourceRoot + "/?");
|
||||
filenameRelative = filenameRelative.replace(sourceRootRegEx, "");
|
||||
}
|
||||
|
||||
// remove extension
|
||||
filenameRelative = filenameRelative.replace(/\.(\w*?)$/, "");
|
||||
|
||||
moduleName += filenameRelative;
|
||||
|
||||
// normalize path separators
|
||||
moduleName = moduleName.replace(/\\/g, "/");
|
||||
|
||||
if (opts.getModuleId) {
|
||||
// If return is falsy, assume they want us to use our generated default name
|
||||
return opts.getModuleId(moduleName) || moduleName;
|
||||
} else {
|
||||
return moduleName;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove this before 7.x's official release. Leaving it in for now to
|
||||
// prevent unnecessary breakage between beta versions.
|
||||
resolveModuleSource(source: string): string {
|
||||
return source;
|
||||
}
|
||||
|
||||
addImport() {
|
||||
throw new Error(
|
||||
"This API has been removed. If you're looking for this " +
|
||||
"functionality in Babel 7, you should import the " +
|
||||
"'babel-helper-module-imports' module and use the functions exposed " +
|
||||
" from that module, such as 'addNamed' or 'addDefault'.",
|
||||
);
|
||||
}
|
||||
|
||||
addHelper(name: string): Object {
|
||||
const declar = this.declarations[name];
|
||||
if (declar) return declar;
|
||||
|
||||
const generator = this.get("helperGenerator");
|
||||
const runtime = this.get("helpersNamespace");
|
||||
if (generator) {
|
||||
const res = generator(name);
|
||||
if (res) return res;
|
||||
} else if (runtime) {
|
||||
return t.memberExpression(runtime, t.identifier(name));
|
||||
}
|
||||
|
||||
const uid = (this.declarations[name] = this.scope.generateUidIdentifier(
|
||||
name,
|
||||
));
|
||||
|
||||
const { nodes, globals } = getHelper(
|
||||
name,
|
||||
name => this.addHelper(name),
|
||||
uid,
|
||||
() => Object.keys(this.scope.getAllBindings()),
|
||||
);
|
||||
|
||||
globals.forEach(name => {
|
||||
if (this.path.scope.hasBinding(name, true /* noGlobals */)) {
|
||||
this.path.scope.rename(name);
|
||||
}
|
||||
});
|
||||
|
||||
nodes.forEach(node => {
|
||||
node._compact = true;
|
||||
});
|
||||
|
||||
this.path.unshiftContainer("body", nodes);
|
||||
// TODO: NodePath#unshiftContainer should automatically register new
|
||||
// bindings.
|
||||
this.path.get("body").forEach(path => {
|
||||
if (nodes.indexOf(path.node) === -1) return;
|
||||
if (path.isVariableDeclaration()) this.scope.registerDeclaration(path);
|
||||
});
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
addTemplateObject() {
|
||||
throw new Error(
|
||||
"This function has been moved into the template literal transform itself.",
|
||||
);
|
||||
}
|
||||
|
||||
buildCodeFrameError(
|
||||
node: Object,
|
||||
msg: string,
|
||||
Error: typeof Error = SyntaxError,
|
||||
): Error {
|
||||
let loc = node && (node.loc || node._loc);
|
||||
|
||||
msg = `${this.opts.filename}: ${msg}`;
|
||||
|
||||
if (!loc && node) {
|
||||
const state = {
|
||||
loc: null,
|
||||
};
|
||||
traverse(node, errorVisitor, this.scope, state);
|
||||
loc = state.loc;
|
||||
|
||||
let txt =
|
||||
"This is an error on an internal node. Probably an internal error.";
|
||||
if (loc) txt += " Location has been estimated.";
|
||||
|
||||
msg += ` (${txt})`;
|
||||
}
|
||||
|
||||
msg +=
|
||||
"\n" +
|
||||
codeFrameColumns(
|
||||
this.code,
|
||||
{
|
||||
start: {
|
||||
line: loc.line,
|
||||
column: loc.column + 1,
|
||||
},
|
||||
},
|
||||
this.opts,
|
||||
);
|
||||
|
||||
return new Error(msg);
|
||||
}
|
||||
|
||||
mergeSourceMap(map: Object) {
|
||||
const inputMap = this.opts.inputSourceMap;
|
||||
|
||||
if (inputMap) {
|
||||
const inputMapConsumer = new sourceMap.SourceMapConsumer(inputMap);
|
||||
const outputMapConsumer = new sourceMap.SourceMapConsumer(map);
|
||||
|
||||
const mergedGenerator = new sourceMap.SourceMapGenerator({
|
||||
file: inputMapConsumer.file,
|
||||
sourceRoot: inputMapConsumer.sourceRoot,
|
||||
});
|
||||
|
||||
// This assumes the output map always has a single source, since Babel always compiles a
|
||||
// single source file to a single output file.
|
||||
const source = outputMapConsumer.sources[0];
|
||||
|
||||
inputMapConsumer.eachMapping(function(mapping) {
|
||||
const generatedPosition = outputMapConsumer.generatedPositionFor({
|
||||
line: mapping.generatedLine,
|
||||
column: mapping.generatedColumn,
|
||||
source: source,
|
||||
});
|
||||
if (generatedPosition.column != null) {
|
||||
mergedGenerator.addMapping({
|
||||
source: mapping.source,
|
||||
|
||||
original:
|
||||
mapping.source == null
|
||||
? null
|
||||
: {
|
||||
line: mapping.originalLine,
|
||||
column: mapping.originalColumn,
|
||||
},
|
||||
|
||||
generated: generatedPosition,
|
||||
|
||||
name: mapping.name,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const mergedMap = mergedGenerator.toJSON();
|
||||
inputMap.mappings = mergedMap.mappings;
|
||||
return inputMap;
|
||||
} else {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
parse(code: string) {
|
||||
let parseCode = parse;
|
||||
let parserOpts = this.opts.parserOpts;
|
||||
|
||||
if (parserOpts) {
|
||||
parserOpts = Object.assign({}, this.parserOpts, parserOpts);
|
||||
|
||||
if (parserOpts.parser) {
|
||||
parseCode = parserOpts.parser;
|
||||
|
||||
parserOpts.parser = {
|
||||
parse(source) {
|
||||
return parse(source, parserOpts);
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
debug(this.opts, "Parse start");
|
||||
let ast;
|
||||
try {
|
||||
ast = parseCode(code, parserOpts || this.parserOpts);
|
||||
} catch (err) {
|
||||
const loc = err.loc;
|
||||
if (loc) {
|
||||
err.loc = null;
|
||||
err.message =
|
||||
`${this.opts.filename}: ${err.message}\n` +
|
||||
codeFrameColumns(
|
||||
this.code,
|
||||
{
|
||||
start: {
|
||||
line: loc.line,
|
||||
column: loc.column + 1,
|
||||
},
|
||||
},
|
||||
this.opts,
|
||||
);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
debug(this.opts, "Parse stop");
|
||||
return ast;
|
||||
}
|
||||
|
||||
_addAst(ast) {
|
||||
this.path = NodePath.get({
|
||||
hub: this.hub,
|
||||
parentPath: null,
|
||||
parent: ast,
|
||||
container: ast,
|
||||
key: "program",
|
||||
}).setContext();
|
||||
this.scope = this.path.scope;
|
||||
this.ast = ast;
|
||||
}
|
||||
|
||||
addAst(ast) {
|
||||
debug(this.opts, "Start set AST");
|
||||
this._addAst(ast);
|
||||
debug(this.opts, "End set AST");
|
||||
}
|
||||
|
||||
transform(): BabelFileResult {
|
||||
for (const pluginPairs of this.pluginPasses) {
|
||||
const passPairs = [];
|
||||
const passes = [];
|
||||
const visitors = [];
|
||||
|
||||
for (const [plugin, pluginOpts] of pluginPairs.concat(INTERNAL_PLUGINS)) {
|
||||
const pass = new PluginPass(this, plugin.key, pluginOpts);
|
||||
|
||||
passPairs.push([plugin, pass]);
|
||||
passes.push(pass);
|
||||
visitors.push(plugin.visitor);
|
||||
}
|
||||
|
||||
for (const [plugin, pass] of passPairs) {
|
||||
const fn = plugin.pre;
|
||||
if (fn) fn.call(pass, this);
|
||||
}
|
||||
|
||||
debug(this.opts, "Start transform traverse");
|
||||
|
||||
// merge all plugin visitors into a single visitor
|
||||
const visitor = traverse.visitors.merge(
|
||||
visitors,
|
||||
passes,
|
||||
this.opts.wrapPluginVisitorMethod,
|
||||
);
|
||||
traverse(this.ast, visitor, this.scope);
|
||||
|
||||
debug(this.opts, "End transform traverse");
|
||||
|
||||
for (const [plugin, pass] of passPairs) {
|
||||
const fn = plugin.post;
|
||||
if (fn) fn.call(pass, this);
|
||||
}
|
||||
}
|
||||
|
||||
return this.generate();
|
||||
}
|
||||
|
||||
addCode(code: string) {
|
||||
code = (code || "") + "";
|
||||
code = this.parseInputSourceMap(code);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
parseCode() {
|
||||
this.parseShebang();
|
||||
const ast = this.parse(this.code);
|
||||
this.addAst(ast);
|
||||
}
|
||||
|
||||
parseInputSourceMap(code: string): string {
|
||||
const opts = this.opts;
|
||||
|
||||
if (opts.inputSourceMap !== false) {
|
||||
const inputMap = convertSourceMap.fromSource(code);
|
||||
if (inputMap) {
|
||||
opts.inputSourceMap = inputMap.toObject();
|
||||
code = convertSourceMap.removeComments(code);
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
parseShebang() {
|
||||
const shebangMatch = shebangRegex.exec(this.code);
|
||||
if (shebangMatch) {
|
||||
this.shebang = shebangMatch[0];
|
||||
this.code = this.code.replace(shebangRegex, "");
|
||||
}
|
||||
}
|
||||
|
||||
makeResult({ code, map, ast, ignored }: BabelFileResult): BabelFileResult {
|
||||
const result = {
|
||||
metadata: this.metadata,
|
||||
options: this.opts,
|
||||
ignored: !!ignored,
|
||||
code: null,
|
||||
ast: null,
|
||||
map: map || null,
|
||||
};
|
||||
|
||||
if (this.opts.code) {
|
||||
result.code = code;
|
||||
}
|
||||
|
||||
if (this.opts.ast) {
|
||||
result.ast = ast;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
generate(): BabelFileResult {
|
||||
const opts = this.opts;
|
||||
const ast = this.ast;
|
||||
|
||||
const result: BabelFileResult = { ast };
|
||||
if (!opts.code) return this.makeResult(result);
|
||||
|
||||
let gen = generate;
|
||||
if (opts.generatorOpts && opts.generatorOpts.generator) {
|
||||
gen = opts.generatorOpts.generator;
|
||||
}
|
||||
|
||||
debug(this.opts, "Generation start");
|
||||
|
||||
const _result = gen(
|
||||
ast,
|
||||
opts.generatorOpts ? Object.assign(opts, opts.generatorOpts) : opts,
|
||||
this.code,
|
||||
);
|
||||
result.code = _result.code;
|
||||
result.map = _result.map;
|
||||
|
||||
debug(this.opts, "Generation end");
|
||||
|
||||
if (this.shebang) {
|
||||
// add back shebang
|
||||
result.code = `${this.shebang}\n${result.code}`;
|
||||
}
|
||||
|
||||
if (result.map) {
|
||||
result.map = this.mergeSourceMap(result.map);
|
||||
}
|
||||
|
||||
if (opts.sourceMaps === "inline" || opts.sourceMaps === "both") {
|
||||
result.code += "\n" + convertSourceMap.fromObject(result.map).toComment();
|
||||
}
|
||||
|
||||
if (opts.sourceMaps === "inline") {
|
||||
result.map = null;
|
||||
}
|
||||
|
||||
return this.makeResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
export { File };
|
||||
@ -1,88 +1,80 @@
|
||||
/* global BabelFileResult */
|
||||
import fs from "fs";
|
||||
// @flow
|
||||
import traverse from "babel-traverse";
|
||||
import type { SourceMap } from "convert-source-map";
|
||||
|
||||
import * as t from "babel-types";
|
||||
import File from "./file";
|
||||
import loadConfig from "../config";
|
||||
import type { ResolvedConfig, PluginPasses } from "../config";
|
||||
|
||||
export function transform(code: string, opts?: Object): BabelFileResult {
|
||||
const config = loadConfig(opts);
|
||||
if (config === null) return null;
|
||||
import PluginPass from "./plugin-pass";
|
||||
import loadBlockHoistPlugin from "./block-hoist-plugin";
|
||||
import normalizeOptions from "./normalize-opts";
|
||||
import normalizeFile from "./normalize-file";
|
||||
|
||||
const file = new File(config);
|
||||
file.addCode(code);
|
||||
file.parseCode(code);
|
||||
return file.transform();
|
||||
}
|
||||
import generateCode from "./file/generate";
|
||||
import File from "./file/file";
|
||||
|
||||
export function transformFromAst(
|
||||
ast: Object,
|
||||
export type FileResult = {
|
||||
metadata: {},
|
||||
options: {},
|
||||
ast: {} | null,
|
||||
code: string | null,
|
||||
map: SourceMap | null,
|
||||
};
|
||||
|
||||
export default function runTransform(
|
||||
config: ResolvedConfig,
|
||||
code: string,
|
||||
opts: Object,
|
||||
): BabelFileResult {
|
||||
const config = loadConfig(opts);
|
||||
if (config === null) return null;
|
||||
ast?: {},
|
||||
): FileResult {
|
||||
const options = normalizeOptions(config);
|
||||
const input = normalizeFile(options, code, ast);
|
||||
|
||||
if (ast && ast.type === "Program") {
|
||||
ast = t.file(ast, [], []);
|
||||
} else if (!ast || ast.type !== "File") {
|
||||
throw new Error("Not a valid ast?");
|
||||
const file = new File(options, input);
|
||||
|
||||
transformFile(file, config.passes);
|
||||
|
||||
const { outputCode, outputMap } = options.code ? generateCode(file) : {};
|
||||
|
||||
return {
|
||||
metadata: file.metadata,
|
||||
options: options,
|
||||
ast: options.ast ? file.ast : null,
|
||||
code: outputCode === undefined ? null : outputCode,
|
||||
map: outputMap === undefined ? null : outputMap,
|
||||
};
|
||||
}
|
||||
|
||||
const file = new File(config);
|
||||
file.addCode(code);
|
||||
file.addAst(ast);
|
||||
return file.transform();
|
||||
function transformFile(file: File, pluginPasses: PluginPasses): void {
|
||||
for (const pluginPairs of pluginPasses) {
|
||||
const passPairs = [];
|
||||
const passes = [];
|
||||
const visitors = [];
|
||||
|
||||
for (const [plugin, pluginOpts] of pluginPairs.concat([
|
||||
loadBlockHoistPlugin(),
|
||||
])) {
|
||||
const pass = new PluginPass(file, plugin.key, pluginOpts);
|
||||
|
||||
passPairs.push([plugin, pass]);
|
||||
passes.push(pass);
|
||||
visitors.push(plugin.visitor);
|
||||
}
|
||||
|
||||
export function transformFile(
|
||||
filename: string,
|
||||
opts?: Object,
|
||||
callback: Function,
|
||||
) {
|
||||
if (typeof opts === "function") {
|
||||
callback = opts;
|
||||
opts = {};
|
||||
for (const [plugin, pass] of passPairs) {
|
||||
const fn = plugin.pre;
|
||||
if (fn) fn.call(pass, file);
|
||||
}
|
||||
|
||||
opts.filename = filename;
|
||||
const config = loadConfig(opts);
|
||||
if (config === null) return callback(null, null);
|
||||
// merge all plugin visitors into a single visitor
|
||||
const visitor = traverse.visitors.merge(
|
||||
visitors,
|
||||
passes,
|
||||
file.opts.wrapPluginVisitorMethod,
|
||||
);
|
||||
traverse(file.ast, visitor, file.scope);
|
||||
|
||||
fs.readFile(filename, function(err, code) {
|
||||
let result;
|
||||
|
||||
if (!err) {
|
||||
try {
|
||||
const file = new File(config);
|
||||
file.addCode(code);
|
||||
file.parseCode(code);
|
||||
result = file.transform();
|
||||
} catch (_err) {
|
||||
err = _err;
|
||||
for (const [plugin, pass] of passPairs) {
|
||||
const fn = plugin.post;
|
||||
if (fn) fn.call(pass, file);
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
callback(null, result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function transformFileSync(
|
||||
filename: string,
|
||||
opts?: Object = {},
|
||||
): string {
|
||||
opts.filename = filename;
|
||||
const config = loadConfig(opts);
|
||||
if (config === null) return null;
|
||||
|
||||
const code = fs.readFileSync(filename, "utf8");
|
||||
const file = new File(config);
|
||||
|
||||
file.addCode(code);
|
||||
file.parseCode(code);
|
||||
return file.transform();
|
||||
}
|
||||
|
||||
87
packages/babel-core/src/transformation/normalize-file.js
Normal file
87
packages/babel-core/src/transformation/normalize-file.js
Normal file
@ -0,0 +1,87 @@
|
||||
// @flow
|
||||
|
||||
import convertSourceMap, { typeof Converter } from "convert-source-map";
|
||||
import { parse } from "babylon";
|
||||
import { codeFrameColumns } from "babel-code-frame";
|
||||
|
||||
const shebangRegex = /^#!.*/;
|
||||
|
||||
export type NormalizedFile = {
|
||||
code: string,
|
||||
ast: {},
|
||||
shebang: string | null,
|
||||
inputMap: Converter | null,
|
||||
};
|
||||
|
||||
export default function normalizeFile(
|
||||
options: Object,
|
||||
code: string,
|
||||
ast?: {},
|
||||
): NormalizedFile {
|
||||
code = `${code || ""}`;
|
||||
|
||||
let shebang = null;
|
||||
let inputMap = null;
|
||||
if (options.inputSourceMap !== false) {
|
||||
inputMap = convertSourceMap.fromSource(code);
|
||||
if (inputMap) {
|
||||
code = convertSourceMap.removeComments(code);
|
||||
} else if (typeof options.inputSourceMap === "object") {
|
||||
inputMap = convertSourceMap.fromObject(options.inputSourceMap);
|
||||
}
|
||||
}
|
||||
|
||||
const shebangMatch = shebangRegex.exec(code);
|
||||
if (shebangMatch) {
|
||||
shebang = shebangMatch[0];
|
||||
code = code.replace(shebangRegex, "");
|
||||
}
|
||||
|
||||
if (!ast) ast = parser(options, code);
|
||||
|
||||
return {
|
||||
code,
|
||||
ast,
|
||||
shebang,
|
||||
inputMap,
|
||||
};
|
||||
}
|
||||
|
||||
function parser(options, code) {
|
||||
let parseCode = parse;
|
||||
|
||||
let { parserOpts } = options;
|
||||
if (parserOpts.parser) {
|
||||
parseCode = parserOpts.parser;
|
||||
|
||||
parserOpts = Object.assign({}, parserOpts, {
|
||||
parser: {
|
||||
parse(source) {
|
||||
return parse(source, parserOpts);
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
return parseCode(code, parserOpts);
|
||||
} catch (err) {
|
||||
const loc = err.loc;
|
||||
if (loc) {
|
||||
err.loc = null;
|
||||
err.message =
|
||||
`${options.filename}: ${err.message}\n` +
|
||||
codeFrameColumns(
|
||||
code,
|
||||
{
|
||||
start: {
|
||||
line: loc.line,
|
||||
column: loc.column + 1,
|
||||
},
|
||||
},
|
||||
options,
|
||||
);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
26
packages/babel-core/src/transformation/normalize-opts.js
Normal file
26
packages/babel-core/src/transformation/normalize-opts.js
Normal file
@ -0,0 +1,26 @@
|
||||
// @flow
|
||||
|
||||
import type { ResolvedConfig } from "../config";
|
||||
|
||||
export default function normalizeOptions(config: ResolvedConfig): {} {
|
||||
const options = Object.assign({}, config.options, {
|
||||
parserOpts: Object.assign(
|
||||
{
|
||||
sourceType: config.options.sourceType,
|
||||
sourceFileName: config.options.filename,
|
||||
plugins: [],
|
||||
},
|
||||
config.options.parserOpts,
|
||||
),
|
||||
});
|
||||
|
||||
for (const pluginPairs of config.passes) {
|
||||
for (const [plugin] of pluginPairs) {
|
||||
if (plugin.manipulateOptions) {
|
||||
plugin.manipulateOptions(options, options.parserOpts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
@ -1,39 +1,47 @@
|
||||
import File from "./file";
|
||||
// @flow
|
||||
|
||||
import type File from "./file/file";
|
||||
|
||||
export default class PluginPass {
|
||||
constructor(file: File, key: string, options: Object = {}) {
|
||||
this._map = new Map();
|
||||
|
||||
this.key = key;
|
||||
this.file = file;
|
||||
this.opts = options;
|
||||
}
|
||||
|
||||
key: string;
|
||||
_map: Map<mixed, mixed> = new Map();
|
||||
key: ?string;
|
||||
file: File;
|
||||
opts: Object;
|
||||
|
||||
set(key: string, val) {
|
||||
constructor(file: File, key: ?string, options: ?Object) {
|
||||
this.key = key;
|
||||
this.file = file;
|
||||
this.opts = options || {};
|
||||
}
|
||||
|
||||
set(key: mixed, val: mixed) {
|
||||
this._map.set(key, val);
|
||||
}
|
||||
|
||||
get(key: string): any {
|
||||
get(key: mixed): any {
|
||||
return this._map.get(key);
|
||||
}
|
||||
|
||||
addHelper(...args) {
|
||||
return this.file.addHelper(...args);
|
||||
addHelper(name: string) {
|
||||
return this.file.addHelper(name);
|
||||
}
|
||||
|
||||
addImport(...args) {
|
||||
return this.file.addImport(...args);
|
||||
addImport() {
|
||||
return this.file.addImport();
|
||||
}
|
||||
|
||||
getModuleName(...args) {
|
||||
return this.file.getModuleName(...args);
|
||||
getModuleName(): ?string {
|
||||
return this.file.getModuleName();
|
||||
}
|
||||
|
||||
buildCodeFrameError(...args) {
|
||||
return this.file.buildCodeFrameError(...args);
|
||||
buildCodeFrameError(
|
||||
node: ?{
|
||||
loc?: { line: number, column: number },
|
||||
_loc?: { line: number, column: number },
|
||||
},
|
||||
msg: string,
|
||||
Error?: typeof Error,
|
||||
) {
|
||||
return this.file.buildCodeFrameError(node, msg, Error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ describe("option-manager", () => {
|
||||
manageOptions({
|
||||
plugins: [({ Plugin }) => new Plugin("object-assign", {})],
|
||||
});
|
||||
}, /Babel 5 plugin is being run with Babel 6/);
|
||||
}, /Babel 5 plugin is being run with an unsupported Babel/);
|
||||
});
|
||||
|
||||
describe("mergeOptions", () => {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
export default class Hub {
|
||||
constructor(file, options) {
|
||||
constructor(file) {
|
||||
this.file = file;
|
||||
this.options = options;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user