Refine babel core types (#11544)
Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
This commit is contained in:
parent
30835f14db
commit
601c824873
@ -28,3 +28,4 @@ esproposal.export_star_as=enable
|
|||||||
esproposal.optional_chaining=enable
|
esproposal.optional_chaining=enable
|
||||||
esproposal.nullish_coalescing=enable
|
esproposal.nullish_coalescing=enable
|
||||||
module.name_mapper='^@babel\/\([a-zA-Z0-9_\-]+\)$' -> '<PROJECT_ROOT>/packages/babel-\1/src/index'
|
module.name_mapper='^@babel\/\([a-zA-Z0-9_\-]+\)$' -> '<PROJECT_ROOT>/packages/babel-\1/src/index'
|
||||||
|
module.ignore_non_literal_requires=true
|
||||||
|
|||||||
@ -2,6 +2,10 @@
|
|||||||
* Basic declarations for the npm modules we use.
|
* Basic declarations for the npm modules we use.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
declare module "debug" {
|
||||||
|
declare export default (namespace: string) => (formatter: string, ...args: any[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
declare module "resolve" {
|
declare module "resolve" {
|
||||||
declare export default {
|
declare export default {
|
||||||
(string, {| basedir: string |}, (err: ?Error, res: string) => void): void;
|
(string, {| basedir: string |}, (err: ?Error, res: string) => void): void;
|
||||||
@ -27,6 +31,10 @@ declare module "lodash/merge" {
|
|||||||
declare export default <T: Object>(T, Object) => T;
|
declare export default <T: Object>(T, Object) => T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module "lodash/escapeRegExp" {
|
||||||
|
declare export default (toEscape?: string) => string;
|
||||||
|
}
|
||||||
|
|
||||||
declare module "semver" {
|
declare module "semver" {
|
||||||
declare class SemVer {
|
declare class SemVer {
|
||||||
build: Array<string>;
|
build: Array<string>;
|
||||||
|
|||||||
@ -108,7 +108,7 @@ function makeCachedFunction<ArgT, ResultT, SideChannel, Cache: *>(
|
|||||||
const asyncContext = yield* isAsync();
|
const asyncContext = yield* isAsync();
|
||||||
const callCache = asyncContext ? callCacheAsync : callCacheSync;
|
const callCache = asyncContext ? callCacheAsync : callCacheSync;
|
||||||
|
|
||||||
const cached = yield* getCachedValueOrWait(
|
const cached = yield* getCachedValueOrWait<ArgT, ResultT, SideChannel>(
|
||||||
asyncContext,
|
asyncContext,
|
||||||
callCache,
|
callCache,
|
||||||
futureCache,
|
futureCache,
|
||||||
@ -119,7 +119,7 @@ function makeCachedFunction<ArgT, ResultT, SideChannel, Cache: *>(
|
|||||||
|
|
||||||
const cache = new CacheConfigurator(data);
|
const cache = new CacheConfigurator(data);
|
||||||
|
|
||||||
const handlerResult = handler(arg, cache);
|
const handlerResult: Handler<ResultT> | ResultT = handler(arg, cache);
|
||||||
|
|
||||||
let finishLock: ?Lock<ResultT>;
|
let finishLock: ?Lock<ResultT>;
|
||||||
let value: ResultT;
|
let value: ResultT;
|
||||||
@ -313,7 +313,7 @@ class CacheConfigurator<SideChannel = void> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (isThenable(key)) {
|
if (isThenable(key)) {
|
||||||
return key.then(key => {
|
return key.then((key: mixed) => {
|
||||||
this._pairs.push([key, fn]);
|
this._pairs.push([key, fn]);
|
||||||
return key;
|
return key;
|
||||||
});
|
});
|
||||||
@ -369,7 +369,13 @@ function makeSimpleConfigurator(
|
|||||||
|
|
||||||
// Types are limited here so that in the future these values can be used
|
// Types are limited here so that in the future these values can be used
|
||||||
// as part of Babel's caching logic.
|
// as part of Babel's caching logic.
|
||||||
type SimpleType = string | boolean | number | null | void | Promise<SimpleType>;
|
export type SimpleType =
|
||||||
|
| string
|
||||||
|
| boolean
|
||||||
|
| number
|
||||||
|
| null
|
||||||
|
| void
|
||||||
|
| Promise<SimpleType>;
|
||||||
export function assertSimpleType(value: mixed): SimpleType {
|
export function assertSimpleType(value: mixed): SimpleType {
|
||||||
if (isThenable(value)) {
|
if (isThenable(value)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
@ -76,7 +76,6 @@ export const buildPresetChainWalker: (
|
|||||||
arg: PresetInstance,
|
arg: PresetInstance,
|
||||||
context: *,
|
context: *,
|
||||||
) => * = makeChainWalker({
|
) => * = makeChainWalker({
|
||||||
init: arg => arg,
|
|
||||||
root: preset => loadPresetDescriptors(preset),
|
root: preset => loadPresetDescriptors(preset),
|
||||||
env: (preset, envName) => loadPresetEnvDescriptors(preset)(envName),
|
env: (preset, envName) => loadPresetEnvDescriptors(preset)(envName),
|
||||||
overrides: (preset, index) => loadPresetOverridesDescriptors(preset)(index),
|
overrides: (preset, index) => loadPresetOverridesDescriptors(preset)(index),
|
||||||
@ -419,12 +418,12 @@ function makeChainWalker<ArgT: { options: ValidatedOptions, dirname: string }>({
|
|||||||
env,
|
env,
|
||||||
overrides,
|
overrides,
|
||||||
overridesEnv,
|
overridesEnv,
|
||||||
}: {
|
}: {|
|
||||||
root: ArgT => OptionsAndDescriptors,
|
root: ArgT => OptionsAndDescriptors,
|
||||||
env: (ArgT, string) => OptionsAndDescriptors | null,
|
env: (ArgT, string) => OptionsAndDescriptors | null,
|
||||||
overrides: (ArgT, number) => OptionsAndDescriptors,
|
overrides: (ArgT, number) => OptionsAndDescriptors,
|
||||||
overridesEnv: (ArgT, number, string) => OptionsAndDescriptors | null,
|
overridesEnv: (ArgT, number, string) => OptionsAndDescriptors | null,
|
||||||
}): (
|
|}): (
|
||||||
ArgT,
|
ArgT,
|
||||||
ConfigContext,
|
ConfigContext,
|
||||||
Set<ConfigFile> | void,
|
Set<ConfigFile> | void,
|
||||||
|
|||||||
@ -151,7 +151,7 @@ export function* loadConfig(
|
|||||||
* Read the given config file, returning the result. Returns null if no config was found, but will
|
* Read the given config file, returning the result. Returns null if no config was found, but will
|
||||||
* throw if there are parsing errors while loading a config.
|
* throw if there are parsing errors while loading a config.
|
||||||
*/
|
*/
|
||||||
function readConfig(filepath, envName, caller) {
|
function readConfig(filepath, envName, caller): Handler<ConfigFile | null> {
|
||||||
const ext = path.extname(filepath);
|
const ext = path.extname(filepath);
|
||||||
return ext === ".js" || ext === ".cjs" || ext === ".mjs"
|
return ext === ".js" || ext === ".cjs" || ext === ".mjs"
|
||||||
? readConfigJS(filepath, { envName, caller })
|
? readConfigJS(filepath, { envName, caller })
|
||||||
@ -236,7 +236,7 @@ const readConfigJS = makeStrongCache(function* readConfigJS(
|
|||||||
|
|
||||||
const packageToBabelConfig = makeWeakCacheSync(
|
const packageToBabelConfig = makeWeakCacheSync(
|
||||||
(file: ConfigFile): ConfigFile | null => {
|
(file: ConfigFile): ConfigFile | null => {
|
||||||
const babel = file.options[("babel": string)];
|
const babel: mixed = file.options[("babel": string)];
|
||||||
|
|
||||||
if (typeof babel === "undefined") return null;
|
if (typeof babel === "undefined") return null;
|
||||||
|
|
||||||
@ -252,7 +252,7 @@ const packageToBabelConfig = makeWeakCacheSync(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const readConfigJSON5 = makeStaticFileCache((filepath, content) => {
|
const readConfigJSON5 = makeStaticFileCache((filepath, content): ConfigFile => {
|
||||||
let options;
|
let options;
|
||||||
try {
|
try {
|
||||||
options = json5.parse(content);
|
options = json5.parse(content);
|
||||||
@ -281,7 +281,7 @@ const readIgnoreConfig = makeStaticFileCache((filepath, content) => {
|
|||||||
const ignoreDir = path.dirname(filepath);
|
const ignoreDir = path.dirname(filepath);
|
||||||
const ignorePatterns = content
|
const ignorePatterns = content
|
||||||
.split("\n")
|
.split("\n")
|
||||||
.map(line => line.replace(/#(.*?)$/, "").trim())
|
.map<string>(line => line.replace(/#(.*?)$/, "").trim())
|
||||||
.filter(line => !!line);
|
.filter(line => !!line);
|
||||||
|
|
||||||
for (const pattern of ignorePatterns) {
|
for (const pattern of ignorePatterns) {
|
||||||
@ -299,7 +299,7 @@ const readIgnoreConfig = makeStaticFileCache((filepath, content) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
function throwConfigError() {
|
function throwConfigError(): empty {
|
||||||
throw new Error(`\
|
throw new Error(`\
|
||||||
Caching was left unconfigured. Babel's plugins, presets, and .babelrc.js files can be configured
|
Caching was left unconfigured. Babel's plugins, presets, and .babelrc.js files can be configured
|
||||||
for various types of caching, using the first param of their handler functions:
|
for various types of caching, using the first param of their handler functions:
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @flow
|
||||||
// We keep this in a seprate file so that in older node versions, where
|
// We keep this in a seprate file so that in older node versions, where
|
||||||
// import() isn't supported, we can try/catch around the require() call
|
// import() isn't supported, we can try/catch around the require() call
|
||||||
// when loading this file.
|
// when loading this file.
|
||||||
|
|||||||
@ -39,12 +39,14 @@ const readConfigPackage = makeStaticFileCache(
|
|||||||
(filepath, content): ConfigFile => {
|
(filepath, content): ConfigFile => {
|
||||||
let options;
|
let options;
|
||||||
try {
|
try {
|
||||||
options = JSON.parse(content);
|
options = (JSON.parse(content): mixed);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
err.message = `${filepath}: Error while parsing JSON - ${err.message}`;
|
err.message = `${filepath}: Error while parsing JSON - ${err.message}`;
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!options) throw new Error(`${filepath}: No config detected`);
|
||||||
|
|
||||||
if (typeof options !== "object") {
|
if (typeof options !== "object") {
|
||||||
throw new Error(`${filepath}: Config returned typeof ${typeof options}`);
|
throw new Error(`${filepath}: Config returned typeof ${typeof options}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,7 +105,7 @@ function resolveStandardizedName(
|
|||||||
try {
|
try {
|
||||||
resolve.sync(name, { basedir: dirname });
|
resolve.sync(name, { basedir: dirname });
|
||||||
resolvedOriginal = true;
|
resolvedOriginal = true;
|
||||||
} catch (e2) {}
|
} catch {}
|
||||||
|
|
||||||
if (resolvedOriginal) {
|
if (resolvedOriginal) {
|
||||||
e.message += `\n- If you want to resolve "${name}", use "module:${name}"`;
|
e.message += `\n- If you want to resolve "${name}", use "module:${name}"`;
|
||||||
@ -118,7 +118,7 @@ function resolveStandardizedName(
|
|||||||
basedir: dirname,
|
basedir: dirname,
|
||||||
});
|
});
|
||||||
resolvedBabel = true;
|
resolvedBabel = true;
|
||||||
} catch (e2) {}
|
} catch {}
|
||||||
|
|
||||||
if (resolvedBabel) {
|
if (resolvedBabel) {
|
||||||
e.message += `\n- Did you mean "@babel/${name}"?`;
|
e.message += `\n- Did you mean "@babel/${name}"?`;
|
||||||
@ -129,7 +129,7 @@ function resolveStandardizedName(
|
|||||||
try {
|
try {
|
||||||
resolve.sync(standardizeName(oppositeType, name), { basedir: dirname });
|
resolve.sync(standardizeName(oppositeType, name), { basedir: dirname });
|
||||||
resolvedOppositeType = true;
|
resolvedOppositeType = true;
|
||||||
} catch (e2) {}
|
} catch {}
|
||||||
|
|
||||||
if (resolvedOppositeType) {
|
if (resolvedOppositeType) {
|
||||||
e.message += `\n- Did you accidentally pass a ${oppositeType} as a ${type}?`;
|
e.message += `\n- Did you accidentally pass a ${oppositeType} as a ${type}?`;
|
||||||
@ -151,7 +151,6 @@ function requireModule(type: string, name: string): mixed {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
LOADING_MODULES.add(name);
|
LOADING_MODULES.add(name);
|
||||||
// $FlowIssue
|
|
||||||
return require(name);
|
return require(name);
|
||||||
} finally {
|
} finally {
|
||||||
LOADING_MODULES.delete(name);
|
LOADING_MODULES.delete(name);
|
||||||
|
|||||||
@ -66,7 +66,7 @@ export default gensync<[any], ResolvedConfig | null>(function* loadFullConfig(
|
|||||||
const { options, context } = result;
|
const { options, context } = result;
|
||||||
|
|
||||||
const optionDefaults = {};
|
const optionDefaults = {};
|
||||||
const passes = [[]];
|
const passes: Array<Array<Plugin>> = [[]];
|
||||||
try {
|
try {
|
||||||
const { plugins, presets } = options;
|
const { plugins, presets } = options;
|
||||||
|
|
||||||
@ -74,14 +74,8 @@ export default gensync<[any], ResolvedConfig | null>(function* loadFullConfig(
|
|||||||
throw new Error("Assertion failure - plugins and presets exist");
|
throw new Error("Assertion failure - plugins and presets exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
const ignored = yield* (function* recurseDescriptors(
|
const ignored = yield* (function* recurseDescriptors(config, pass) {
|
||||||
config: {
|
const plugins: Array<Plugin> = [];
|
||||||
plugins: Array<UnloadedDescriptor>,
|
|
||||||
presets: Array<UnloadedDescriptor>,
|
|
||||||
},
|
|
||||||
pass: Array<Plugin>,
|
|
||||||
) {
|
|
||||||
const plugins = [];
|
|
||||||
for (let i = 0; i < config.plugins.length; i++) {
|
for (let i = 0; i < config.plugins.length; i++) {
|
||||||
const descriptor = config.plugins[i];
|
const descriptor = config.plugins[i];
|
||||||
if (descriptor.options !== false) {
|
if (descriptor.options !== false) {
|
||||||
@ -103,7 +97,10 @@ export default gensync<[any], ResolvedConfig | null>(function* loadFullConfig(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const presets = [];
|
const presets: Array<{|
|
||||||
|
preset: ConfigChain | null,
|
||||||
|
pass: Array<Plugin>,
|
||||||
|
|}> = [];
|
||||||
for (let i = 0; i < config.presets.length; i++) {
|
for (let i = 0; i < config.presets.length; i++) {
|
||||||
const descriptor = config.presets[i];
|
const descriptor = config.presets[i];
|
||||||
if (descriptor.options !== false) {
|
if (descriptor.options !== false) {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
assertSimpleType,
|
assertSimpleType,
|
||||||
type CacheConfigurator,
|
type CacheConfigurator,
|
||||||
type SimpleCacheConfigurator,
|
type SimpleCacheConfigurator,
|
||||||
|
type SimpleType,
|
||||||
} from "../caching";
|
} from "../caching";
|
||||||
|
|
||||||
import type { CallerMetadata } from "../validation/options";
|
import type { CallerMetadata } from "../validation/options";
|
||||||
@ -17,13 +18,15 @@ type EnvFunction = {
|
|||||||
(Array<string>): boolean,
|
(Array<string>): boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type CallerFactory = ((CallerMetadata | void) => mixed) => SimpleType;
|
||||||
|
|
||||||
export type PluginAPI = {|
|
export type PluginAPI = {|
|
||||||
version: string,
|
version: string,
|
||||||
cache: SimpleCacheConfigurator,
|
cache: SimpleCacheConfigurator,
|
||||||
env: EnvFunction,
|
env: EnvFunction,
|
||||||
async: () => boolean,
|
async: () => boolean,
|
||||||
assertVersion: typeof assertVersion,
|
assertVersion: typeof assertVersion,
|
||||||
caller?: any,
|
caller?: CallerFactory,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
export default function makeAPI(
|
export default function makeAPI(
|
||||||
@ -37,7 +40,7 @@ export default function makeAPI(
|
|||||||
}
|
}
|
||||||
if (!Array.isArray(value)) value = [value];
|
if (!Array.isArray(value)) value = [value];
|
||||||
|
|
||||||
return value.some(entry => {
|
return value.some((entry: mixed) => {
|
||||||
if (typeof entry !== "string") {
|
if (typeof entry !== "string") {
|
||||||
throw new Error("Unexpected non-string value");
|
throw new Error("Unexpected non-string value");
|
||||||
}
|
}
|
||||||
@ -45,8 +48,7 @@ export default function makeAPI(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const caller: any = cb =>
|
const caller = cb => cache.using(data => assertSimpleType(cb(data.caller)));
|
||||||
cache.using(data => assertSimpleType(cb(data.caller)));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
version: coreVersion,
|
version: coreVersion,
|
||||||
|
|||||||
@ -103,7 +103,7 @@ class ConfigItem {
|
|||||||
// programmatically, and also make sure that if people happen to
|
// programmatically, and also make sure that if people happen to
|
||||||
// pass the item through JSON.stringify, it doesn't show up.
|
// pass the item through JSON.stringify, it doesn't show up.
|
||||||
this._descriptor = descriptor;
|
this._descriptor = descriptor;
|
||||||
Object.defineProperty(this, "_descriptor", ({ enumerable: false }: any));
|
Object.defineProperty(this, "_descriptor", { enumerable: false });
|
||||||
|
|
||||||
this.value = this._descriptor.value;
|
this.value = this._descriptor.value;
|
||||||
this.options = this._descriptor.options;
|
this.options = this._descriptor.options;
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import type { PluginObject } from "./validation/plugins";
|
|||||||
|
|
||||||
export default class Plugin {
|
export default class Plugin {
|
||||||
key: ?string;
|
key: ?string;
|
||||||
manipulateOptions: Function | void;
|
manipulateOptions: ((options: mixed, parserOpts: mixed) => void) | void;
|
||||||
post: Function | void;
|
post: Function | void;
|
||||||
pre: Function | void;
|
pre: Function | void;
|
||||||
visitor: {};
|
visitor: {};
|
||||||
|
|||||||
@ -18,6 +18,8 @@ import type {
|
|||||||
RootMode,
|
RootMode,
|
||||||
} from "./options";
|
} from "./options";
|
||||||
|
|
||||||
|
export type { RootPath } from "./options";
|
||||||
|
|
||||||
export type ValidatorSet = {
|
export type ValidatorSet = {
|
||||||
[string]: Validator<any>,
|
[string]: Validator<any>,
|
||||||
};
|
};
|
||||||
@ -192,7 +194,10 @@ export function assertBoolean(loc: GeneralPath, value: mixed): boolean | void {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function assertObject(loc: GeneralPath, value: mixed): {} | void {
|
export function assertObject(
|
||||||
|
loc: GeneralPath,
|
||||||
|
value: mixed,
|
||||||
|
): { +[string]: mixed } | void {
|
||||||
if (
|
if (
|
||||||
value !== undefined &&
|
value !== undefined &&
|
||||||
(typeof value !== "object" || Array.isArray(value) || !value)
|
(typeof value !== "object" || Array.isArray(value) || !value)
|
||||||
|
|||||||
@ -276,7 +276,7 @@ export type OptionsSource =
|
|||||||
| "preset"
|
| "preset"
|
||||||
| "plugin";
|
| "plugin";
|
||||||
|
|
||||||
type RootPath = $ReadOnly<{
|
export type RootPath = $ReadOnly<{
|
||||||
type: "root",
|
type: "root",
|
||||||
source: OptionsSource,
|
source: OptionsSource,
|
||||||
}>;
|
}>;
|
||||||
@ -311,7 +311,7 @@ function validateNested(loc: NestingPath, opts: {}) {
|
|||||||
|
|
||||||
assertNoDuplicateSourcemap(opts);
|
assertNoDuplicateSourcemap(opts);
|
||||||
|
|
||||||
Object.keys(opts).forEach(key => {
|
Object.keys(opts).forEach((key: string) => {
|
||||||
const optLoc = {
|
const optLoc = {
|
||||||
type: "option",
|
type: "option",
|
||||||
name: key,
|
name: key,
|
||||||
@ -364,7 +364,10 @@ function throwUnknownError(loc: OptionPath) {
|
|||||||
const key = loc.name;
|
const key = loc.name;
|
||||||
|
|
||||||
if (removed[key]) {
|
if (removed[key]) {
|
||||||
const { message, version = 5 } = removed[key];
|
const {
|
||||||
|
message,
|
||||||
|
version = 5,
|
||||||
|
}: { message: string, version?: number } = removed[key];
|
||||||
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Using removed Babel ${version} option: ${msg(loc)} - ${message}`,
|
`Using removed Babel ${version} option: ${msg(loc)} - ${message}`,
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
|
// @flow
|
||||||
import {
|
import {
|
||||||
assertString,
|
assertString,
|
||||||
assertFunction,
|
assertFunction,
|
||||||
assertObject,
|
assertObject,
|
||||||
|
msg,
|
||||||
type ValidatorSet,
|
type ValidatorSet,
|
||||||
type Validator,
|
type Validator,
|
||||||
|
type OptionPath,
|
||||||
|
type RootPath,
|
||||||
} from "./option-assertions";
|
} from "./option-assertions";
|
||||||
|
|
||||||
// Note: The casts here are just meant to be static assertions to make sure
|
// Note: The casts here are just meant to be static assertions to make sure
|
||||||
@ -31,14 +35,16 @@ const VALIDATORS: ValidatorSet = {
|
|||||||
>),
|
>),
|
||||||
};
|
};
|
||||||
|
|
||||||
function assertVisitorMap(key: string, value: mixed): VisitorMap {
|
function assertVisitorMap(loc: OptionPath, value: mixed): VisitorMap {
|
||||||
const obj = assertObject(key, value);
|
const obj = assertObject(loc, value);
|
||||||
if (obj) {
|
if (obj) {
|
||||||
Object.keys(obj).forEach(prop => assertVisitorHandler(prop, obj[prop]));
|
Object.keys(obj).forEach(prop => assertVisitorHandler(prop, obj[prop]));
|
||||||
|
|
||||||
if (obj.enter || obj.exit) {
|
if (obj.enter || obj.exit) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`.${key} cannot contain catch-all "enter" or "exit" handlers. Please target individual nodes.`,
|
`${msg(
|
||||||
|
loc,
|
||||||
|
)} cannot contain catch-all "enter" or "exit" handlers. Please target individual nodes.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,7 +56,7 @@ function assertVisitorHandler(
|
|||||||
value: mixed,
|
value: mixed,
|
||||||
): VisitorHandler | void {
|
): VisitorHandler | void {
|
||||||
if (value && typeof value === "object") {
|
if (value && typeof value === "object") {
|
||||||
Object.keys(value).forEach(handler => {
|
Object.keys(value).forEach((handler: string) => {
|
||||||
if (handler !== "enter" && handler !== "exit") {
|
if (handler !== "enter" && handler !== "exit") {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`.visitor["${key}"] may only have .enter and/or .exit handlers.`,
|
`.visitor["${key}"] may only have .enter and/or .exit handlers.`,
|
||||||
@ -71,7 +77,7 @@ export type VisitorMap = {
|
|||||||
|
|
||||||
export type PluginObject = {
|
export type PluginObject = {
|
||||||
name?: string,
|
name?: string,
|
||||||
manipulateOptions?: Function,
|
manipulateOptions?: (options: mixed, parserOpts: mixed) => void,
|
||||||
|
|
||||||
pre?: Function,
|
pre?: Function,
|
||||||
post?: Function,
|
post?: Function,
|
||||||
@ -88,16 +94,17 @@ export function validatePluginObject(obj: {}): PluginObject {
|
|||||||
type: "root",
|
type: "root",
|
||||||
source: "plugin",
|
source: "plugin",
|
||||||
};
|
};
|
||||||
Object.keys(obj).forEach(key => {
|
Object.keys(obj).forEach((key: string) => {
|
||||||
const validator = VALIDATORS[key];
|
const validator = VALIDATORS[key];
|
||||||
const optLoc = {
|
|
||||||
type: "option",
|
|
||||||
name: key,
|
|
||||||
parent: rootPath,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (validator) validator(optLoc, obj[key]);
|
if (validator) {
|
||||||
else {
|
const optLoc: OptionPath = {
|
||||||
|
type: "option",
|
||||||
|
name: key,
|
||||||
|
parent: rootPath,
|
||||||
|
};
|
||||||
|
validator(optLoc, obj[key]);
|
||||||
|
} else {
|
||||||
const invalidPluginPropertyError = new Error(
|
const invalidPluginPropertyError = new Error(
|
||||||
`.${key} is not a valid Plugin property`,
|
`.${key} is not a valid Plugin property`,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -339,6 +339,23 @@ describe("@babel/core config loading", () => {
|
|||||||
/\.inherits must be a function, or undefined/,
|
/\.inherits must be a function, or undefined/,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should throw when plugin contains `enter` handler", () => {
|
||||||
|
const fooPlugin = {
|
||||||
|
visitor: {
|
||||||
|
enter() {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const opts = {
|
||||||
|
cwd: path.dirname(FILEPATH),
|
||||||
|
filename: FILEPATH,
|
||||||
|
plugins: [fooPlugin],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(() => loadConfig(opts)).toThrow(
|
||||||
|
/\.visitor cannot contain catch-all "enter" or "exit" handlers\. Please target individual nodes\./,
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("caller metadata", () => {
|
describe("caller metadata", () => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user