Merge pull request #6781 from loganfsmyth/parsegen-plugins
Make official API for plugins to override parser/generator
This commit is contained in:
commit
d90ba531ee
@ -42,21 +42,3 @@ export function loadPreset(
|
|||||||
`Cannot load preset ${name} relative to ${dirname} in a browser`,
|
`Cannot load preset ${name} relative to ${dirname} in a browser`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadParser(
|
|
||||||
name: string,
|
|
||||||
dirname: string,
|
|
||||||
): { filepath: string, value: Function } {
|
|
||||||
throw new Error(
|
|
||||||
`Cannot load parser ${name} relative to ${dirname} in a browser`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function loadGenerator(
|
|
||||||
name: string,
|
|
||||||
dirname: string,
|
|
||||||
): { filepath: string, value: Function } {
|
|
||||||
throw new Error(
|
|
||||||
`Cannot load generator ${name} relative to ${dirname} in a browser`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -57,62 +57,6 @@ export function loadPreset(
|
|||||||
return { filepath, value };
|
return { filepath, value };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadParser(
|
|
||||||
name: string,
|
|
||||||
dirname: string,
|
|
||||||
): { filepath: string, value: Function } {
|
|
||||||
const filepath = resolve.sync(name, { basedir: dirname });
|
|
||||||
|
|
||||||
const mod = requireModule("parser", filepath);
|
|
||||||
|
|
||||||
if (!mod) {
|
|
||||||
throw new Error(
|
|
||||||
`Parser ${name} relative to ${dirname} does not export an object`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (typeof mod.parse !== "function") {
|
|
||||||
throw new Error(
|
|
||||||
`Parser ${name} relative to ${dirname} does not export a .parse function`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const value = mod.parse;
|
|
||||||
|
|
||||||
debug("Loaded parser %o from %o.", name, dirname);
|
|
||||||
|
|
||||||
return {
|
|
||||||
filepath,
|
|
||||||
value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function loadGenerator(
|
|
||||||
name: string,
|
|
||||||
dirname: string,
|
|
||||||
): { filepath: string, value: Function } {
|
|
||||||
const filepath = resolve.sync(name, { basedir: dirname });
|
|
||||||
|
|
||||||
const mod = requireModule("generator", filepath);
|
|
||||||
|
|
||||||
if (!mod) {
|
|
||||||
throw new Error(
|
|
||||||
`Generator ${name} relative to ${dirname} does not export an object`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (typeof mod.print !== "function") {
|
|
||||||
throw new Error(
|
|
||||||
`Generator ${name} relative to ${dirname} does not export a .print function`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const value = mod.print;
|
|
||||||
|
|
||||||
debug("Loaded generator %o from %o.", name, dirname);
|
|
||||||
|
|
||||||
return {
|
|
||||||
filepath,
|
|
||||||
value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function standardizeName(type: "plugin" | "preset", name: string) {
|
function standardizeName(type: "plugin" | "preset", name: string) {
|
||||||
// Let absolute and relative paths through.
|
// Let absolute and relative paths through.
|
||||||
if (path.isAbsolute(name)) return name;
|
if (path.isAbsolute(name)) return name;
|
||||||
|
|||||||
@ -12,6 +12,12 @@ import type {
|
|||||||
RootInputSourceMapOption,
|
RootInputSourceMapOption,
|
||||||
} from "./options";
|
} from "./options";
|
||||||
|
|
||||||
|
export type ValidatorSet = {
|
||||||
|
[string]: Validator<any>,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Validator<T> = (string, mixed) => T;
|
||||||
|
|
||||||
export function assertSourceMaps(
|
export function assertSourceMaps(
|
||||||
key: string,
|
key: string,
|
||||||
value: mixed,
|
value: mixed,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as context from "../index";
|
import * as context from "../index";
|
||||||
import Plugin from "./plugin";
|
import Plugin, { validatePluginObject } from "./plugin";
|
||||||
import defaults from "lodash/defaults";
|
import defaults from "lodash/defaults";
|
||||||
import merge from "lodash/merge";
|
import merge from "lodash/merge";
|
||||||
import buildConfigChain, { type ConfigItem } from "./build-config-chain";
|
import buildConfigChain, { type ConfigItem } from "./build-config-chain";
|
||||||
@ -12,12 +12,7 @@ import { makeWeakCache } from "./caching";
|
|||||||
import { getEnv } from "./helpers/environment";
|
import { getEnv } from "./helpers/environment";
|
||||||
import { validate, type ValidatedOptions, type PluginItem } from "./options";
|
import { validate, type ValidatedOptions, type PluginItem } from "./options";
|
||||||
|
|
||||||
import {
|
import { loadPlugin, loadPreset } from "./loading/files";
|
||||||
loadPlugin,
|
|
||||||
loadPreset,
|
|
||||||
loadParser,
|
|
||||||
loadGenerator,
|
|
||||||
} from "./loading/files";
|
|
||||||
|
|
||||||
type MergeOptions =
|
type MergeOptions =
|
||||||
| ConfigItem
|
| ConfigItem
|
||||||
@ -28,15 +23,6 @@ type MergeOptions =
|
|||||||
dirname: string,
|
dirname: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ALLOWED_PLUGIN_KEYS = new Set([
|
|
||||||
"name",
|
|
||||||
"manipulateOptions",
|
|
||||||
"pre",
|
|
||||||
"post",
|
|
||||||
"visitor",
|
|
||||||
"inherits",
|
|
||||||
]);
|
|
||||||
|
|
||||||
export default function manageOptions(opts: {}): {
|
export default function manageOptions(opts: {}): {
|
||||||
options: Object,
|
options: Object,
|
||||||
passes: Array<Array<Plugin>>,
|
passes: Array<Array<Plugin>>,
|
||||||
@ -205,7 +191,7 @@ const loadConfig = makeWeakCache((config: MergeOptions): {
|
|||||||
plugins: Array<BasicDescriptor>,
|
plugins: Array<BasicDescriptor>,
|
||||||
presets: Array<BasicDescriptor>,
|
presets: Array<BasicDescriptor>,
|
||||||
} => {
|
} => {
|
||||||
const options = normalizeOptions(config);
|
const options = config.options;
|
||||||
|
|
||||||
const plugins = (config.options.plugins || []).map((plugin, index) =>
|
const plugins = (config.options.plugins || []).map((plugin, index) =>
|
||||||
createDescriptor(plugin, loadPlugin, config.dirname, {
|
createDescriptor(plugin, loadPlugin, config.dirname, {
|
||||||
@ -275,37 +261,16 @@ function loadPluginDescriptor(descriptor: BasicDescriptor): Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const instantiatePlugin = makeWeakCache(
|
const instantiatePlugin = makeWeakCache(
|
||||||
(
|
({ value, options, dirname, alias }: LoadedDescriptor, cache): Plugin => {
|
||||||
{ value: pluginObj, options, dirname, alias }: LoadedDescriptor,
|
const pluginObj = validatePluginObject(value);
|
||||||
cache,
|
|
||||||
): Plugin => {
|
const plugin = Object.assign({}, pluginObj);
|
||||||
Object.keys(pluginObj).forEach(key => {
|
if (plugin.visitor) {
|
||||||
if (!ALLOWED_PLUGIN_KEYS.has(key)) {
|
plugin.visitor = traverse.explode(clone(plugin.visitor));
|
||||||
throw new Error(
|
|
||||||
`Plugin ${alias} provided an invalid property of ${key}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (
|
|
||||||
pluginObj.visitor &&
|
|
||||||
(pluginObj.visitor.enter || pluginObj.visitor.exit)
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
"Plugins aren't allowed to specify catch-all enter/exit handlers. " +
|
|
||||||
"Please target individual nodes.",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const plugin = Object.assign({}, pluginObj, {
|
|
||||||
visitor: clone(pluginObj.visitor || {}),
|
|
||||||
});
|
|
||||||
|
|
||||||
traverse.explode(plugin.visitor);
|
|
||||||
|
|
||||||
let inheritsDescriptor;
|
|
||||||
let inherits;
|
|
||||||
if (plugin.inherits) {
|
if (plugin.inherits) {
|
||||||
inheritsDescriptor = {
|
const inheritsDescriptor = {
|
||||||
alias: `${alias}$inherits`,
|
alias: `${alias}$inherits`,
|
||||||
value: plugin.inherits,
|
value: plugin.inherits,
|
||||||
options,
|
options,
|
||||||
@ -313,7 +278,7 @@ const instantiatePlugin = makeWeakCache(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// If the inherited plugin changes, reinstantiate this plugin.
|
// If the inherited plugin changes, reinstantiate this plugin.
|
||||||
inherits = cache.invalidate(() =>
|
const inherits = cache.invalidate(() =>
|
||||||
loadPluginDescriptor(inheritsDescriptor),
|
loadPluginDescriptor(inheritsDescriptor),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -324,8 +289,8 @@ const instantiatePlugin = makeWeakCache(
|
|||||||
plugin.manipulateOptions,
|
plugin.manipulateOptions,
|
||||||
);
|
);
|
||||||
plugin.visitor = traverse.visitors.merge([
|
plugin.visitor = traverse.visitors.merge([
|
||||||
inherits.visitor,
|
inherits.visitor || {},
|
||||||
plugin.visitor,
|
plugin.visitor || {},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,35 +316,6 @@ const instantiatePreset = makeWeakCache(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate and return the options object for the config.
|
|
||||||
*/
|
|
||||||
function normalizeOptions(config) {
|
|
||||||
//
|
|
||||||
const options = Object.assign({}, config.options);
|
|
||||||
|
|
||||||
if (options.parserOpts && typeof options.parserOpts.parser === "string") {
|
|
||||||
options.parserOpts = Object.assign({}, options.parserOpts);
|
|
||||||
(options.parserOpts: any).parser = loadParser(
|
|
||||||
options.parserOpts.parser,
|
|
||||||
config.dirname,
|
|
||||||
).value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
options.generatorOpts &&
|
|
||||||
typeof options.generatorOpts.generator === "string"
|
|
||||||
) {
|
|
||||||
options.generatorOpts = Object.assign({}, options.generatorOpts);
|
|
||||||
(options.generatorOpts: any).generator = loadGenerator(
|
|
||||||
options.generatorOpts.generator,
|
|
||||||
config.dirname,
|
|
||||||
).value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a plugin/preset item, resolve it into a standard format.
|
* Given a plugin/preset item, resolve it into a standard format.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -12,14 +12,10 @@ import {
|
|||||||
assertSourceMaps,
|
assertSourceMaps,
|
||||||
assertCompact,
|
assertCompact,
|
||||||
assertSourceType,
|
assertSourceType,
|
||||||
|
type ValidatorSet,
|
||||||
|
type Validator,
|
||||||
} from "./option-assertions";
|
} from "./option-assertions";
|
||||||
|
|
||||||
type ValidatorSet = {
|
|
||||||
[string]: Validator<any>,
|
|
||||||
};
|
|
||||||
|
|
||||||
type Validator<T> = (string, mixed) => T;
|
|
||||||
|
|
||||||
const ROOT_VALIDATORS: ValidatorSet = {
|
const ROOT_VALIDATORS: ValidatorSet = {
|
||||||
filename: (assertString: Validator<
|
filename: (assertString: Validator<
|
||||||
$PropertyType<ValidatedOptions, "filename">,
|
$PropertyType<ValidatedOptions, "filename">,
|
||||||
|
|||||||
@ -1,43 +1,123 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
// $FlowIssue recursion?
|
import {
|
||||||
|
assertString,
|
||||||
|
assertFunction,
|
||||||
|
assertObject,
|
||||||
|
type ValidatorSet,
|
||||||
|
type Validator,
|
||||||
|
} from "./option-assertions";
|
||||||
|
|
||||||
|
// Note: The casts here are just meant to be static assertions to make sure
|
||||||
|
// that the assertion functions actually assert that the value's type matches
|
||||||
|
// the declared types.
|
||||||
|
const VALIDATORS: ValidatorSet = {
|
||||||
|
name: (assertString: Validator<$PropertyType<PluginObject, "name">>),
|
||||||
|
manipulateOptions: (assertFunction: Validator<
|
||||||
|
$PropertyType<PluginObject, "manipulateOptions">,
|
||||||
|
>),
|
||||||
|
pre: (assertFunction: Validator<$PropertyType<PluginObject, "pre">>),
|
||||||
|
post: (assertFunction: Validator<$PropertyType<PluginObject, "post">>),
|
||||||
|
inherits: (assertFunction: Validator<
|
||||||
|
$PropertyType<PluginObject, "inherits">,
|
||||||
|
>),
|
||||||
|
visitor: (assertVisitorMap: Validator<
|
||||||
|
$PropertyType<PluginObject, "visitor">,
|
||||||
|
>),
|
||||||
|
|
||||||
|
parserOverride: (assertFunction: Validator<
|
||||||
|
$PropertyType<PluginObject, "parserOverride">,
|
||||||
|
>),
|
||||||
|
generatorOverride: (assertFunction: Validator<
|
||||||
|
$PropertyType<PluginObject, "generatorOverride">,
|
||||||
|
>),
|
||||||
|
};
|
||||||
|
|
||||||
|
function assertVisitorMap(key: string, value: mixed): VisitorMap {
|
||||||
|
const obj = assertObject(key, value);
|
||||||
|
if (obj) {
|
||||||
|
Object.keys(obj).forEach(prop => assertVisitorHandler(prop, obj[prop]));
|
||||||
|
|
||||||
|
if (obj.enter || obj.exit) {
|
||||||
|
throw new Error(
|
||||||
|
`.${key} cannot contain catch-all "enter" or "exit" handlers. Please target individual nodes.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (obj: any);
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertVisitorHandler(
|
||||||
|
key: string,
|
||||||
|
value: mixed,
|
||||||
|
): VisitorHandler | void {
|
||||||
|
if (value && typeof value === "object") {
|
||||||
|
Object.keys(value).forEach(handler => {
|
||||||
|
if (handler !== "enter" && handler !== "exit") {
|
||||||
|
throw new Error(
|
||||||
|
`.visitor["${key}"] may only have .enter and/or .exit handlers.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (typeof value !== "function") {
|
||||||
|
throw new Error(`.visitor["${key}"] must be a function`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (value: any);
|
||||||
|
}
|
||||||
|
|
||||||
|
type VisitorHandler = Function | { enter?: Function, exit?: Function };
|
||||||
|
export type VisitorMap = {
|
||||||
|
[string]: VisitorHandler,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PluginObject = {
|
||||||
|
name?: string,
|
||||||
|
manipulateOptions?: Function,
|
||||||
|
|
||||||
|
pre?: Function,
|
||||||
|
post?: Function,
|
||||||
|
|
||||||
|
inherits?: Function,
|
||||||
|
visitor?: VisitorMap,
|
||||||
|
|
||||||
|
parserOverride?: Function,
|
||||||
|
generatorOverride?: Function,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function validatePluginObject(obj: {}): PluginObject {
|
||||||
|
Object.keys(obj).forEach(key => {
|
||||||
|
const validator = VALIDATORS[key];
|
||||||
|
|
||||||
|
if (validator) validator(key, obj[key]);
|
||||||
|
else throw new Error(`.${key} is not a valid Plugin property`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (obj: any);
|
||||||
|
}
|
||||||
|
|
||||||
export default class Plugin {
|
export default class Plugin {
|
||||||
key: ?string;
|
key: ?string;
|
||||||
manipulateOptions: ?Function;
|
manipulateOptions: Function | void;
|
||||||
post: ?Function;
|
post: Function | void;
|
||||||
pre: ?Function;
|
pre: Function | void;
|
||||||
visitor: ?{};
|
visitor: {};
|
||||||
|
|
||||||
|
parserOverride: Function | void;
|
||||||
|
generatorOverride: Function | void;
|
||||||
|
|
||||||
options: {};
|
options: {};
|
||||||
|
|
||||||
constructor(plugin: {}, options: {}, key?: string) {
|
constructor(plugin: PluginObject, options: {}, key?: string) {
|
||||||
if (plugin.name != null && typeof plugin.name !== "string") {
|
|
||||||
throw new Error("Plugin .name must be a string, null, or undefined");
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
plugin.manipulateOptions != null &&
|
|
||||||
typeof plugin.manipulateOptions !== "function"
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
"Plugin .manipulateOptions must be a function, null, or undefined",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (plugin.post != null && typeof plugin.post !== "function") {
|
|
||||||
throw new Error("Plugin .post must be a function, null, or undefined");
|
|
||||||
}
|
|
||||||
if (plugin.pre != null && typeof plugin.pre !== "function") {
|
|
||||||
throw new Error("Plugin .pre must be a function, null, or undefined");
|
|
||||||
}
|
|
||||||
if (plugin.visitor != null && typeof plugin.visitor !== "object") {
|
|
||||||
throw new Error("Plugin .visitor must be an object, null, or undefined");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.key = plugin.name || key;
|
this.key = plugin.name || key;
|
||||||
|
|
||||||
this.manipulateOptions = plugin.manipulateOptions;
|
this.manipulateOptions = plugin.manipulateOptions;
|
||||||
this.post = plugin.post;
|
this.post = plugin.post;
|
||||||
this.pre = plugin.pre;
|
this.pre = plugin.pre;
|
||||||
this.visitor = plugin.visitor;
|
this.visitor = plugin.visitor || {};
|
||||||
|
this.parserOverride = plugin.parserOverride;
|
||||||
|
this.generatorOverride = plugin.generatorOverride;
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import type { PluginPasses } from "../../config";
|
||||||
import convertSourceMap, { type SourceMap } from "convert-source-map";
|
import convertSourceMap, { type SourceMap } from "convert-source-map";
|
||||||
import sourceMap from "source-map";
|
import sourceMap from "source-map";
|
||||||
import generate from "@babel/generator";
|
import generate from "@babel/generator";
|
||||||
@ -7,6 +8,7 @@ import generate from "@babel/generator";
|
|||||||
import type File from "./file";
|
import type File from "./file";
|
||||||
|
|
||||||
export default function generateCode(
|
export default function generateCode(
|
||||||
|
pluginPasses: PluginPasses,
|
||||||
file: File,
|
file: File,
|
||||||
): {
|
): {
|
||||||
outputCode: string,
|
outputCode: string,
|
||||||
@ -14,12 +16,33 @@ export default function generateCode(
|
|||||||
} {
|
} {
|
||||||
const { opts, ast, shebang, code, inputMap } = file;
|
const { opts, ast, shebang, code, inputMap } = file;
|
||||||
|
|
||||||
let gen = generate;
|
const results = [];
|
||||||
if (opts.generatorOpts && opts.generatorOpts.generator) {
|
for (const plugins of pluginPasses) {
|
||||||
gen = opts.generatorOpts.generator;
|
for (const plugin of plugins) {
|
||||||
|
const { generatorOverride } = plugin;
|
||||||
|
if (generatorOverride) {
|
||||||
|
const result = generatorOverride(
|
||||||
|
ast,
|
||||||
|
opts.generatorOpts,
|
||||||
|
code,
|
||||||
|
generate,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result !== undefined) results.push(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let { code: outputCode, map: outputMap } = gen(ast, opts.generatorOpts, code);
|
let result;
|
||||||
|
if (results.length === 0) {
|
||||||
|
result = generate(ast, opts.generatorOpts, code);
|
||||||
|
} else if (results.length === 1) {
|
||||||
|
result = results[0];
|
||||||
|
} else {
|
||||||
|
throw new Error("More than one plugin attempted to override codegen.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let { code: outputCode, map: outputMap } = result;
|
||||||
|
|
||||||
if (shebang) {
|
if (shebang) {
|
||||||
// add back shebang
|
// add back shebang
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import normalizeOptions from "./normalize-opts";
|
|||||||
import normalizeFile from "./normalize-file";
|
import normalizeFile from "./normalize-file";
|
||||||
|
|
||||||
import generateCode from "./file/generate";
|
import generateCode from "./file/generate";
|
||||||
import File from "./file/file";
|
import type File from "./file/file";
|
||||||
|
|
||||||
export type FileResultCallback = {
|
export type FileResultCallback = {
|
||||||
(Error, null): any,
|
(Error, null): any,
|
||||||
@ -48,19 +48,24 @@ export function runSync(
|
|||||||
code: string,
|
code: string,
|
||||||
ast: ?(BabelNodeFile | BabelNodeProgram),
|
ast: ?(BabelNodeFile | BabelNodeProgram),
|
||||||
): FileResult {
|
): FileResult {
|
||||||
const options = normalizeOptions(config);
|
const file = normalizeFile(
|
||||||
const input = normalizeFile(options, code, ast);
|
config.passes,
|
||||||
|
normalizeOptions(config),
|
||||||
const file = new File(options, input);
|
code,
|
||||||
|
ast,
|
||||||
|
);
|
||||||
|
|
||||||
transformFile(file, config.passes);
|
transformFile(file, config.passes);
|
||||||
|
|
||||||
const { outputCode, outputMap } = options.code ? generateCode(file) : {};
|
const opts = file.opts;
|
||||||
|
const { outputCode, outputMap } = opts.code
|
||||||
|
? generateCode(config.passes, file)
|
||||||
|
: {};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
metadata: file.metadata,
|
metadata: file.metadata,
|
||||||
options: options,
|
options: opts,
|
||||||
ast: options.ast ? file.ast : null,
|
ast: opts.ast ? file.ast : null,
|
||||||
code: outputCode === undefined ? null : outputCode,
|
code: outputCode === undefined ? null : outputCode,
|
||||||
map: outputMap === undefined ? null : outputMap,
|
map: outputMap === undefined ? null : outputMap,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as t from "@babel/types";
|
import * as t from "@babel/types";
|
||||||
|
import type { PluginPasses } from "../config";
|
||||||
import convertSourceMap, { typeof Converter } from "convert-source-map";
|
import convertSourceMap, { typeof Converter } from "convert-source-map";
|
||||||
import { parse } from "babylon";
|
import { parse } from "babylon";
|
||||||
import { codeFrameColumns } from "@babel/code-frame";
|
import { codeFrameColumns } from "@babel/code-frame";
|
||||||
|
import File from "./file/file";
|
||||||
|
|
||||||
const shebangRegex = /^#!.*/;
|
const shebangRegex = /^#!.*/;
|
||||||
|
|
||||||
@ -15,10 +17,11 @@ export type NormalizedFile = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function normalizeFile(
|
export default function normalizeFile(
|
||||||
|
pluginPasses: PluginPasses,
|
||||||
options: Object,
|
options: Object,
|
||||||
code: string,
|
code: string,
|
||||||
ast: ?(BabelNodeFile | BabelNodeProgram),
|
ast: ?(BabelNodeFile | BabelNodeProgram),
|
||||||
): NormalizedFile {
|
): File {
|
||||||
code = `${code || ""}`;
|
code = `${code || ""}`;
|
||||||
|
|
||||||
let shebang = null;
|
let shebang = null;
|
||||||
@ -45,35 +48,37 @@ export default function normalizeFile(
|
|||||||
throw new Error("AST root must be a Program or File node");
|
throw new Error("AST root must be a Program or File node");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ast = parser(options, code);
|
ast = parser(pluginPasses, options, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return new File(options, {
|
||||||
code,
|
code,
|
||||||
ast,
|
ast,
|
||||||
shebang,
|
shebang,
|
||||||
inputMap,
|
inputMap,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function parser(options, code) {
|
function parser(pluginPasses, 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 {
|
try {
|
||||||
return parseCode(code, parserOpts);
|
const results = [];
|
||||||
|
for (const plugins of pluginPasses) {
|
||||||
|
for (const plugin of plugins) {
|
||||||
|
const { parserOverride } = plugin;
|
||||||
|
if (parserOverride) {
|
||||||
|
const ast = parserOverride(code, options.parserOpts, parse);
|
||||||
|
|
||||||
|
if (ast !== undefined) results.push(ast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (results.length === 0) {
|
||||||
|
return parse(code, options.parserOpts);
|
||||||
|
} else if (results.length === 1) {
|
||||||
|
return results[0];
|
||||||
|
}
|
||||||
|
throw new Error("More than one plugin attempted to override parsing.");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const loc = err.loc;
|
const loc = err.loc;
|
||||||
if (loc) {
|
if (loc) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user