Convert @babel/core to TypeScript (#12929)

Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
This commit is contained in:
Bogdan Savluk 2021-03-27 02:03:15 +01:00 committed by Nicolò Ribaudo
parent c8a91d9eef
commit a647b9ea6b
53 changed files with 1265 additions and 1200 deletions

View File

@ -42,10 +42,10 @@
"./lib/config/resolve-targets.js": "./lib/config/resolve-targets-browser.js", "./lib/config/resolve-targets.js": "./lib/config/resolve-targets-browser.js",
"./lib/transform-file.js": "./lib/transform-file-browser.js", "./lib/transform-file.js": "./lib/transform-file-browser.js",
"./lib/transformation/util/clone-deep.js": "./lib/transformation/util/clone-deep-browser.js", "./lib/transformation/util/clone-deep.js": "./lib/transformation/util/clone-deep-browser.js",
"./src/config/files/index.js": "./src/config/files/index-browser.js", "./src/config/files/index.ts": "./src/config/files/index-browser.ts",
"./src/config/resolve-targets.js": "./src/config/resolve-targets-browser.js", "./src/config/resolve-targets.ts": "./src/config/resolve-targets-browser.ts",
"./src/transform-file.js": "./src/transform-file-browser.js", "./src/transform-file.ts": "./src/transform-file-browser.ts",
"./src/transformation/util/clone-deep.js": "./src/transformation/util/clone-deep-browser.js" "./src/transformation/util/clone-deep.ts": "./src/transformation/util/clone-deep-browser.ts"
}, },
"dependencies": { "dependencies": {
"@babel/code-frame": "workspace:^7.12.13", "@babel/code-frame": "workspace:^7.12.13",
@ -65,6 +65,12 @@
"source-map": "^0.5.0" "source-map": "^0.5.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/helper-transform-fixture-test-runner": "workspace:*" "@babel/helper-transform-fixture-test-runner": "workspace:*",
"@types/convert-source-map": "^1.5.1",
"@types/debug": "^4.1.0",
"@types/lodash": "^4.14.150",
"@types/resolve": "^1.3.2",
"@types/semver": "^5.4.0",
"@types/source-map": "^0.5.0"
} }
} }

View File

@ -1,5 +1,3 @@
// @flow
import type { Targets } from "@babel/helper-compilation-targets"; import type { Targets } from "@babel/helper-compilation-targets";
import type { ConfigContext } from "./config-chain"; import type { ConfigContext } from "./config-chain";
@ -8,25 +6,23 @@ import type { CallerMetadata } from "./validation/options";
export type { ConfigContext as FullConfig }; export type { ConfigContext as FullConfig };
export type FullPreset = { export type FullPreset = {
...ConfigContext, targets: Targets;
targets: Targets, } & ConfigContext;
};
export type FullPlugin = { export type FullPlugin = {
...FullPreset, assumptions: { [name: string]: boolean };
assumptions: { [name: string]: boolean }, } & FullPreset;
};
// Context not including filename since it is used in places that cannot // Context not including filename since it is used in places that cannot
// process 'ignore'/'only' and other filename-based logic. // process 'ignore'/'only' and other filename-based logic.
export type SimpleConfig = { export type SimpleConfig = {
envName: string, envName: string;
caller: CallerMetadata | void, caller: CallerMetadata | void;
}; };
export type SimplePreset = { export type SimplePreset = {
...SimpleConfig, targets: Targets;
targets: Targets, } & SimpleConfig;
};
export type SimplePlugin = { export type SimplePlugin = {
...SimplePreset, assumptions: {
assumptions: { [name: string]: boolean }, [name: string]: boolean;
}; };
} & SimplePreset;

View File

@ -1,6 +1,5 @@
// @flow import gensync from "gensync";
import type { Handler } from "gensync";
import gensync, { type Handler } from "gensync";
import { import {
maybeAsync, maybeAsync,
isAsync, isAsync,
@ -12,60 +11,61 @@ import { isIterableIterator } from "./util";
export type { CacheConfigurator }; export type { CacheConfigurator };
export type SimpleCacheConfigurator = SimpleCacheConfiguratorFn & export type SimpleCacheConfigurator = {
SimpleCacheConfiguratorObj; (forever: boolean): void;
<T>(handler: () => T): T;
type SimpleCacheConfiguratorFn = { forever: () => void;
(boolean): void, never: () => void;
<T>(handler: () => T): T, using: <T>(handler: () => T) => T;
}; invalidate: <T>(handler: () => T) => T;
type SimpleCacheConfiguratorObj = {
forever: () => void,
never: () => void,
using: <T>(handler: () => T) => T,
invalidate: <T>(handler: () => T) => T,
}; };
export type CacheEntry<ResultT, SideChannel> = Array<{ export type CacheEntry<ResultT, SideChannel> = Array<{
value: ResultT, value: ResultT;
valid: SideChannel => Handler<boolean>, valid: (channel: SideChannel) => Handler<boolean>;
}>; }>;
const synchronize = <ArgsT, ResultT>( const synchronize = <ArgsT extends any[], ResultT>(
gen: (...ArgsT) => Handler<ResultT>, gen: (...args: ArgsT) => Handler<ResultT>,
// $FlowIssue https://github.com/facebook/flow/issues/7279
): ((...args: ArgsT) => ResultT) => { ): ((...args: ArgsT) => ResultT) => {
return gensync(gen).sync; return gensync(gen).sync;
}; };
// eslint-disable-next-line require-yield, no-unused-vars // eslint-disable-next-line require-yield
function* genTrue(data: any) { function* genTrue() {
return true; return true;
} }
export function makeWeakCache<ArgT, ResultT, SideChannel>( export function makeWeakCache<ArgT extends object, ResultT, SideChannel>(
handler: (ArgT, CacheConfigurator<SideChannel>) => Handler<ResultT> | ResultT, handler: (
): (ArgT, SideChannel) => Handler<ResultT> { arg: ArgT,
return makeCachedFunction<ArgT, ResultT, SideChannel, *>(WeakMap, handler); cache: CacheConfigurator<SideChannel>,
) => Handler<ResultT> | ResultT,
): (arg: ArgT, data: SideChannel) => Handler<ResultT> {
return makeCachedFunction<ArgT, ResultT, SideChannel>(WeakMap, handler);
} }
export function makeWeakCacheSync<ArgT, ResultT, SideChannel>( export function makeWeakCacheSync<ArgT extends object, ResultT, SideChannel>(
handler: (ArgT, CacheConfigurator<SideChannel>) => ResultT, handler: (arg: ArgT, cache?: CacheConfigurator<SideChannel>) => ResultT,
): (ArgT, SideChannel) => ResultT { ): (arg: ArgT, data?: SideChannel) => ResultT {
return synchronize<[ArgT, SideChannel], ResultT>( return synchronize<[ArgT, SideChannel], ResultT>(
makeWeakCache<ArgT, ResultT, SideChannel>(handler), makeWeakCache<ArgT, ResultT, SideChannel>(handler),
); );
} }
export function makeStrongCache<ArgT, ResultT, SideChannel>( export function makeStrongCache<ArgT, ResultT, SideChannel>(
handler: (ArgT, CacheConfigurator<SideChannel>) => Handler<ResultT> | ResultT, handler: (
): (ArgT, SideChannel) => Handler<ResultT> { arg: ArgT,
return makeCachedFunction<ArgT, ResultT, SideChannel, *>(Map, handler); cache: CacheConfigurator<SideChannel>,
) => Handler<ResultT> | ResultT,
): (arg: ArgT, data: SideChannel) => Handler<ResultT> {
return makeCachedFunction<ArgT, ResultT, SideChannel>(Map, handler);
} }
export function makeStrongCacheSync<ArgT, ResultT, SideChannel>( export function makeStrongCacheSync<ArgT, ResultT, SideChannel>(
handler: (ArgT, CacheConfigurator<SideChannel>) => ResultT, handler: (arg: ArgT, cache?: CacheConfigurator<SideChannel>) => ResultT,
): (ArgT, SideChannel) => ResultT { ): (arg: ArgT, data?: SideChannel) => ResultT {
return synchronize<[ArgT, SideChannel], ResultT>( return synchronize<[ArgT, SideChannel], ResultT>(
makeStrongCache<ArgT, ResultT, SideChannel>(handler), makeStrongCache<ArgT, ResultT, SideChannel>(handler),
); );
@ -96,13 +96,16 @@ export function makeStrongCacheSync<ArgT, ResultT, SideChannel>(
* 6. Store the result in the cache * 6. Store the result in the cache
* 7. RETURN the result * 7. RETURN the result
*/ */
function makeCachedFunction<ArgT, ResultT, SideChannel, Cache: *>( function makeCachedFunction<ArgT, ResultT, SideChannel>(
CallCache: Class<Cache>, CallCache: new <Cached>() => CacheMap<ArgT, Cached, SideChannel>,
handler: (ArgT, CacheConfigurator<SideChannel>) => Handler<ResultT> | ResultT, handler: (
): (ArgT, SideChannel) => Handler<ResultT> { arg: ArgT,
const callCacheSync = new CallCache(); cache: CacheConfigurator<SideChannel>,
const callCacheAsync = new CallCache(); ) => Handler<ResultT> | ResultT,
const futureCache = new CallCache(); ): (arg: ArgT, data: SideChannel) => Handler<ResultT> {
const callCacheSync = new CallCache<ResultT>();
const callCacheAsync = new CallCache<ResultT>();
const futureCache = new CallCache<Lock<ResultT>>();
return function* cachedFunction(arg: ArgT, data: SideChannel) { return function* cachedFunction(arg: ArgT, data: SideChannel) {
const asyncContext = yield* isAsync(); const asyncContext = yield* isAsync();
@ -121,19 +124,17 @@ function makeCachedFunction<ArgT, ResultT, SideChannel, Cache: *>(
const handlerResult: Handler<ResultT> | ResultT = 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;
if (isIterableIterator(handlerResult)) { if (isIterableIterator(handlerResult)) {
// Flow refines handlerResult to Generator<any, any, any> const gen = handlerResult as Generator<unknown, ResultT, unknown>;
const gen = (handlerResult: Generator<*, ResultT, *>);
value = yield* onFirstPause(gen, () => { value = yield* onFirstPause(gen, () => {
finishLock = setupAsyncLocks(cache, futureCache, arg); finishLock = setupAsyncLocks(cache, futureCache, arg);
}); });
} else { } else {
// $FlowIgnore doesn't refine handlerResult to ResultT value = handlerResult;
value = (handlerResult: ResultT);
} }
updateFunctionCache(callCache, cache, arg, value); updateFunctionCache(callCache, cache, arg, value);
@ -149,19 +150,14 @@ function makeCachedFunction<ArgT, ResultT, SideChannel, Cache: *>(
type CacheMap<ArgT, ResultT, SideChannel> = type CacheMap<ArgT, ResultT, SideChannel> =
| Map<ArgT, CacheEntry<ResultT, SideChannel>> | Map<ArgT, CacheEntry<ResultT, SideChannel>>
// @ts-expect-error todo(flow->ts): add `extends object` constraint to ArgT
| WeakMap<ArgT, CacheEntry<ResultT, SideChannel>>; | WeakMap<ArgT, CacheEntry<ResultT, SideChannel>>;
function* getCachedValue< function* getCachedValue<ArgT, ResultT, SideChannel>(
ArgT, cache: CacheMap<ArgT, ResultT, SideChannel>,
ResultT,
SideChannel,
// $FlowIssue https://github.com/facebook/flow/issues/4528
Cache: CacheMap<ArgT, ResultT, SideChannel>,
>(
cache: Cache,
arg: ArgT, arg: ArgT,
data: SideChannel, data: SideChannel,
): Handler<{ valid: true, value: ResultT } | { valid: false, value: null }> { ): Handler<{ valid: true; value: ResultT } | { valid: false; value: null }> {
const cachedValue: CacheEntry<ResultT, SideChannel> | void = cache.get(arg); const cachedValue: CacheEntry<ResultT, SideChannel> | void = cache.get(arg);
if (cachedValue) { if (cachedValue) {
@ -179,7 +175,7 @@ function* getCachedValueOrWait<ArgT, ResultT, SideChannel>(
futureCache: CacheMap<ArgT, Lock<ResultT>, SideChannel>, futureCache: CacheMap<ArgT, Lock<ResultT>, SideChannel>,
arg: ArgT, arg: ArgT,
data: SideChannel, data: SideChannel,
): Handler<{ valid: true, value: ResultT } | { valid: false, value: null }> { ): Handler<{ valid: true; value: ResultT } | { valid: false; value: null }> {
const cached = yield* getCachedValue(callCache, arg, data); const cached = yield* getCachedValue(callCache, arg, data);
if (cached.valid) { if (cached.valid) {
return cached; return cached;
@ -212,8 +208,7 @@ function updateFunctionCache<
ArgT, ArgT,
ResultT, ResultT,
SideChannel, SideChannel,
// $FlowIssue https://github.com/facebook/flow/issues/4528 Cache extends CacheMap<ArgT, ResultT, SideChannel>
Cache: CacheMap<ArgT, ResultT, SideChannel>,
>( >(
cache: Cache, cache: Cache,
config: CacheConfigurator<SideChannel>, config: CacheConfigurator<SideChannel>,
@ -253,7 +248,9 @@ class CacheConfigurator<SideChannel = void> {
_configured: boolean = false; _configured: boolean = false;
_pairs: Array<[mixed, (SideChannel) => Handler<mixed>]> = []; _pairs: Array<
[cachedValue: unknown, handler: (data: SideChannel) => Handler<unknown>]
> = [];
_data: SideChannel; _data: SideChannel;
@ -294,7 +291,7 @@ class CacheConfigurator<SideChannel = void> {
this._configured = true; this._configured = true;
} }
using<T>(handler: SideChannel => T): T { using<T>(handler: (data: SideChannel) => T): T {
if (!this._active) { if (!this._active) {
throw new Error("Cannot change caching after evaluation has completed."); throw new Error("Cannot change caching after evaluation has completed.");
} }
@ -313,7 +310,8 @@ class CacheConfigurator<SideChannel = void> {
); );
if (isThenable(key)) { if (isThenable(key)) {
return key.then((key: mixed) => { // @ts-expect-error todo(flow->ts): improve function return type annotation
return key.then((key: unknown) => {
this._pairs.push([key, fn]); this._pairs.push([key, fn]);
return key; return key;
}); });
@ -323,12 +321,12 @@ class CacheConfigurator<SideChannel = void> {
return key; return key;
} }
invalidate<T>(handler: SideChannel => T): T { invalidate<T>(handler: (data: SideChannel) => T): T {
this._invalidate = true; this._invalidate = true;
return this.using(handler); return this.using(handler);
} }
validator(): SideChannel => Handler<boolean> { validator(): (data: SideChannel) => Handler<boolean> {
const pairs = this._pairs; const pairs = this._pairs;
return function* (data: SideChannel) { return function* (data: SideChannel) {
for (const [key, fn] of pairs) { for (const [key, fn] of pairs) {
@ -364,7 +362,7 @@ function makeSimpleConfigurator(
cacheFn.using = cb => cache.using(() => assertSimpleType(cb())); cacheFn.using = cb => cache.using(() => assertSimpleType(cb()));
cacheFn.invalidate = cb => cache.invalidate(() => assertSimpleType(cb())); cacheFn.invalidate = cb => cache.invalidate(() => assertSimpleType(cb()));
return (cacheFn: any); return cacheFn as any;
} }
// 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
@ -376,7 +374,7 @@ export type SimpleType =
| null | null
| void | void
| Promise<SimpleType>; | Promise<SimpleType>;
export function assertSimpleType(value: mixed): SimpleType { export function assertSimpleType(value: unknown): SimpleType {
if (isThenable(value)) { if (isThenable(value)) {
throw new Error( throw new Error(
`You appear to be using an async cache handler, ` + `You appear to be using an async cache handler, ` +
@ -397,6 +395,7 @@ export function assertSimpleType(value: mixed): SimpleType {
"Cache keys must be either string, boolean, number, null, or undefined.", "Cache keys must be either string, boolean, number, null, or undefined.",
); );
} }
// @ts-expect-error todo(flow->ts) value is still typed as unknown, also assert function typically should not return a value
return value; return value;
} }

View File

@ -1,15 +1,14 @@
// @flow
import path from "path"; import path from "path";
import buildDebug from "debug"; import buildDebug from "debug";
import type { Handler } from "gensync"; import type { Handler } from "gensync";
import { import { validate } from "./validation/options";
validate, import type {
type ValidatedOptions, ValidatedOptions,
type IgnoreList, IgnoreList,
type ConfigApplicableTest, ConfigApplicableTest,
type BabelrcSearch, BabelrcSearch,
type CallerMetadata, CallerMetadata,
IgnoreItem,
} from "./validation/options"; } from "./validation/options";
import pathPatternToRegex from "./pattern-to-regex"; import pathPatternToRegex from "./pattern-to-regex";
import { ConfigPrinter, ChainFormatter } from "./printer"; import { ConfigPrinter, ChainFormatter } from "./printer";
@ -21,41 +20,41 @@ import {
findRelativeConfig, findRelativeConfig,
findRootConfig, findRootConfig,
loadConfig, loadConfig,
type ConfigFile,
type IgnoreFile,
type FilePackageData,
} from "./files"; } from "./files";
import type { ConfigFile, IgnoreFile, FilePackageData } from "./files";
import { makeWeakCacheSync, makeStrongCacheSync } from "./caching"; import { makeWeakCacheSync, makeStrongCacheSync } from "./caching";
import { import {
createCachedDescriptors, createCachedDescriptors,
createUncachedDescriptors, createUncachedDescriptors,
type UnloadedDescriptor, } from "./config-descriptors";
type OptionsAndDescriptors, import type {
type ValidatedFile, UnloadedDescriptor,
OptionsAndDescriptors,
ValidatedFile,
} from "./config-descriptors"; } from "./config-descriptors";
export type ConfigChain = { export type ConfigChain = {
plugins: Array<UnloadedDescriptor>, plugins: Array<UnloadedDescriptor>;
presets: Array<UnloadedDescriptor>, presets: Array<UnloadedDescriptor>;
options: Array<ValidatedOptions>, options: Array<ValidatedOptions>;
files: Set<string>, files: Set<string>;
}; };
export type PresetInstance = { export type PresetInstance = {
options: ValidatedOptions, options: ValidatedOptions;
alias: string, alias: string;
dirname: string, dirname: string;
}; };
export type ConfigContext = { export type ConfigContext = {
filename: string | void, filename: string | void;
cwd: string, cwd: string;
root: string, root: string;
envName: string, envName: string;
caller: CallerMetadata | void, caller: CallerMetadata | void;
showConfig: boolean, showConfig: boolean;
}; };
/** /**
@ -63,7 +62,7 @@ export type ConfigContext = {
*/ */
export function* buildPresetChain( export function* buildPresetChain(
arg: PresetInstance, arg: PresetInstance,
context: *, context: any,
): Handler<ConfigChain | null> { ): Handler<ConfigChain | null> {
const chain = yield* buildPresetChainWalker(arg, context); const chain = yield* buildPresetChainWalker(arg, context);
if (!chain) return null; if (!chain) return null;
@ -76,10 +75,7 @@ export function* buildPresetChain(
}; };
} }
export const buildPresetChainWalker: ( export const buildPresetChainWalker = makeChainWalker<PresetInstance>({
arg: PresetInstance,
context: *,
) => * = makeChainWalker({
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),
@ -128,11 +124,11 @@ const loadPresetOverridesEnvDescriptors = makeWeakCacheSync(
export type FileHandling = "transpile" | "ignored" | "unsupported"; export type FileHandling = "transpile" | "ignored" | "unsupported";
export type RootConfigChain = ConfigChain & { export type RootConfigChain = ConfigChain & {
babelrc: ConfigFile | void, babelrc: ConfigFile | void;
config: ConfigFile | void, config: ConfigFile | void;
ignore: IgnoreFile | void, ignore: IgnoreFile | void;
fileHandling: FileHandling, fileHandling: FileHandling;
files: Set<string>, files: Set<string>;
}; };
/** /**
@ -257,7 +253,6 @@ export function* buildRootChain(
if (context.showConfig) { if (context.showConfig) {
console.log( console.log(
// $FlowIgnore: context.showConfig implies context.filename is not null
`Babel configs on "${context.filename}" (ascending priority):\n` + `Babel configs on "${context.filename}" (ascending priority):\n` +
// print config by the order of ascending priority // print config by the order of ascending priority
[configReport, babelRcReport, programmaticReport] [configReport, babelRcReport, programmaticReport]
@ -288,7 +283,7 @@ export function* buildRootChain(
function babelrcLoadEnabled( function babelrcLoadEnabled(
context: ConfigContext, context: ConfigContext,
pkgData: FilePackageData, pkgData: FilePackageData,
babelrcRoots: BabelrcSearch | void, babelrcRoots: BabelrcSearch | undefined,
babelrcRootsDirectory: string, babelrcRootsDirectory: string,
): boolean { ): boolean {
if (typeof babelrcRoots === "boolean") return babelrcRoots; if (typeof babelrcRoots === "boolean") return babelrcRoots;
@ -302,7 +297,9 @@ function babelrcLoadEnabled(
} }
let babelrcPatterns = babelrcRoots; let babelrcPatterns = babelrcRoots;
if (!Array.isArray(babelrcPatterns)) babelrcPatterns = [babelrcPatterns]; if (!Array.isArray(babelrcPatterns)) {
babelrcPatterns = [babelrcPatterns as IgnoreItem];
}
babelrcPatterns = babelrcPatterns.map(pat => { babelrcPatterns = babelrcPatterns.map(pat => {
return typeof pat === "string" return typeof pat === "string"
? path.resolve(babelrcRootsDirectory, pat) ? path.resolve(babelrcRootsDirectory, pat)
@ -374,7 +371,7 @@ const loadProgrammaticChain = makeChainWalker({
/** /**
* Build a config chain for a given file. * Build a config chain for a given file.
*/ */
const loadFileChainWalker = makeChainWalker({ const loadFileChainWalker = makeChainWalker<ValidatedFile>({
root: file => loadFileDescriptors(file), root: file => loadFileDescriptors(file),
env: (file, envName) => loadFileEnvDescriptors(file)(envName), env: (file, envName) => loadFileEnvDescriptors(file)(envName),
overrides: (file, index) => loadFileOverridesDescriptors(file)(index), overrides: (file, index) => loadFileOverridesDescriptors(file)(index),
@ -499,36 +496,46 @@ function buildOverrideEnvDescriptors(
: null; : null;
} }
function makeChainWalker<ArgT: { options: ValidatedOptions, dirname: string }>({ function makeChainWalker<
ArgT extends { options: ValidatedOptions; dirname: string }
>({
root, root,
env, env,
overrides, overrides,
overridesEnv, overridesEnv,
createLogger, createLogger,
}: {| }: {
root: ArgT => OptionsAndDescriptors, root: (configEntry: ArgT) => OptionsAndDescriptors;
env: (ArgT, string) => OptionsAndDescriptors | null, env: (configEntry: ArgT, env: string) => OptionsAndDescriptors | null;
overrides: (ArgT, number) => OptionsAndDescriptors, overrides: (configEntry: ArgT, index: number) => OptionsAndDescriptors;
overridesEnv: (ArgT, number, string) => OptionsAndDescriptors | null, overridesEnv: (
configEntry: ArgT,
index: number,
env: string,
) => OptionsAndDescriptors | null;
createLogger: ( createLogger: (
ArgT, configEntry: ArgT,
ConfigContext, context: ConfigContext,
ConfigPrinter | void, printer: ConfigPrinter | void,
) => (OptionsAndDescriptors, ?number, ?string) => void, ) => (
|}): ( opts: OptionsAndDescriptors,
ArgT, index?: number | null,
ConfigContext, env?: string | null,
files?: Set<ConfigFile> | void, ) => void;
baseLogger: ConfigPrinter | void, }): (
configEntry: ArgT,
context: ConfigContext,
files?: Set<ConfigFile>,
baseLogger?: ConfigPrinter,
) => Handler<ConfigChain | null> { ) => Handler<ConfigChain | null> {
return function* (input, context, files = new Set(), baseLogger) { return function* (input, context, files = new Set(), baseLogger) {
const { dirname } = input; const { dirname } = input;
const flattenedConfigs: Array<{| const flattenedConfigs: Array<{
config: OptionsAndDescriptors, config: OptionsAndDescriptors;
index: ?number, index: number | undefined | null;
envName: ?string, envName: string | undefined | null;
|}> = []; }> = [];
const rootOpts = root(input); const rootOpts = root(input);
if (configIsApplicable(rootOpts, dirname, context)) { if (configIsApplicable(rootOpts, dirname, context)) {
@ -612,7 +619,7 @@ function* mergeExtendsChain(
dirname: string, dirname: string,
context: ConfigContext, context: ConfigContext,
files: Set<ConfigFile>, files: Set<ConfigFile>,
baseLogger: ConfigPrinter | void, baseLogger?: ConfigPrinter,
): Handler<boolean> { ): Handler<boolean> {
if (opts.extends === undefined) return true; if (opts.extends === undefined) return true;
@ -708,7 +715,7 @@ function dedupDescriptors(
): Array<UnloadedDescriptor> { ): Array<UnloadedDescriptor> {
const map: Map< const map: Map<
Function, Function,
Map<string | void, { value: UnloadedDescriptor }>, Map<string | void, { value: UnloadedDescriptor }>
> = new Map(); > = new Map();
const descriptors = []; const descriptors = [];
@ -773,8 +780,8 @@ function configFieldIsApplicable(
*/ */
function shouldIgnore( function shouldIgnore(
context: ConfigContext, context: ConfigContext,
ignore: ?IgnoreList, ignore: IgnoreList | undefined | null,
only: ?IgnoreList, only: IgnoreList | undefined | null,
dirname: string, dirname: string,
): boolean { ): boolean {
if (ignore && matchesPatterns(context, ignore, dirname)) { if (ignore && matchesPatterns(context, ignore, dirname)) {

View File

@ -1,6 +1,6 @@
// @flow import gensync from "gensync";
import gensync, { type Handler } from "gensync"; import type { Handler } from "gensync";
import { loadPlugin, loadPreset } from "./files"; import { loadPlugin, loadPreset } from "./files";
@ -10,8 +10,8 @@ import {
makeWeakCacheSync, makeWeakCacheSync,
makeStrongCacheSync, makeStrongCacheSync,
makeStrongCache, makeStrongCache,
type CacheConfigurator,
} from "./caching"; } from "./caching";
import type { CacheConfigurator } from "./caching";
import type { import type {
ValidatedOptions, ValidatedOptions,
@ -25,25 +25,25 @@ import { resolveBrowserslistConfigFile } from "./resolve-targets";
// for the plugins and presets so we don't load the plugins/presets unless // for the plugins and presets so we don't load the plugins/presets unless
// the options object actually ends up being applicable. // the options object actually ends up being applicable.
export type OptionsAndDescriptors = { export type OptionsAndDescriptors = {
options: ValidatedOptions, options: ValidatedOptions;
plugins: () => Handler<Array<UnloadedDescriptor>>, plugins: () => Handler<Array<UnloadedDescriptor>>;
presets: () => Handler<Array<UnloadedDescriptor>>, presets: () => Handler<Array<UnloadedDescriptor>>;
}; };
// Represents a plugin or presets at a given location in a config object. // Represents a plugin or presets at a given location in a config object.
// At this point these have been resolved to a specific object or function, // At this point these have been resolved to a specific object or function,
// but have not yet been executed to call functions with options. // but have not yet been executed to call functions with options.
export type UnloadedDescriptor = { export type UnloadedDescriptor = {
name: string | void, name: string | undefined;
value: {} | Function, value: any | Function;
options: {} | void | false, options: {} | undefined | false;
dirname: string, dirname: string;
alias: string, alias: string;
ownPass?: boolean, ownPass?: boolean;
file?: { file?: {
request: string, request: string;
resolved: string, resolved: string;
} | void, };
}; };
function isEqualDescriptor( function isEqualDescriptor(
@ -63,9 +63,9 @@ function isEqualDescriptor(
} }
export type ValidatedFile = { export type ValidatedFile = {
filepath: string, filepath: string;
dirname: string, dirname: string;
options: ValidatedOptions, options: ValidatedOptions;
}; };
// eslint-disable-next-line require-yield // eslint-disable-next-line require-yield
@ -100,10 +100,13 @@ export function createCachedDescriptors(
return { return {
options: optionsWithResolvedBrowserslistConfigFile(options, dirname), options: optionsWithResolvedBrowserslistConfigFile(options, dirname),
plugins: plugins plugins: plugins
? () => createCachedPluginDescriptors(plugins, dirname)(alias) ? () =>
// @ts-expect-error todo(flow->ts) ts complains about incorrect arguments
createCachedPluginDescriptors(plugins, dirname)(alias)
: () => handlerOf([]), : () => handlerOf([]),
presets: presets presets: presets
? () => ? () =>
// @ts-expect-error todo(flow->ts) ts complains about incorrect arguments
createCachedPresetDescriptors(presets, dirname)(alias)( createCachedPresetDescriptors(presets, dirname)(alias)(
!!passPerPreset, !!passPerPreset,
) )
@ -295,9 +298,9 @@ export function* createDescriptor(
alias, alias,
ownPass, ownPass,
}: { }: {
type?: "plugin" | "preset", type?: "plugin" | "preset";
alias: string, alias: string;
ownPass?: boolean, ownPass?: boolean;
}, },
): Handler<UnloadedDescriptor> { ): Handler<UnloadedDescriptor> {
const desc = getItemDescriptor(pair); const desc = getItemDescriptor(pair);
@ -307,7 +310,8 @@ export function* createDescriptor(
let name; let name;
let options; let options;
let value = pair; // todo(flow->ts) better type annotation
let value: any = pair;
if (Array.isArray(value)) { if (Array.isArray(value)) {
if (value.length === 3) { if (value.length === 3) {
[value, options, name] = value; [value, options, name] = value;

View File

@ -1,15 +1,12 @@
// @flow
import buildDebug from "debug"; import buildDebug from "debug";
import path from "path"; import path from "path";
import json5 from "json5"; import json5 from "json5";
import gensync, { type Handler } from "gensync"; import gensync from "gensync";
import { import type { Handler } from "gensync";
makeStrongCache, import { makeStrongCache, makeWeakCacheSync } from "../caching";
makeWeakCacheSync, import type { CacheConfigurator } from "../caching";
type CacheConfigurator, import { makeConfigAPI } from "../helpers/config-api";
} from "../caching"; import type { ConfigAPI } from "../helpers/config-api";
import { makeConfigAPI, type ConfigAPI } from "../helpers/config-api";
import { makeStaticFileCache } from "./utils"; import { makeStaticFileCache } from "./utils";
import loadCjsOrMjsDefault from "./module-types"; import loadCjsOrMjsDefault from "./module-types";
import pathPatternToRegex from "../pattern-to-regex"; import pathPatternToRegex from "../pattern-to-regex";
@ -19,8 +16,7 @@ import type { CallerMetadata } from "../validation/options";
import * as fs from "../../gensync-utils/fs"; import * as fs from "../../gensync-utils/fs";
import { createRequire } from "module"; import { createRequire } from "module";
// $FlowIgnore - https://github.com/facebook/flow/issues/6913#issuecomment-662787504 const require = createRequire(import.meta.url);
const require = createRequire(import /*::("")*/.meta.url);
const debug = buildDebug("babel:config:loading:files:configuration"); const debug = buildDebug("babel:config:loading:files:configuration");
@ -75,8 +71,7 @@ export function* findRelativeConfig(
envName, envName,
caller, caller,
packageData.pkg?.dirname === loc packageData.pkg?.dirname === loc
? // $FlowIgnore - packageData.pkg is not null ? packageToBabelConfig(packageData.pkg as ConfigFile)
packageToBabelConfig((packageData.pkg: ConfigFile))
: null, : null,
); );
} }
@ -107,7 +102,7 @@ function* loadOneConfig(
dirname: string, dirname: string,
envName: string, envName: string,
caller: CallerMetadata | void, caller: CallerMetadata | void,
previousConfig?: ConfigFile | null = null, previousConfig: ConfigFile | null = null,
): Handler<ConfigFile | null> { ): Handler<ConfigFile | null> {
const configs = yield* gensync.all( const configs = yield* gensync.all(
names.map(filename => names.map(filename =>
@ -166,8 +161,8 @@ const LOADING_CONFIGS = new Set();
const readConfigJS = makeStrongCache(function* readConfigJS( const readConfigJS = makeStrongCache(function* readConfigJS(
filepath: string, filepath: string,
cache: CacheConfigurator<{ cache: CacheConfigurator<{
envName: string, envName: string;
caller: CallerMetadata | void, caller: CallerMetadata | void;
}>, }>,
): Handler<ConfigFile | null> { ): Handler<ConfigFile | null> {
if (!fs.exists.sync(filepath)) { if (!fs.exists.sync(filepath)) {
@ -189,14 +184,14 @@ const readConfigJS = makeStrongCache(function* readConfigJS(
}; };
} }
let options: mixed; let options: unknown;
try { try {
LOADING_CONFIGS.add(filepath); LOADING_CONFIGS.add(filepath);
options = (yield* loadCjsOrMjsDefault( options = yield* loadCjsOrMjsDefault(
filepath, filepath,
"You appear to be using a native ECMAScript module configuration " + "You appear to be using a native ECMAScript module configuration " +
"file, which is only supported when running Babel asynchronously.", "file, which is only supported when running Babel asynchronously.",
): mixed); );
} catch (err) { } catch (err) {
err.message = `${filepath}: Error while loading config - ${err.message}`; err.message = `${filepath}: Error while loading config - ${err.message}`;
throw err; throw err;
@ -206,8 +201,12 @@ const readConfigJS = makeStrongCache(function* readConfigJS(
let assertCache = false; let assertCache = false;
if (typeof options === "function") { if (typeof options === "function") {
yield* []; // if we want to make it possible to use async configs // @ts-expect-error - if we want to make it possible to use async configs
options = ((options: any): (api: ConfigAPI) => {})(makeConfigAPI(cache)); yield* [];
options = ((options as any) as (api: ConfigAPI) => {})(
makeConfigAPI(cache),
);
assertCache = true; assertCache = true;
} }
@ -218,6 +217,7 @@ const readConfigJS = makeStrongCache(function* readConfigJS(
); );
} }
// @ts-expect-error todo(flow->ts)
if (typeof options.then === "function") { if (typeof options.then === "function") {
throw new Error( throw new Error(
`You appear to be using an async configuration, ` + `You appear to be using an async configuration, ` +
@ -239,7 +239,7 @@ const readConfigJS = makeStrongCache(function* readConfigJS(
const packageToBabelConfig = makeWeakCacheSync( const packageToBabelConfig = makeWeakCacheSync(
(file: ConfigFile): ConfigFile | null => { (file: ConfigFile): ConfigFile | null => {
const babel: mixed = file.options[("babel": string)]; const babel: unknown = file.options["babel"];
if (typeof babel === "undefined") return null; if (typeof babel === "undefined") return null;
@ -255,30 +255,32 @@ const packageToBabelConfig = makeWeakCacheSync(
}, },
); );
const readConfigJSON5 = makeStaticFileCache((filepath, content): ConfigFile => { const readConfigJSON5 = makeStaticFileCache(
let options; (filepath, content): ConfigFile => {
try { let options;
options = json5.parse(content); try {
} catch (err) { options = json5.parse(content);
err.message = `${filepath}: Error while parsing config - ${err.message}`; } catch (err) {
throw err; err.message = `${filepath}: Error while parsing config - ${err.message}`;
} throw err;
}
if (!options) throw new Error(`${filepath}: No config detected`); 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}`);
} }
if (Array.isArray(options)) { if (Array.isArray(options)) {
throw new Error(`${filepath}: Expected config object but found array`); throw new Error(`${filepath}: Expected config object but found array`);
} }
return { return {
filepath, filepath,
dirname: path.dirname(filepath), dirname: path.dirname(filepath),
options, options,
}; };
}); },
);
const readIgnoreConfig = makeStaticFileCache((filepath, content) => { const readIgnoreConfig = makeStaticFileCache((filepath, content) => {
const ignoreDir = path.dirname(filepath); const ignoreDir = path.dirname(filepath);
@ -319,7 +321,7 @@ export function* resolveShowConfigPath(
return null; return null;
} }
function throwConfigError(): empty { function throwConfigError(): never {
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:

View File

@ -1,4 +1,3 @@
// @flow
// We keep this in a separate file so that in older node versions, where // We keep this in a separate 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.

View File

@ -1,5 +1,3 @@
// @flow
import type { Handler } from "gensync"; import type { Handler } from "gensync";
import type { import type {
@ -15,7 +13,8 @@ export type { ConfigFile, IgnoreFile, RelativeConfig, FilePackageData };
// eslint-disable-next-line require-yield // eslint-disable-next-line require-yield
export function* findConfigUpwards( export function* findConfigUpwards(
rootDir: string, // eslint-disable-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
rootDir: string,
): Handler<string | null> { ): Handler<string | null> {
return null; return null;
} }
@ -32,18 +31,24 @@ export function* findPackageData(filepath: string): Handler<FilePackageData> {
// eslint-disable-next-line require-yield // eslint-disable-next-line require-yield
export function* findRelativeConfig( export function* findRelativeConfig(
pkgData: FilePackageData, // eslint-disable-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
envName: string, // eslint-disable-line no-unused-vars pkgData: FilePackageData,
caller: CallerMetadata | void, // eslint-disable-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
envName: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
caller: CallerMetadata | void,
): Handler<RelativeConfig> { ): Handler<RelativeConfig> {
return { pkg: null, config: null, ignore: null }; return { config: null, ignore: null };
} }
// eslint-disable-next-line require-yield // eslint-disable-next-line require-yield
export function* findRootConfig( export function* findRootConfig(
dirname: string, // eslint-disable-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
envName: string, // eslint-disable-line no-unused-vars dirname: string,
caller: CallerMetadata | void, // eslint-disable-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
envName: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
caller: CallerMetadata | void,
): Handler<ConfigFile | null> { ): Handler<ConfigFile | null> {
return null; return null;
} }
@ -52,27 +57,30 @@ export function* findRootConfig(
export function* loadConfig( export function* loadConfig(
name: string, name: string,
dirname: string, dirname: string,
envName: string, // eslint-disable-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
caller: CallerMetadata | void, // eslint-disable-line no-unused-vars envName: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
caller: CallerMetadata | void,
): Handler<ConfigFile> { ): Handler<ConfigFile> {
throw new Error(`Cannot load ${name} relative to ${dirname} in a browser`); throw new Error(`Cannot load ${name} relative to ${dirname} in a browser`);
} }
// eslint-disable-next-line require-yield // eslint-disable-next-line require-yield
export function* resolveShowConfigPath( export function* resolveShowConfigPath(
dirname: string, // eslint-disable-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
dirname: string,
): Handler<string | null> { ): Handler<string | null> {
return null; return null;
} }
export const ROOT_CONFIG_FILENAMES = []; export const ROOT_CONFIG_FILENAMES = [];
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
export function resolvePlugin(name: string, dirname: string): string | null { export function resolvePlugin(name: string, dirname: string): string | null {
return null; return null;
} }
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
export function resolvePreset(name: string, dirname: string): string | null { export function resolvePreset(name: string, dirname: string): string | null {
return null; return null;
} }
@ -80,7 +88,10 @@ export function resolvePreset(name: string, dirname: string): string | null {
export function loadPlugin( export function loadPlugin(
name: string, name: string,
dirname: string, dirname: string,
): Handler<{ filepath: string, value: mixed }> { ): Handler<{
filepath: string;
value: unknown;
}> {
throw new Error( throw new Error(
`Cannot load plugin ${name} relative to ${dirname} in a browser`, `Cannot load plugin ${name} relative to ${dirname} in a browser`,
); );
@ -89,7 +100,10 @@ export function loadPlugin(
export function loadPreset( export function loadPreset(
name: string, name: string,
dirname: string, dirname: string,
): Handler<{ filepath: string, value: mixed }> { ): Handler<{
filepath: string;
value: unknown;
}> {
throw new Error( throw new Error(
`Cannot load preset ${name} relative to ${dirname} in a browser`, `Cannot load preset ${name} relative to ${dirname} in a browser`,
); );

View File

@ -1,11 +1,9 @@
// @flow type indexBrowserType = typeof import("./index-browser");
type indexType = typeof import("./index");
import typeof * as indexBrowserType from "./index-browser";
import typeof * as indexType from "./index";
// Kind of gross, but essentially asserting that the exports of this module are the same as the // Kind of gross, but essentially asserting that the exports of this module are the same as the
// exports of index-browser, since this file may be replaced at bundle time with index-browser. // exports of index-browser, since this file may be replaced at bundle time with index-browser.
((({}: any): $Exact<indexBrowserType>): $Exact<indexType>); ((({} as any) as indexBrowserType) as indexType);
export { findPackageData } from "./package"; export { findPackageData } from "./package";

View File

@ -17,7 +17,7 @@ export default function* loadCjsOrMjsDefault(
asyncError: string, asyncError: string,
// TODO(Babel 8): Remove this // TODO(Babel 8): Remove this
fallbackToTranspiledModule: boolean = false, fallbackToTranspiledModule: boolean = false,
): Handler<mixed> { ): Handler<unknown> {
switch (guessJSModuleType(filepath)) { switch (guessJSModuleType(filepath)) {
case "cjs": case "cjs":
return loadCjsDefault(filepath, fallbackToTranspiledModule); return loadCjsDefault(filepath, fallbackToTranspiledModule);
@ -48,7 +48,7 @@ function guessJSModuleType(filename: string): "cjs" | "mjs" | "unknown" {
} }
function loadCjsDefault(filepath: string, fallbackToTranspiledModule: boolean) { function loadCjsDefault(filepath: string, fallbackToTranspiledModule: boolean) {
const module = (require(filepath): mixed); const module = require(filepath) as any;
return module?.__esModule return module?.__esModule
? // TODO (Babel 8): Remove "module" and "undefined" fallback ? // TODO (Babel 8): Remove "module" and "undefined" fallback
module.default || (fallbackToTranspiledModule ? module : undefined) module.default || (fallbackToTranspiledModule ? module : undefined)

View File

@ -1,5 +1,3 @@
// @flow
import path from "path"; import path from "path";
import type { Handler } from "gensync"; import type { Handler } from "gensync";
import { makeStaticFileCache } from "./utils"; import { makeStaticFileCache } from "./utils";
@ -39,7 +37,7 @@ const readConfigPackage = makeStaticFileCache(
(filepath, content): ConfigFile => { (filepath, content): ConfigFile => {
let options; let options;
try { try {
options = (JSON.parse(content): mixed); options = JSON.parse(content) as unknown;
} 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;

View File

@ -1,17 +1,14 @@
// @flow
/** /**
* This file handles all logic for converting string-based configuration references into loaded objects. * This file handles all logic for converting string-based configuration references into loaded objects.
*/ */
import buildDebug from "debug"; import buildDebug from "debug";
import path from "path"; import path from "path";
import { type Handler } from "gensync"; import type { Handler } from "gensync";
import loadCjsOrMjsDefault from "./module-types"; import loadCjsOrMjsDefault from "./module-types";
import { createRequire } from "module"; import { createRequire } from "module";
// $FlowIgnore - https://github.com/facebook/flow/issues/6913#issuecomment-662787504 const require = createRequire(import.meta.url);
const require = createRequire(import /*::("")*/.meta.url);
const debug = buildDebug("babel:config:loading:files:plugins"); const debug = buildDebug("babel:config:loading:files:plugins");
@ -35,7 +32,7 @@ export function resolvePreset(name: string, dirname: string): string | null {
export function* loadPlugin( export function* loadPlugin(
name: string, name: string,
dirname: string, dirname: string,
): Handler<{ filepath: string, value: mixed }> { ): Handler<{ filepath: string; value: unknown }> {
const filepath = resolvePlugin(name, dirname); const filepath = resolvePlugin(name, dirname);
if (!filepath) { if (!filepath) {
throw new Error(`Plugin ${name} not found relative to ${dirname}`); throw new Error(`Plugin ${name} not found relative to ${dirname}`);
@ -50,7 +47,7 @@ export function* loadPlugin(
export function* loadPreset( export function* loadPreset(
name: string, name: string,
dirname: string, dirname: string,
): Handler<{ filepath: string, value: mixed }> { ): Handler<{ filepath: string; value: unknown }> {
const filepath = resolvePreset(name, dirname); const filepath = resolvePreset(name, dirname);
if (!filepath) { if (!filepath) {
throw new Error(`Preset ${name} not found relative to ${dirname}`); throw new Error(`Preset ${name} not found relative to ${dirname}`);
@ -151,7 +148,7 @@ function resolveStandardizedName(
} }
const LOADING_MODULES = new Set(); const LOADING_MODULES = new Set();
function* requireModule(type: string, name: string): Handler<mixed> { function* requireModule(type: string, name: string): Handler<unknown> {
if (LOADING_MODULES.has(name)) { if (LOADING_MODULES.has(name)) {
throw new Error( throw new Error(
`Reentrant ${type} detected trying to load "${name}". This module is not ignored ` + `Reentrant ${type} detected trying to load "${name}". This module is not ignored ` +
@ -162,7 +159,7 @@ function* requireModule(type: string, name: string): Handler<mixed> {
try { try {
LOADING_MODULES.add(name); LOADING_MODULES.add(name);
return (yield* loadCjsOrMjsDefault( return yield* loadCjsOrMjsDefault(
name, name,
`You appear to be using a native ECMAScript module ${type}, ` + `You appear to be using a native ECMAScript module ${type}, ` +
"which is only supported when running Babel asynchronously.", "which is only supported when running Babel asynchronously.",
@ -171,7 +168,7 @@ function* requireModule(type: string, name: string): Handler<mixed> {
// export. // export.
// See packages/babel-core/test/fixtures/option-manager/presets/es2015_named.js // See packages/babel-core/test/fixtures/option-manager/presets/es2015_named.js
true, true,
): mixed); );
} catch (err) { } catch (err) {
err.message = `[BABEL]: ${err.message} (While processing: ${name})`; err.message = `[BABEL]: ${err.message} (While processing: ${name})`;
throw err; throw err;

View File

@ -1,38 +1,32 @@
// @flow
export type ConfigFile = { export type ConfigFile = {
filepath: string, filepath: string;
dirname: string, dirname: string;
options: {}, options: {};
}; };
export type IgnoreFile = { export type IgnoreFile = {
filepath: string, filepath: string;
dirname: string, dirname: string;
ignore: Array<RegExp>, ignore: Array<RegExp>;
}; };
export type RelativeConfig = { export type RelativeConfig = {
// The actual config, either from package.json#babel, .babelrc, or // The actual config, either from package.json#babel, .babelrc, or
// .babelrc.js, if there was one. // .babelrc.js, if there was one.
config: ConfigFile | null, config: ConfigFile | null;
// The .babelignore, if there was one. // The .babelignore, if there was one.
ignore: IgnoreFile | null, ignore: IgnoreFile | null;
}; };
export type FilePackageData = { export type FilePackageData = {
// The file in the package. // The file in the package.
filepath: string, filepath: string;
// Any ancestor directories of the file that are within the package. // Any ancestor directories of the file that are within the package.
directories: Array<string>, directories: Array<string>;
// The contents of the package.json. May not be found if the package just // The contents of the package.json. May not be found if the package just
// terminated at a node_modules folder without finding one. // terminated at a node_modules folder without finding one.
pkg: ConfigFile | null, pkg: ConfigFile | null;
// True if a package.json or node_modules folder was found while traversing // True if a package.json or node_modules folder was found while traversing
// the directory structure. // the directory structure.
isPackage: boolean, isPackage: boolean;
}; };

View File

@ -1,17 +1,16 @@
// @flow import type { Handler } from "gensync";
import type { Gensync, Handler } from "gensync"; import { makeStrongCache } from "../caching";
import type { CacheConfigurator } from "../caching";
import { makeStrongCache, type CacheConfigurator } from "../caching";
import * as fs from "../../gensync-utils/fs"; import * as fs from "../../gensync-utils/fs";
import nodeFs from "fs"; import nodeFs from "fs";
export function makeStaticFileCache<T>( export function makeStaticFileCache<T>(
fn: (string, string) => T, fn: (filepath: string, contents: string) => T,
): Gensync<[string], T | null> { ) {
return (makeStrongCache(function* ( return makeStrongCache(function* (
filepath: string, filepath: string,
cache: CacheConfigurator<?void>, cache: CacheConfigurator<void>,
): Handler<null | T> { ): Handler<null | T> {
const cached = cache.invalidate(() => fileMtime(filepath)); const cached = cache.invalidate(() => fileMtime(filepath));
@ -20,7 +19,7 @@ export function makeStaticFileCache<T>(
} }
return fn(filepath, yield* fs.readFile(filepath, "utf8")); return fn(filepath, yield* fs.readFile(filepath, "utf8"));
}): Gensync<any, *>); });
} }
function fileMtime(filepath: string): number | null { function fileMtime(filepath: string): number | null {

View File

@ -1,32 +1,29 @@
// @flow import gensync from "gensync";
import type { Handler } from "gensync";
import gensync, { type Handler } from "gensync";
import { forwardAsync, maybeAsync, isThenable } from "../gensync-utils/async"; import { forwardAsync, maybeAsync, isThenable } from "../gensync-utils/async";
import { mergeOptions } from "./util"; import { mergeOptions } from "./util";
import * as context from "../index"; import * as context from "../index";
import Plugin from "./plugin"; import Plugin from "./plugin";
import { getItemDescriptor } from "./item"; import { getItemDescriptor } from "./item";
import { import { buildPresetChain } from "./config-chain";
buildPresetChain, import type {
type ConfigContext, ConfigContext,
type ConfigChain, ConfigChain,
type PresetInstance, PresetInstance,
} from "./config-chain"; } from "./config-chain";
import type { UnloadedDescriptor } from "./config-descriptors"; import type { UnloadedDescriptor } from "./config-descriptors";
import traverse from "@babel/traverse"; import traverse from "@babel/traverse";
import { import { makeWeakCache, makeWeakCacheSync } from "./caching";
makeWeakCache, import type { CacheConfigurator } from "./caching";
makeWeakCacheSync,
type CacheConfigurator,
} from "./caching";
import { import {
validate, validate,
checkNoUnwrappedItemOptionPairs, checkNoUnwrappedItemOptionPairs,
type PluginItem,
} from "./validation/options"; } from "./validation/options";
import type { PluginItem } from "./validation/options";
import { validatePluginObject } from "./validation/plugins"; import { validatePluginObject } from "./validation/plugins";
import { makePluginAPI, makePresetAPI } from "./helpers/config-api"; import { makePluginAPI, makePresetAPI } from "./helpers/config-api";
import type { PluginAPI, PresetAPI } from "./helpers/config-api";
import loadPrivatePartialConfig from "./partial"; import loadPrivatePartialConfig from "./partial";
import type { ValidatedOptions } from "./validation/options"; import type { ValidatedOptions } from "./validation/options";
@ -34,172 +31,183 @@ import type { ValidatedOptions } from "./validation/options";
import * as Context from "./cache-contexts"; import * as Context from "./cache-contexts";
type LoadedDescriptor = { type LoadedDescriptor = {
value: {}, value: {};
options: {}, options: {};
dirname: string, dirname: string;
alias: string, alias: string;
}; };
export type { InputOptions } from "./validation/options"; export type { InputOptions } from "./validation/options";
export type ResolvedConfig = { export type ResolvedConfig = {
options: Object, options: any;
passes: PluginPasses, passes: PluginPasses;
}; };
export type { Plugin }; export type { Plugin };
export type PluginPassList = Array<Plugin>; export type PluginPassList = Array<Plugin>;
export type PluginPasses = Array<PluginPassList>; export type PluginPasses = Array<PluginPassList>;
export default gensync<[any], ResolvedConfig | null>(function* loadFullConfig( export default gensync<(inputOpts: unknown) => ResolvedConfig | null>(
inputOpts: mixed, function* loadFullConfig(inputOpts) {
): Handler<ResolvedConfig | null> { const result = yield* loadPrivatePartialConfig(inputOpts);
const result = yield* loadPrivatePartialConfig(inputOpts); if (!result) {
if (!result) { return null;
return null; }
} const { options, context, fileHandling } = result;
const { options, context, fileHandling } = result;
if (fileHandling === "ignored") { if (fileHandling === "ignored") {
return null; return null;
}
const optionDefaults = {};
const { plugins, presets } = options;
if (!plugins || !presets) {
throw new Error("Assertion failure - plugins and presets exist");
}
const pluginContext: Context.FullPlugin = {
...context,
targets: options.targets,
assumptions: options.assumptions ?? {},
};
const toDescriptor = (item: PluginItem) => {
const desc = getItemDescriptor(item);
if (!desc) {
throw new Error("Assertion failure - must be config item");
} }
return desc; const optionDefaults = {};
};
const presetsDescriptors = presets.map(toDescriptor); const { plugins, presets } = options;
const initialPluginsDescriptors = plugins.map(toDescriptor);
const pluginDescriptorsByPass: Array<Array<UnloadedDescriptor>> = [[]];
const passes: Array<Array<Plugin>> = [];
const ignored = yield* enhanceError( if (!plugins || !presets) {
context, throw new Error("Assertion failure - plugins and presets exist");
function* recursePresetDescriptors( }
rawPresets: Array<UnloadedDescriptor>,
pluginDescriptorsPass: Array<UnloadedDescriptor>,
) {
const presets: Array<{|
preset: ConfigChain | null,
pass: Array<UnloadedDescriptor>,
|}> = [];
for (let i = 0; i < rawPresets.length; i++) { const pluginContext: Context.FullPlugin = {
const descriptor = rawPresets[i]; ...context,
if (descriptor.options !== false) { targets: options.targets,
try { assumptions: options.assumptions ?? {},
// Presets normally run in reverse order, but if they };
// have their own pass they run after the presets
// in the previous pass. const toDescriptor = (item: PluginItem) => {
if (descriptor.ownPass) { const desc = getItemDescriptor(item);
presets.push({ if (!desc) {
preset: yield* loadPresetDescriptor(descriptor, pluginContext), throw new Error("Assertion failure - must be config item");
pass: [], }
});
} else { return desc;
presets.unshift({ };
preset: yield* loadPresetDescriptor(descriptor, pluginContext),
pass: pluginDescriptorsPass, const presetsDescriptors = presets.map(toDescriptor);
}); const initialPluginsDescriptors = plugins.map(toDescriptor);
const pluginDescriptorsByPass: Array<Array<UnloadedDescriptor>> = [[]];
const passes: Array<Array<Plugin>> = [];
const ignored = yield* enhanceError(
context,
function* recursePresetDescriptors(
rawPresets: Array<UnloadedDescriptor>,
pluginDescriptorsPass: Array<UnloadedDescriptor>,
) {
const presets: Array<{
preset: ConfigChain | null;
pass: Array<UnloadedDescriptor>;
}> = [];
for (let i = 0; i < rawPresets.length; i++) {
const descriptor = rawPresets[i];
if (descriptor.options !== false) {
try {
// Presets normally run in reverse order, but if they
// have their own pass they run after the presets
// in the previous pass.
if (descriptor.ownPass) {
presets.push({
preset: yield* loadPresetDescriptor(
descriptor,
pluginContext,
),
pass: [],
});
} else {
presets.unshift({
preset: yield* loadPresetDescriptor(
descriptor,
pluginContext,
),
pass: pluginDescriptorsPass,
});
}
} catch (e) {
if (e.code === "BABEL_UNKNOWN_OPTION") {
checkNoUnwrappedItemOptionPairs(rawPresets, i, "preset", e);
}
throw e;
} }
} catch (e) { }
if (e.code === "BABEL_UNKNOWN_OPTION") { }
checkNoUnwrappedItemOptionPairs(rawPresets, i, "preset", e);
// resolve presets
if (presets.length > 0) {
// The passes are created in the same order as the preset list, but are inserted before any
// existing additional passes.
pluginDescriptorsByPass.splice(
1,
0,
...presets
.map(o => o.pass)
.filter(p => p !== pluginDescriptorsPass),
);
for (const { preset, pass } of presets) {
if (!preset) return true;
pass.push(...preset.plugins);
const ignored = yield* recursePresetDescriptors(
preset.presets,
pass,
);
if (ignored) return true;
preset.options.forEach(opts => {
mergeOptions(optionDefaults, opts);
});
}
}
},
)(presetsDescriptors, pluginDescriptorsByPass[0]);
if (ignored) return null;
const opts: any = optionDefaults;
mergeOptions(opts, options);
yield* enhanceError(context, function* loadPluginDescriptors() {
pluginDescriptorsByPass[0].unshift(...initialPluginsDescriptors);
for (const descs of pluginDescriptorsByPass) {
const pass = [];
passes.push(pass);
for (let i = 0; i < descs.length; i++) {
const descriptor: UnloadedDescriptor = descs[i];
if (descriptor.options !== false) {
try {
pass.push(yield* loadPluginDescriptor(descriptor, pluginContext));
} catch (e) {
if (e.code === "BABEL_UNKNOWN_PLUGIN_PROPERTY") {
// print special message for `plugins: ["@babel/foo", { foo: "option" }]`
checkNoUnwrappedItemOptionPairs(descs, i, "plugin", e);
}
throw e;
} }
throw e;
} }
} }
} }
})();
// resolve presets opts.plugins = passes[0];
if (presets.length > 0) { opts.presets = passes
// The passes are created in the same order as the preset list, but are inserted before any .slice(1)
// existing additional passes. .filter(plugins => plugins.length > 0)
pluginDescriptorsByPass.splice( .map(plugins => ({ plugins }));
1, opts.passPerPreset = opts.presets.length > 0;
0,
...presets.map(o => o.pass).filter(p => p !== pluginDescriptorsPass),
);
for (const { preset, pass } of presets) { return {
if (!preset) return true; options: opts,
passes: passes,
};
},
);
pass.push(...preset.plugins); function enhanceError<T extends Function>(context, fn: T): T {
return function* (arg1, arg2) {
const ignored = yield* recursePresetDescriptors(preset.presets, pass);
if (ignored) return true;
preset.options.forEach(opts => {
mergeOptions(optionDefaults, opts);
});
}
}
},
)(presetsDescriptors, pluginDescriptorsByPass[0]);
if (ignored) return null;
const opts: Object = optionDefaults;
mergeOptions(opts, options);
yield* enhanceError(context, function* loadPluginDescriptors() {
pluginDescriptorsByPass[0].unshift(...initialPluginsDescriptors);
for (const descs of pluginDescriptorsByPass) {
const pass = [];
passes.push(pass);
for (let i = 0; i < descs.length; i++) {
const descriptor: UnloadedDescriptor = descs[i];
if (descriptor.options !== false) {
try {
pass.push(yield* loadPluginDescriptor(descriptor, pluginContext));
} catch (e) {
if (e.code === "BABEL_UNKNOWN_PLUGIN_PROPERTY") {
// print special message for `plugins: ["@babel/foo", { foo: "option" }]`
checkNoUnwrappedItemOptionPairs(descs, i, "plugin", e);
}
throw e;
}
}
}
}
})();
opts.plugins = passes[0];
opts.presets = passes
.slice(1)
.filter(plugins => plugins.length > 0)
.map(plugins => ({ plugins }));
opts.passPerPreset = opts.presets.length > 0;
return {
options: opts,
passes: passes,
};
});
function enhanceError<T: Function>(context, fn: T): T {
return (function* (arg1, arg2) {
try { try {
return yield* fn(arg1, arg2); return yield* fn(arg1, arg2);
} catch (e) { } catch (e) {
@ -211,7 +219,7 @@ function enhanceError<T: Function>(context, fn: T): T {
throw e; throw e;
} }
}: any); } as any;
} }
/** /**
@ -255,7 +263,8 @@ const makeDescriptorLoader = <Context, API>(
} }
if (isThenable(item)) { if (isThenable(item)) {
yield* []; // if we want to support async plugins // @ts-expect-error - if we want to support async plugins
yield* [];
throw new Error( throw new Error(
`You appear to be using a promise as a plugin, ` + `You appear to be using a promise as a plugin, ` +
@ -270,12 +279,14 @@ const makeDescriptorLoader = <Context, API>(
return { value: item, options, dirname, alias }; return { value: item, options, dirname, alias };
}); });
const pluginDescriptorLoader = makeDescriptorLoader<Context.SimplePlugin, *>( const pluginDescriptorLoader = makeDescriptorLoader<
makePluginAPI, Context.SimplePlugin,
); PluginAPI
const presetDescriptorLoader = makeDescriptorLoader<Context.SimplePreset, *>( >(makePluginAPI);
makePresetAPI, const presetDescriptorLoader = makeDescriptorLoader<
); Context.SimplePreset,
PresetAPI
>(makePresetAPI);
/** /**
* Instantiate a plugin for the given descriptor, returning the plugin/options pair. * Instantiate a plugin for the given descriptor, returning the plugin/options pair.

View File

@ -1,14 +1,12 @@
// @flow
import semver from "semver"; import semver from "semver";
import type { Targets } from "@babel/helper-compilation-targets"; import type { Targets } from "@babel/helper-compilation-targets";
import { version as coreVersion } from "../../"; import { version as coreVersion } from "../../";
import { import { assertSimpleType } from "../caching";
assertSimpleType, import type {
type CacheConfigurator, CacheConfigurator,
type SimpleCacheConfigurator, SimpleCacheConfigurator,
type SimpleType, SimpleType,
} from "../caching"; } from "../caching";
import type { CallerMetadata } from "../validation/options"; import type { CallerMetadata } from "../validation/options";
@ -16,38 +14,36 @@ import type { CallerMetadata } from "../validation/options";
import * as Context from "../cache-contexts"; import * as Context from "../cache-contexts";
type EnvFunction = { type EnvFunction = {
(): string, (): string;
<T>((string) => T): T, <T>(extractor: (babelEnv: string) => T): T;
(string): boolean, (envVar: string): boolean;
(Array<string>): boolean, (envVars: Array<string>): boolean;
}; };
type CallerFactory = ((CallerMetadata | void) => mixed) => SimpleType; type CallerFactory = (
extractor: (callerMetadata: CallerMetadata | void) => unknown,
) => SimpleType;
type TargetsFunction = () => Targets; type TargetsFunction = () => Targets;
type AssumptionFunction = (name: string) => boolean | void; type AssumptionFunction = (name: string) => boolean | void;
export type ConfigAPI = {| export type ConfigAPI = {
version: string, version: string;
cache: SimpleCacheConfigurator, cache: SimpleCacheConfigurator;
env: EnvFunction, env: EnvFunction;
async: () => boolean, async: () => boolean;
assertVersion: typeof assertVersion, assertVersion: typeof assertVersion;
caller?: CallerFactory, caller?: CallerFactory;
|}; };
export type PresetAPI = {| export type PresetAPI = {
...ConfigAPI, targets: TargetsFunction;
targets: TargetsFunction, } & ConfigAPI;
|};
export type PluginAPI = {| export type PluginAPI = {
...PresetAPI, assumption: AssumptionFunction;
assumption: AssumptionFunction, } & PresetAPI;
|};
export function makeConfigAPI<SideChannel: Context.SimpleConfig>( export function makeConfigAPI<SideChannel extends Context.SimpleConfig>(
cache: CacheConfigurator<SideChannel>, cache: CacheConfigurator<SideChannel>,
): ConfigAPI { ): ConfigAPI {
const env: any = value => const env: any = value =>
@ -58,7 +54,7 @@ export function makeConfigAPI<SideChannel: Context.SimpleConfig>(
} }
if (!Array.isArray(value)) value = [value]; if (!Array.isArray(value)) value = [value];
return value.some((entry: mixed) => { return value.some((entry: unknown) => {
if (typeof entry !== "string") { if (typeof entry !== "string") {
throw new Error("Unexpected non-string value"); throw new Error("Unexpected non-string value");
} }
@ -79,7 +75,7 @@ export function makeConfigAPI<SideChannel: Context.SimpleConfig>(
}; };
} }
export function makePresetAPI<SideChannel: Context.SimplePreset>( export function makePresetAPI<SideChannel extends Context.SimplePreset>(
cache: CacheConfigurator<SideChannel>, cache: CacheConfigurator<SideChannel>,
): PresetAPI { ): PresetAPI {
const targets = () => const targets = () =>
@ -91,7 +87,7 @@ export function makePresetAPI<SideChannel: Context.SimplePreset>(
return { ...makeConfigAPI(cache), targets }; return { ...makeConfigAPI(cache), targets };
} }
export function makePluginAPI<SideChannel: Context.SimplePlugin>( export function makePluginAPI<SideChannel extends Context.SimplePlugin>(
cache: CacheConfigurator<SideChannel>, cache: CacheConfigurator<SideChannel>,
): PluginAPI { ): PluginAPI {
const assumption = name => cache.using(data => data.assumptions[name]); const assumption = name => cache.using(data => data.assumptions[name]);
@ -133,12 +129,9 @@ function assertVersion(range: string | number): void {
Error.stackTraceLimit = limit; Error.stackTraceLimit = limit;
} }
throw Object.assign( throw Object.assign(err, {
err, code: "BABEL_VERSION_UNSUPPORTED",
({ version: coreVersion,
code: "BABEL_VERSION_UNSUPPORTED", range,
version: coreVersion, });
range,
}: any),
);
} }

View File

@ -1,5 +1,3 @@
// @flow
export function getEnv(defaultValue: string = "development"): string { export function getEnv(defaultValue: string = "development"): string {
return process.env.BABEL_ENV || process.env.NODE_ENV || defaultValue; return process.env.BABEL_ENV || process.env.NODE_ENV || defaultValue;
} }

View File

@ -1,5 +1,3 @@
// @flow
import gensync from "gensync"; import gensync from "gensync";
export type { export type {
@ -18,19 +16,19 @@ export { loadFullConfig as default };
export type { PartialConfig } from "./partial"; export type { PartialConfig } from "./partial";
import { createConfigItem as createConfigItemImpl } from "./item"; import { createConfigItem as createConfigItemImpl } from "./item";
import type { ConfigItem } from "./item";
const loadOptionsRunner = gensync<[mixed], Object | null>(function* (opts) { const loadOptionsRunner = gensync<(opts: unknown) => any>(function* (opts) {
const config = yield* loadFullConfig(opts); const config = yield* loadFullConfig(opts);
// NOTE: We want to return "null" explicitly, while ?. alone returns undefined // NOTE: We want to return "null" explicitly, while ?. alone returns undefined
return config?.options ?? null; return config?.options ?? null;
}); });
const createConfigItemRunner = gensync<[PluginTarget, any], Object | null>( const createConfigItemRunner = gensync<
// $FlowIgnore (...args: Parameters<typeof createConfigItemImpl>) => ConfigItem
createConfigItemImpl, >(createConfigItemImpl);
);
const maybeErrback = runner => (opts: mixed, callback: Function) => { const maybeErrback = runner => (opts: unknown, callback?: Function) => {
if (callback === undefined && typeof opts === "function") { if (callback === undefined && typeof opts === "function") {
callback = opts; callback = opts;
opts = undefined; opts = undefined;
@ -51,7 +49,7 @@ export const createConfigItemAsync = createConfigItemRunner.async;
export function createConfigItem( export function createConfigItem(
target: PluginTarget, target: PluginTarget,
options: any, options: any,
callback?: Function, callback?: (err: Error, val: ConfigItem | null) => void,
) { ) {
if (callback !== undefined) { if (callback !== undefined) {
return createConfigItemRunner.errback(target, options, callback); return createConfigItemRunner.errback(target, options, callback);

View File

@ -1,15 +1,10 @@
// @flow
/*:: declare var invariant; */
import type { Handler } from "gensync"; import type { Handler } from "gensync";
import type { PluginTarget, PluginOptions } from "./validation/options"; import type { PluginTarget, PluginOptions } from "./validation/options";
import path from "path"; import path from "path";
import { import { createDescriptor } from "./config-descriptors";
createDescriptor,
type UnloadedDescriptor, import type { UnloadedDescriptor } from "./config-descriptors";
} from "./config-descriptors";
export function createItemFromDescriptor(desc: UnloadedDescriptor): ConfigItem { export function createItemFromDescriptor(desc: UnloadedDescriptor): ConfigItem {
return new ConfigItem(desc); return new ConfigItem(desc);
@ -30,8 +25,8 @@ export function* createConfigItem(
dirname = ".", dirname = ".",
type, type,
}: { }: {
dirname?: string, dirname?: string;
type?: "preset" | "plugin", type?: "preset" | "plugin";
} = {}, } = {},
): Handler<ConfigItem> { ): Handler<ConfigItem> {
const descriptor = yield* createDescriptor(value, path.resolve(dirname), { const descriptor = yield* createDescriptor(value, path.resolve(dirname), {
@ -42,10 +37,9 @@ export function* createConfigItem(
return createItemFromDescriptor(descriptor); return createItemFromDescriptor(descriptor);
} }
export function getItemDescriptor(item: mixed): UnloadedDescriptor | void { export function getItemDescriptor(item: unknown): UnloadedDescriptor | void {
if ((item: any)?.[CONFIG_ITEM_BRAND]) { if ((item as any)?.[CONFIG_ITEM_BRAND]) {
/*:: invariant(item instanceof ConfigItem) */ return (item as ConfigItem)._descriptor;
return item._descriptor;
} }
return undefined; return undefined;
@ -74,7 +68,6 @@ class ConfigItem {
/** /**
* Used to detect ConfigItem instances from other Babel instances. * Used to detect ConfigItem instances from other Babel instances.
*/ */
// $FlowIgnore
[CONFIG_ITEM_BRAND] = true; [CONFIG_ITEM_BRAND] = true;
/** /**
@ -105,10 +98,9 @@ class ConfigItem {
*/ */
file: { file: {
// The requested path, e.g. "@babel/env". // The requested path, e.g. "@babel/env".
request: string, request: string;
// The resolved absolute path of the file. // The resolved absolute path of the file.
resolved: string, resolved: string;
} | void; } | void;
constructor(descriptor: UnloadedDescriptor) { constructor(descriptor: UnloadedDescriptor) {

View File

@ -1,30 +1,26 @@
// @flow
import path from "path"; import path from "path";
import gensync, { type Handler } from "gensync"; import gensync from "gensync";
import type { Handler } from "gensync";
import Plugin from "./plugin"; import Plugin from "./plugin";
import { mergeOptions } from "./util"; import { mergeOptions } from "./util";
import { createItemFromDescriptor } from "./item"; import { createItemFromDescriptor } from "./item";
import { import { buildRootChain } from "./config-chain";
buildRootChain, import type { ConfigContext, FileHandling } from "./config-chain";
type ConfigContext,
type FileHandling,
} from "./config-chain";
import { getEnv } from "./helpers/environment"; import { getEnv } from "./helpers/environment";
import { import { validate } from "./validation/options";
validate,
type ValidatedOptions, import type {
type NormalizedOptions, ValidatedOptions,
type RootMode, NormalizedOptions,
RootMode,
} from "./validation/options"; } from "./validation/options";
import { import {
findConfigUpwards, findConfigUpwards,
resolveShowConfigPath, resolveShowConfigPath,
ROOT_CONFIG_FILENAMES, ROOT_CONFIG_FILENAMES,
type ConfigFile,
type IgnoreFile,
} from "./files"; } from "./files";
import type { ConfigFile, IgnoreFile } from "./files";
import { resolveTargets } from "./resolve-targets"; import { resolveTargets } from "./resolve-targets";
function* resolveRootMode( function* resolveRootMode(
@ -45,12 +41,12 @@ function* resolveRootMode(
if (upwardRootDir !== null) return upwardRootDir; if (upwardRootDir !== null) return upwardRootDir;
throw Object.assign( throw Object.assign(
(new Error( new Error(
`Babel was run with rootMode:"upward" but a root could not ` + `Babel was run with rootMode:"upward" but a root could not ` +
`be found when searching upward from "${rootDir}".\n` + `be found when searching upward from "${rootDir}".\n` +
`One of the following config files must be in the directory tree: ` + `One of the following config files must be in the directory tree: ` +
`"${ROOT_CONFIG_FILENAMES.join(", ")}".`, `"${ROOT_CONFIG_FILENAMES.join(", ")}".`,
): any), ) as any,
{ {
code: "BABEL_ROOT_NOT_FOUND", code: "BABEL_ROOT_NOT_FOUND",
dirname: rootDir, dirname: rootDir,
@ -63,17 +59,17 @@ function* resolveRootMode(
} }
type PrivPartialConfig = { type PrivPartialConfig = {
options: NormalizedOptions, options: NormalizedOptions;
context: ConfigContext, context: ConfigContext;
fileHandling: FileHandling, fileHandling: FileHandling;
ignore: IgnoreFile | void, ignore: IgnoreFile | void;
babelrc: ConfigFile | void, babelrc: ConfigFile | void;
config: ConfigFile | void, config: ConfigFile | void;
files: Set<string>, files: Set<string>;
}; };
export default function* loadPrivatePartialConfig( export default function* loadPrivatePartialConfig(
inputOpts: mixed, inputOpts: unknown,
): Handler<PrivPartialConfig | null> { ): Handler<PrivPartialConfig | null> {
if ( if (
inputOpts != null && inputOpts != null &&
@ -121,7 +117,7 @@ export default function* loadPrivatePartialConfig(
assumptions: {}, assumptions: {},
}; };
configChain.options.forEach(opts => { configChain.options.forEach(opts => {
mergeOptions((merged: any), opts); mergeOptions(merged as any, opts);
}); });
const options: NormalizedOptions = { const options: NormalizedOptions = {
@ -163,47 +159,50 @@ export default function* loadPrivatePartialConfig(
} }
type LoadPartialConfigOpts = { type LoadPartialConfigOpts = {
showIgnoredFiles?: boolean, showIgnoredFiles?: boolean;
...
}; };
export const loadPartialConfig = gensync<[any], PartialConfig | null>( export const loadPartialConfig = gensync<
function* (opts?: LoadPartialConfigOpts): Handler<PartialConfig | null> { (opts?: LoadPartialConfigOpts) => PartialConfig | null
let showIgnoredFiles = false; >(function* (opts) {
// We only extract showIgnoredFiles if opts is an object, so that let showIgnoredFiles = false;
// loadPrivatePartialConfig can throw the appropriate error if it's not. // We only extract showIgnoredFiles if opts is an object, so that
if (typeof opts === "object" && opts !== null && !Array.isArray(opts)) { // loadPrivatePartialConfig can throw the appropriate error if it's not.
({ showIgnoredFiles, ...opts } = opts); if (typeof opts === "object" && opts !== null && !Array.isArray(opts)) {
({ showIgnoredFiles, ...opts } = opts);
}
const result:
| PrivPartialConfig
| undefined
| null = yield* loadPrivatePartialConfig(opts);
if (!result) return null;
const { options, babelrc, ignore, config, fileHandling, files } = result;
if (fileHandling === "ignored" && !showIgnoredFiles) {
return null;
}
(options.plugins || []).forEach(item => {
// @ts-expect-error todo(flow->ts): better type annotation for `item.value`
if (item.value instanceof Plugin) {
throw new Error(
"Passing cached plugin instances is not supported in " +
"babel.loadPartialConfig()",
);
} }
});
const result: ?PrivPartialConfig = yield* loadPrivatePartialConfig(opts); return new PartialConfig(
if (!result) return null; options,
babelrc ? babelrc.filepath : undefined,
const { options, babelrc, ignore, config, fileHandling, files } = result; ignore ? ignore.filepath : undefined,
config ? config.filepath : undefined,
if (fileHandling === "ignored" && !showIgnoredFiles) { fileHandling,
return null; files,
} );
});
(options.plugins || []).forEach(item => {
if (item.value instanceof Plugin) {
throw new Error(
"Passing cached plugin instances is not supported in " +
"babel.loadPartialConfig()",
);
}
});
return new PartialConfig(
options,
babelrc ? babelrc.filepath : undefined,
ignore ? ignore.filepath : undefined,
config ? config.filepath : undefined,
fileHandling,
files,
);
},
);
export type { PartialConfig }; export type { PartialConfig };

View File

@ -1,4 +1,3 @@
// @flow
import path from "path"; import path from "path";
const sep = `\\${path.sep}`; const sep = `\\${path.sep}`;

View File

@ -1,10 +1,8 @@
// @flow
import type { PluginObject } from "./validation/plugins"; import type { PluginObject } from "./validation/plugins";
export default class Plugin { export default class Plugin {
key: ?string; key: string | undefined | null;
manipulateOptions: ((options: mixed, parserOpts: mixed) => void) | void; manipulateOptions: ((options: unknown, parserOpts: unknown) => void) | void;
post: Function | void; post: Function | void;
pre: Function | void; pre: Function | void;
visitor: {}; visitor: {};

View File

@ -1,6 +1,6 @@
// @flow import gensync from "gensync";
import gensync, { type Handler } from "gensync"; import type { Handler } from "gensync";
import type { import type {
OptionsAndDescriptors, OptionsAndDescriptors,
@ -14,19 +14,19 @@ export const ChainFormatter = {
}; };
type PrintableConfig = { type PrintableConfig = {
content: OptionsAndDescriptors, content: OptionsAndDescriptors;
type: $Values<typeof ChainFormatter>, type: typeof ChainFormatter[keyof typeof ChainFormatter];
callerName: ?string, callerName: string | undefined | null;
filepath: ?string, filepath: string | undefined | null;
index: ?number, index: number | undefined | null;
envName: ?string, envName: string | undefined | null;
}; };
const Formatter = { const Formatter = {
title( title(
type: $Values<typeof ChainFormatter>, type: typeof ChainFormatter[keyof typeof ChainFormatter],
callerName: ?string, callerName?: string | null,
filepath: ?string, filepath?: string | null,
): string { ): string {
let title = ""; let title = "";
if (type === ChainFormatter.Programmatic) { if (type === ChainFormatter.Programmatic) {
@ -35,12 +35,11 @@ const Formatter = {
title += " from " + callerName; title += " from " + callerName;
} }
} else { } else {
// $FlowIgnore
title = "config " + filepath; title = "config " + filepath;
} }
return title; return title;
}, },
loc(index: ?number, envName: ?string): string { loc(index?: number | null, envName?: string | null): string {
let loc = ""; let loc = "";
if (index != null) { if (index != null) {
loc += `.overrides[${index}]`; loc += `.overrides[${index}]`;
@ -69,7 +68,9 @@ const Formatter = {
}, },
}; };
function descriptorToConfig(d: UnloadedDescriptor): string | {} | Array<mixed> { function descriptorToConfig(
d: UnloadedDescriptor,
): string | {} | Array<unknown> {
let name = d.file?.request; let name = d.file?.request;
if (name == null) { if (name == null) {
if (typeof d.value === "object") { if (typeof d.value === "object") {
@ -97,14 +98,20 @@ export class ConfigPrinter {
_stack: Array<PrintableConfig> = []; _stack: Array<PrintableConfig> = [];
configure( configure(
enabled: boolean, enabled: boolean,
type: $Values<typeof ChainFormatter>, type: typeof ChainFormatter[keyof typeof ChainFormatter],
{ callerName, filepath }: { callerName?: string, filepath?: string }, {
callerName,
filepath,
}: {
callerName?: string;
filepath?: string;
},
) { ) {
if (!enabled) return () => {}; if (!enabled) return () => {};
return ( return (
content: OptionsAndDescriptors, content: OptionsAndDescriptors,
index: ?number, index?: number | null,
envName: ?string, envName?: string | null,
) => { ) => {
this._stack.push({ this._stack.push({
type, type,

View File

@ -1,12 +1,12 @@
// @flow
import type { ValidatedOptions } from "./validation/options"; import type { ValidatedOptions } from "./validation/options";
import getTargets, { type Targets } from "@babel/helper-compilation-targets"; import getTargets from "@babel/helper-compilation-targets";
import type { Targets } from "@babel/helper-compilation-targets";
export function resolveBrowserslistConfigFile( export function resolveBrowserslistConfigFile(
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
browserslistConfigFile: string, browserslistConfigFile: string,
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
configFilePath: string, configFilePath: string,
): string | void { ): string | void {
return undefined; return undefined;
@ -14,19 +14,19 @@ export function resolveBrowserslistConfigFile(
export function resolveTargets( export function resolveTargets(
options: ValidatedOptions, options: ValidatedOptions,
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
root: string, root: string,
): Targets { ): Targets {
let { targets } = options; // todo(flow->ts) remove any and refactor to not assign different types into same variable
let targets: any = options.targets;
if (typeof targets === "string" || Array.isArray(targets)) { if (typeof targets === "string" || Array.isArray(targets)) {
targets = { browsers: targets }; targets = { browsers: targets };
} }
// $FlowIgnore it thinks that targets.esmodules doesn't exist.
if (targets && targets.esmodules) { if (targets && targets.esmodules) {
targets = { ...targets, esmodules: "intersect" }; targets = { ...targets, esmodules: "intersect" };
} }
return getTargets((targets: any), { return getTargets(targets, {
ignoreBrowserslistConfig: true, ignoreBrowserslistConfig: true,
browserslistEnv: options.browserslistEnv, browserslistEnv: options.browserslistEnv,
}); });

View File

@ -1,20 +1,20 @@
// @flow type browserType = typeof import("./resolve-targets-browser");
type nodeType = typeof import("./resolve-targets");
import typeof * as browserType from "./resolve-targets-browser";
import typeof * as nodeType from "./resolve-targets";
// Kind of gross, but essentially asserting that the exports of this module are the same as the // Kind of gross, but essentially asserting that the exports of this module are the same as the
// exports of index-browser, since this file may be replaced at bundle time with index-browser. // exports of index-browser, since this file may be replaced at bundle time with index-browser.
((({}: any): $Exact<browserType>): $Exact<nodeType>); ((({} as any) as browserType) as nodeType);
import type { ValidatedOptions } from "./validation/options"; import type { ValidatedOptions } from "./validation/options";
import path from "path"; import path from "path";
import getTargets, { type Targets } from "@babel/helper-compilation-targets"; import getTargets from "@babel/helper-compilation-targets";
import type { Targets } from "@babel/helper-compilation-targets";
export function resolveBrowserslistConfigFile( export function resolveBrowserslistConfigFile(
browserslistConfigFile: string, browserslistConfigFile: string,
configFileDir: string, configFileDir: string,
): string | void { ): string | undefined {
return path.resolve(configFileDir, browserslistConfigFile); return path.resolve(configFileDir, browserslistConfigFile);
} }
@ -22,11 +22,11 @@ export function resolveTargets(
options: ValidatedOptions, options: ValidatedOptions,
root: string, root: string,
): Targets { ): Targets {
let { targets } = options; // todo(flow->ts) remove any and refactor to not assign different types into same variable
let targets: any = options.targets;
if (typeof targets === "string" || Array.isArray(targets)) { if (typeof targets === "string" || Array.isArray(targets)) {
targets = { browsers: targets }; targets = { browsers: targets };
} }
// $FlowIgnore it thinks that targets.esmodules doesn't exist.
if (targets && targets.esmodules) { if (targets && targets.esmodules) {
targets = { ...targets, esmodules: "intersect" }; targets = { ...targets, esmodules: "intersect" };
} }
@ -40,7 +40,7 @@ export function resolveTargets(
ignoreBrowserslistConfig = browserslistConfigFile === false; ignoreBrowserslistConfig = browserslistConfigFile === false;
} }
return getTargets((targets: any), { return getTargets(targets, {
ignoreBrowserslistConfig, ignoreBrowserslistConfig,
configFile, configFile,
configPath: root, configPath: root,

View File

@ -1,5 +1,3 @@
// @flow
import type { ValidatedOptions, NormalizedOptions } from "./validation/options"; import type { ValidatedOptions, NormalizedOptions } from "./validation/options";
export function mergeOptions( export function mergeOptions(
@ -16,25 +14,22 @@ export function mergeOptions(
mergeDefaultFields(targetObj, parserOpts); mergeDefaultFields(targetObj, parserOpts);
} else { } else {
const val = source[k]; const val = source[k];
if (val !== undefined) target[k] = (val: any); if (val !== undefined) target[k] = val as any;
} }
} }
} }
function mergeDefaultFields<T: {}>(target: T, source: T) { function mergeDefaultFields<T extends {}>(target: T, source: T) {
for (const k of Object.keys(source)) { for (const k of Object.keys(source)) {
const val = source[k]; const val = source[k];
if (val !== undefined) target[k] = (val: any); if (val !== undefined) target[k] = val as any;
} }
} }
export function isIterableIterator(value: mixed): boolean %checks { export function isIterableIterator(value: any): value is IterableIterator<any> {
return ( return (
/*:: value instanceof Generator && */
// /*:: "@@iterator" in value && */
!!value && !!value &&
typeof value.next === "function" && typeof value.next === "function" &&
// $FlowIgnore
typeof value[Symbol.iterator] === "function" typeof value[Symbol.iterator] === "function"
); );
} }

View File

@ -1,5 +1,3 @@
// @flow
import { import {
isBrowsersQueryValid, isBrowsersQueryValid,
TargetNames, TargetNames,
@ -29,10 +27,10 @@ import { assumptionsNames } from "./options";
export type { RootPath } from "./options"; export type { RootPath } from "./options";
export type ValidatorSet = { export type ValidatorSet = {
[string]: Validator<any>, [name: string]: Validator<any>;
}; };
export type Validator<T> = (OptionPath, mixed) => T; export type Validator<T> = (loc: OptionPath, value: unknown) => T;
export function msg(loc: NestingPath | GeneralPath) { export function msg(loc: NestingPath | GeneralPath) {
switch (loc.type) { switch (loc.type) {
@ -47,6 +45,7 @@ export function msg(loc: NestingPath | GeneralPath) {
case "access": case "access":
return `${msg(loc.parent)}[${JSON.stringify(loc.name)}]`; return `${msg(loc.parent)}[${JSON.stringify(loc.name)}]`;
default: default:
// @ts-ignore should not happen when code is type checked
throw new Error(`Assertion failure: Unknown type ${loc.type}`); throw new Error(`Assertion failure: Unknown type ${loc.type}`);
} }
} }
@ -59,19 +58,22 @@ export function access(loc: GeneralPath, name: string | number): AccessPath {
}; };
} }
export type OptionPath = $ReadOnly<{ export type OptionPath = Readonly<{
type: "option", type: "option";
name: string, name: string;
parent: NestingPath, parent: NestingPath;
}>; }>;
type AccessPath = $ReadOnly<{ type AccessPath = Readonly<{
type: "access", type: "access";
name: string | number, name: string | number;
parent: GeneralPath, parent: GeneralPath;
}>; }>;
type GeneralPath = OptionPath | AccessPath; type GeneralPath = OptionPath | AccessPath;
export function assertRootMode(loc: OptionPath, value: mixed): RootMode | void { export function assertRootMode(
loc: OptionPath,
value: unknown,
): RootMode | void {
if ( if (
value !== undefined && value !== undefined &&
value !== "root" && value !== "root" &&
@ -87,7 +89,7 @@ export function assertRootMode(loc: OptionPath, value: mixed): RootMode | void {
export function assertSourceMaps( export function assertSourceMaps(
loc: OptionPath, loc: OptionPath,
value: mixed, value: unknown,
): SourceMapsOption | void { ): SourceMapsOption | void {
if ( if (
value !== undefined && value !== undefined &&
@ -104,7 +106,7 @@ export function assertSourceMaps(
export function assertCompact( export function assertCompact(
loc: OptionPath, loc: OptionPath,
value: mixed, value: unknown,
): CompactOption | void { ): CompactOption | void {
if (value !== undefined && typeof value !== "boolean" && value !== "auto") { if (value !== undefined && typeof value !== "boolean" && value !== "auto") {
throw new Error(`${msg(loc)} must be a boolean, "auto", or undefined`); throw new Error(`${msg(loc)} must be a boolean, "auto", or undefined`);
@ -114,7 +116,7 @@ export function assertCompact(
export function assertSourceType( export function assertSourceType(
loc: OptionPath, loc: OptionPath,
value: mixed, value: unknown,
): SourceTypeOption | void { ): SourceTypeOption | void {
if ( if (
value !== undefined && value !== undefined &&
@ -131,11 +133,11 @@ export function assertSourceType(
export function assertCallerMetadata( export function assertCallerMetadata(
loc: OptionPath, loc: OptionPath,
value: mixed, value: unknown,
): CallerMetadata | void { ): CallerMetadata | void {
const obj = assertObject(loc, value); const obj = assertObject(loc, value);
if (obj) { if (obj) {
if (typeof obj[("name": string)] !== "string") { if (typeof obj.name !== "string") {
throw new Error( throw new Error(
`${msg(loc)} set but does not contain "name" property string`, `${msg(loc)} set but does not contain "name" property string`,
); );
@ -161,12 +163,13 @@ export function assertCallerMetadata(
} }
} }
} }
return (value: any); // @ts-expect-error todo(flow->ts)
return value;
} }
export function assertInputSourceMap( export function assertInputSourceMap(
loc: OptionPath, loc: OptionPath,
value: mixed, value: unknown,
): RootInputSourceMapOption | void { ): RootInputSourceMapOption | void {
if ( if (
value !== undefined && value !== undefined &&
@ -178,7 +181,7 @@ export function assertInputSourceMap(
return value; return value;
} }
export function assertString(loc: GeneralPath, value: mixed): string | void { export function assertString(loc: GeneralPath, value: unknown): string | void {
if (value !== undefined && typeof value !== "string") { if (value !== undefined && typeof value !== "string") {
throw new Error(`${msg(loc)} must be a string, or undefined`); throw new Error(`${msg(loc)} must be a string, or undefined`);
} }
@ -187,7 +190,7 @@ export function assertString(loc: GeneralPath, value: mixed): string | void {
export function assertFunction( export function assertFunction(
loc: GeneralPath, loc: GeneralPath,
value: mixed, value: unknown,
): Function | void { ): Function | void {
if (value !== undefined && typeof value !== "function") { if (value !== undefined && typeof value !== "function") {
throw new Error(`${msg(loc)} must be a function, or undefined`); throw new Error(`${msg(loc)} must be a function, or undefined`);
@ -195,7 +198,10 @@ export function assertFunction(
return value; return value;
} }
export function assertBoolean(loc: GeneralPath, value: mixed): boolean | void { export function assertBoolean(
loc: GeneralPath,
value: unknown,
): boolean | void {
if (value !== undefined && typeof value !== "boolean") { if (value !== undefined && typeof value !== "boolean") {
throw new Error(`${msg(loc)} must be a boolean, or undefined`); throw new Error(`${msg(loc)} must be a boolean, or undefined`);
} }
@ -204,21 +210,22 @@ export function assertBoolean(loc: GeneralPath, value: mixed): boolean | void {
export function assertObject( export function assertObject(
loc: GeneralPath, loc: GeneralPath,
value: mixed, value: unknown,
): { +[string]: mixed } | void { ): { readonly [key: string]: unknown } | void {
if ( if (
value !== undefined && value !== undefined &&
(typeof value !== "object" || Array.isArray(value) || !value) (typeof value !== "object" || Array.isArray(value) || !value)
) { ) {
throw new Error(`${msg(loc)} must be an object, or undefined`); throw new Error(`${msg(loc)} must be an object, or undefined`);
} }
// @ts-expect-error todo(flow->ts) value is still typed as unknown, also assert function typically should not return a value
return value; return value;
} }
export function assertArray( export function assertArray<T>(
loc: GeneralPath, loc: GeneralPath,
value: mixed, value: Array<T> | undefined | null,
): ?$ReadOnlyArray<mixed> { ): ReadonlyArray<T> | undefined | null {
if (value != null && !Array.isArray(value)) { if (value != null && !Array.isArray(value)) {
throw new Error(`${msg(loc)} must be an array, or undefined`); throw new Error(`${msg(loc)} must be an array, or undefined`);
} }
@ -227,15 +234,16 @@ export function assertArray(
export function assertIgnoreList( export function assertIgnoreList(
loc: OptionPath, loc: OptionPath,
value: mixed, value: unknown[] | undefined,
): IgnoreList | void { ): IgnoreList | void {
const arr = assertArray(loc, value); const arr = assertArray(loc, value);
if (arr) { if (arr) {
arr.forEach((item, i) => assertIgnoreItem(access(loc, i), item)); arr.forEach((item, i) => assertIgnoreItem(access(loc, i), item));
} }
return (arr: any); // @ts-expect-error todo(flow->ts)
return arr;
} }
function assertIgnoreItem(loc: GeneralPath, value: mixed): IgnoreItem { function assertIgnoreItem(loc: GeneralPath, value: unknown): IgnoreItem {
if ( if (
typeof value !== "string" && typeof value !== "string" &&
typeof value !== "function" && typeof value !== "function" &&
@ -252,7 +260,7 @@ function assertIgnoreItem(loc: GeneralPath, value: mixed): IgnoreItem {
export function assertConfigApplicableTest( export function assertConfigApplicableTest(
loc: OptionPath, loc: OptionPath,
value: mixed, value: unknown,
): ConfigApplicableTest | void { ): ConfigApplicableTest | void {
if (value === undefined) return value; if (value === undefined) return value;
@ -269,10 +277,10 @@ export function assertConfigApplicableTest(
`${msg(loc)} must be a string/Function/RegExp, or an array of those`, `${msg(loc)} must be a string/Function/RegExp, or an array of those`,
); );
} }
return (value: any); return value;
} }
function checkValidTest(value: mixed): boolean { function checkValidTest(value: unknown): value is string | Function | RegExp {
return ( return (
typeof value === "string" || typeof value === "string" ||
typeof value === "function" || typeof value === "function" ||
@ -282,7 +290,7 @@ function checkValidTest(value: mixed): boolean {
export function assertConfigFileSearch( export function assertConfigFileSearch(
loc: OptionPath, loc: OptionPath,
value: mixed, value: unknown,
): ConfigFileSearch | void { ): ConfigFileSearch | void {
if ( if (
value !== undefined && value !== undefined &&
@ -291,7 +299,7 @@ export function assertConfigFileSearch(
) { ) {
throw new Error( throw new Error(
`${msg(loc)} must be a undefined, a boolean, a string, ` + `${msg(loc)} must be a undefined, a boolean, a string, ` +
`got ${JSON.stringify((value: any))}`, `got ${JSON.stringify(value)}`,
); );
} }
@ -300,7 +308,7 @@ export function assertConfigFileSearch(
export function assertBabelrcSearch( export function assertBabelrcSearch(
loc: OptionPath, loc: OptionPath,
value: mixed, value: unknown,
): BabelrcSearch | void { ): BabelrcSearch | void {
if (value === undefined || typeof value === "boolean") return value; if (value === undefined || typeof value === "boolean") return value;
@ -315,15 +323,15 @@ export function assertBabelrcSearch(
} else if (!checkValidTest(value)) { } else if (!checkValidTest(value)) {
throw new Error( throw new Error(
`${msg(loc)} must be a undefined, a boolean, a string/Function/RegExp ` + `${msg(loc)} must be a undefined, a boolean, a string/Function/RegExp ` +
`or an array of those, got ${JSON.stringify((value: any))}`, `or an array of those, got ${JSON.stringify(value as any)}`,
); );
} }
return (value: any); return value;
} }
export function assertPluginList( export function assertPluginList(
loc: OptionPath, loc: OptionPath,
value: mixed, value: unknown[] | null | undefined,
): PluginList | void { ): PluginList | void {
const arr = assertArray(loc, value); const arr = assertArray(loc, value);
if (arr) { if (arr) {
@ -331,9 +339,9 @@ export function assertPluginList(
// for plugin array for use during config chain processing. // for plugin array for use during config chain processing.
arr.forEach((item, i) => assertPluginItem(access(loc, i), item)); arr.forEach((item, i) => assertPluginItem(access(loc, i), item));
} }
return (arr: any); return arr as any;
} }
function assertPluginItem(loc: GeneralPath, value: mixed): PluginItem { function assertPluginItem(loc: GeneralPath, value: unknown): PluginItem {
if (Array.isArray(value)) { if (Array.isArray(value)) {
if (value.length === 0) { if (value.length === 0) {
throw new Error(`${msg(loc)} must include an object`); throw new Error(`${msg(loc)} must include an object`);
@ -369,9 +377,10 @@ function assertPluginItem(loc: GeneralPath, value: mixed): PluginItem {
assertPluginTarget(loc, value); assertPluginTarget(loc, value);
} }
return (value: any); // @ts-expect-error todo(flow->ts)
return value;
} }
function assertPluginTarget(loc: GeneralPath, value: mixed): PluginTarget { function assertPluginTarget(loc: GeneralPath, value: unknown): PluginTarget {
if ( if (
(typeof value !== "object" || !value) && (typeof value !== "object" || !value) &&
typeof value !== "string" && typeof value !== "string" &&
@ -384,9 +393,9 @@ function assertPluginTarget(loc: GeneralPath, value: mixed): PluginTarget {
export function assertTargets( export function assertTargets(
loc: GeneralPath, loc: GeneralPath,
value: mixed, value: any,
): TargetsListOrObject { ): TargetsListOrObject {
if (isBrowsersQueryValid(value)) return (value: any); if (isBrowsersQueryValid(value)) return value;
if (typeof value !== "object" || !value || Array.isArray(value)) { if (typeof value !== "object" || !value || Array.isArray(value)) {
throw new Error( throw new Error(
@ -416,10 +425,10 @@ export function assertTargets(
} else assertBrowserVersion(subLoc, val); } else assertBrowserVersion(subLoc, val);
} }
return (value: any); return value;
} }
function assertBrowsersList(loc: GeneralPath, value: mixed) { function assertBrowsersList(loc: GeneralPath, value: unknown) {
if (value !== undefined && !isBrowsersQueryValid(value)) { if (value !== undefined && !isBrowsersQueryValid(value)) {
throw new Error( throw new Error(
`${msg(loc)} must be undefined, a string or an array of strings`, `${msg(loc)} must be undefined, a string or an array of strings`,
@ -427,7 +436,7 @@ function assertBrowsersList(loc: GeneralPath, value: mixed) {
} }
} }
function assertBrowserVersion(loc: GeneralPath, value: mixed) { function assertBrowserVersion(loc: GeneralPath, value: unknown) {
if (typeof value === "number" && Math.round(value) === value) return; if (typeof value === "number" && Math.round(value) === value) return;
if (typeof value === "string") return; if (typeof value === "string") return;
@ -436,7 +445,7 @@ function assertBrowserVersion(loc: GeneralPath, value: mixed) {
export function assertAssumptions( export function assertAssumptions(
loc: GeneralPath, loc: GeneralPath,
value: mixed, value: unknown,
): { [name: string]: boolean } | void { ): { [name: string]: boolean } | void {
if (value === undefined) return; if (value === undefined) return;
@ -444,7 +453,8 @@ export function assertAssumptions(
throw new Error(`${msg(loc)} must be an object or undefined.`); throw new Error(`${msg(loc)} must be an object or undefined.`);
} }
let root = loc; // todo(flow->ts): remove any
let root: any = loc;
do { do {
root = root.parent; root = root.parent;
} while (root.type !== "root"); } while (root.type !== "root");
@ -465,5 +475,6 @@ export function assertAssumptions(
} }
} }
return (value: any); // @ts-expect-error todo(flow->ts)
return value;
} }

View File

@ -1,5 +1,3 @@
// @flow
import type { InputTargets, Targets } from "@babel/helper-compilation-targets"; import type { InputTargets, Targets } from "@babel/helper-compilation-targets";
import type { ConfigItem } from "../item"; import type { ConfigItem } from "../item";
@ -26,159 +24,99 @@ import {
assertCompact, assertCompact,
assertSourceType, assertSourceType,
assertTargets, assertTargets,
type ValidatorSet,
type Validator,
type OptionPath,
assertAssumptions, assertAssumptions,
} from "./option-assertions"; } from "./option-assertions";
import type { ValidatorSet, Validator, OptionPath } from "./option-assertions";
import type { UnloadedDescriptor } from "../config-descriptors"; import type { UnloadedDescriptor } from "../config-descriptors";
const ROOT_VALIDATORS: ValidatorSet = { const ROOT_VALIDATORS: ValidatorSet = {
cwd: (assertString: Validator<$PropertyType<ValidatedOptions, "cwd">>), cwd: assertString as Validator<ValidatedOptions["cwd"]>,
root: (assertString: Validator<$PropertyType<ValidatedOptions, "root">>), root: assertString as Validator<ValidatedOptions["root"]>,
rootMode: (assertRootMode: Validator< rootMode: assertRootMode as Validator<ValidatedOptions["rootMode"]>,
$PropertyType<ValidatedOptions, "rootMode">, configFile: assertConfigFileSearch as Validator<
>), ValidatedOptions["configFile"]
configFile: (assertConfigFileSearch: Validator< >,
$PropertyType<ValidatedOptions, "configFile">,
>),
caller: (assertCallerMetadata: Validator< caller: assertCallerMetadata as Validator<ValidatedOptions["caller"]>,
$PropertyType<ValidatedOptions, "caller">, filename: assertString as Validator<ValidatedOptions["filename"]>,
>), filenameRelative: assertString as Validator<
filename: (assertString: Validator< ValidatedOptions["filenameRelative"]
$PropertyType<ValidatedOptions, "filename">, >,
>), code: assertBoolean as Validator<ValidatedOptions["code"]>,
filenameRelative: (assertString: Validator< ast: assertBoolean as Validator<ValidatedOptions["ast"]>,
$PropertyType<ValidatedOptions, "filenameRelative">,
>),
code: (assertBoolean: Validator<$PropertyType<ValidatedOptions, "code">>),
ast: (assertBoolean: Validator<$PropertyType<ValidatedOptions, "ast">>),
cloneInputAst: (assertBoolean: Validator< cloneInputAst: assertBoolean as Validator<ValidatedOptions["cloneInputAst"]>,
$PropertyType<ValidatedOptions, "cloneInputAst">,
>),
envName: (assertString: Validator< envName: assertString as Validator<ValidatedOptions["envName"]>,
$PropertyType<ValidatedOptions, "envName">,
>),
}; };
const BABELRC_VALIDATORS: ValidatorSet = { const BABELRC_VALIDATORS: ValidatorSet = {
babelrc: (assertBoolean: Validator< babelrc: assertBoolean as Validator<ValidatedOptions["babelrc"]>,
$PropertyType<ValidatedOptions, "babelrc">, babelrcRoots: assertBabelrcSearch as Validator<
>), ValidatedOptions["babelrcRoots"]
babelrcRoots: (assertBabelrcSearch: Validator< >,
$PropertyType<ValidatedOptions, "babelrcRoots">,
>),
}; };
const NONPRESET_VALIDATORS: ValidatorSet = { const NONPRESET_VALIDATORS: ValidatorSet = {
extends: (assertString: Validator< extends: assertString as Validator<ValidatedOptions["extends"]>,
$PropertyType<ValidatedOptions, "extends">, ignore: assertIgnoreList as Validator<ValidatedOptions["ignore"]>,
>), only: assertIgnoreList as Validator<ValidatedOptions["only"]>,
ignore: (assertIgnoreList: Validator<
$PropertyType<ValidatedOptions, "ignore">,
>),
only: (assertIgnoreList: Validator<$PropertyType<ValidatedOptions, "only">>),
targets: (assertTargets: Validator< targets: assertTargets as Validator<ValidatedOptions["targets"]>,
$PropertyType<ValidatedOptions, "targets">, browserslistConfigFile: assertConfigFileSearch as Validator<
>), ValidatedOptions["browserslistConfigFile"]
browserslistConfigFile: (assertConfigFileSearch: Validator< >,
$PropertyType<ValidatedOptions, "browserslistConfigFile">, browserslistEnv: assertString as Validator<
>), ValidatedOptions["browserslistEnv"]
browserslistEnv: (assertString: Validator< >,
$PropertyType<ValidatedOptions, "browserslistEnv">,
>),
}; };
const COMMON_VALIDATORS: ValidatorSet = { const COMMON_VALIDATORS: ValidatorSet = {
// TODO: Should 'inputSourceMap' be moved to be a root-only option? // TODO: Should 'inputSourceMap' be moved to be a root-only option?
// We may want a boolean-only version to be a common option, with the // We may want a boolean-only version to be a common option, with the
// object only allowed as a root config argument. // object only allowed as a root config argument.
inputSourceMap: (assertInputSourceMap: Validator< inputSourceMap: assertInputSourceMap as Validator<
$PropertyType<ValidatedOptions, "inputSourceMap">, ValidatedOptions["inputSourceMap"]
>), >,
presets: (assertPluginList: Validator< presets: assertPluginList as Validator<ValidatedOptions["presets"]>,
$PropertyType<ValidatedOptions, "presets">, plugins: assertPluginList as Validator<ValidatedOptions["plugins"]>,
>), passPerPreset: assertBoolean as Validator<ValidatedOptions["passPerPreset"]>,
plugins: (assertPluginList: Validator< assumptions: assertAssumptions as Validator<ValidatedOptions["assumptions"]>,
$PropertyType<ValidatedOptions, "plugins">,
>),
passPerPreset: (assertBoolean: Validator<
$PropertyType<ValidatedOptions, "passPerPreset">,
>),
assumptions: (assertAssumptions: Validator<
$PropertyType<ValidatedOptions, "assumptions">,
>),
env: (assertEnvSet: Validator<$PropertyType<ValidatedOptions, "env">>), env: assertEnvSet as Validator<ValidatedOptions["env"]>,
overrides: (assertOverridesList: Validator< overrides: assertOverridesList as Validator<ValidatedOptions["overrides"]>,
$PropertyType<ValidatedOptions, "overrides">,
>),
// We could limit these to 'overrides' blocks, but it's not clear why we'd // We could limit these to 'overrides' blocks, but it's not clear why we'd
// bother, when the ability to limit a config to a specific set of files // bother, when the ability to limit a config to a specific set of files
// is a fairly general useful feature. // is a fairly general useful feature.
test: (assertConfigApplicableTest: Validator< test: assertConfigApplicableTest as Validator<ValidatedOptions["test"]>,
$PropertyType<ValidatedOptions, "test">, include: assertConfigApplicableTest as Validator<ValidatedOptions["include"]>,
>), exclude: assertConfigApplicableTest as Validator<ValidatedOptions["exclude"]>,
include: (assertConfigApplicableTest: Validator<
$PropertyType<ValidatedOptions, "include">,
>),
exclude: (assertConfigApplicableTest: Validator<
$PropertyType<ValidatedOptions, "exclude">,
>),
retainLines: (assertBoolean: Validator< retainLines: assertBoolean as Validator<ValidatedOptions["retainLines"]>,
$PropertyType<ValidatedOptions, "retainLines">, comments: assertBoolean as Validator<ValidatedOptions["comments"]>,
>), shouldPrintComment: assertFunction as Validator<
comments: (assertBoolean: Validator< ValidatedOptions["shouldPrintComment"]
$PropertyType<ValidatedOptions, "comments">, >,
>), compact: assertCompact as Validator<ValidatedOptions["compact"]>,
shouldPrintComment: (assertFunction: Validator< minified: assertBoolean as Validator<ValidatedOptions["minified"]>,
$PropertyType<ValidatedOptions, "shouldPrintComment">, auxiliaryCommentBefore: assertString as Validator<
>), ValidatedOptions["auxiliaryCommentBefore"]
compact: (assertCompact: Validator< >,
$PropertyType<ValidatedOptions, "compact">, auxiliaryCommentAfter: assertString as Validator<
>), ValidatedOptions["auxiliaryCommentAfter"]
minified: (assertBoolean: Validator< >,
$PropertyType<ValidatedOptions, "minified">, sourceType: assertSourceType as Validator<ValidatedOptions["sourceType"]>,
>), wrapPluginVisitorMethod: assertFunction as Validator<
auxiliaryCommentBefore: (assertString: Validator< ValidatedOptions["wrapPluginVisitorMethod"]
$PropertyType<ValidatedOptions, "auxiliaryCommentBefore">, >,
>), highlightCode: assertBoolean as Validator<ValidatedOptions["highlightCode"]>,
auxiliaryCommentAfter: (assertString: Validator< sourceMaps: assertSourceMaps as Validator<ValidatedOptions["sourceMaps"]>,
$PropertyType<ValidatedOptions, "auxiliaryCommentAfter">, sourceMap: assertSourceMaps as Validator<ValidatedOptions["sourceMap"]>,
>), sourceFileName: assertString as Validator<ValidatedOptions["sourceFileName"]>,
sourceType: (assertSourceType: Validator< sourceRoot: assertString as Validator<ValidatedOptions["sourceRoot"]>,
$PropertyType<ValidatedOptions, "sourceType">, parserOpts: assertObject as Validator<ValidatedOptions["parserOpts"]>,
>), generatorOpts: assertObject as Validator<ValidatedOptions["generatorOpts"]>,
wrapPluginVisitorMethod: (assertFunction: Validator<
$PropertyType<ValidatedOptions, "wrapPluginVisitorMethod">,
>),
highlightCode: (assertBoolean: Validator<
$PropertyType<ValidatedOptions, "highlightCode">,
>),
sourceMaps: (assertSourceMaps: Validator<
$PropertyType<ValidatedOptions, "sourceMaps">,
>),
sourceMap: (assertSourceMaps: Validator<
$PropertyType<ValidatedOptions, "sourceMap">,
>),
sourceFileName: (assertString: Validator<
$PropertyType<ValidatedOptions, "sourceFileName">,
>),
sourceRoot: (assertString: Validator<
$PropertyType<ValidatedOptions, "sourceRoot">,
>),
parserOpts: (assertObject: Validator<
$PropertyType<ValidatedOptions, "parserOpts">,
>),
generatorOpts: (assertObject: Validator<
$PropertyType<ValidatedOptions, "generatorOpts">,
>),
}; };
if (!process.env.BABEL_8_BREAKING) { if (!process.env.BABEL_8_BREAKING) {
Object.assign(COMMON_VALIDATORS, { Object.assign(COMMON_VALIDATORS, {
@ -192,95 +130,86 @@ if (!process.env.BABEL_8_BREAKING) {
export type InputOptions = ValidatedOptions; export type InputOptions = ValidatedOptions;
export type ValidatedOptions = { export type ValidatedOptions = {
cwd?: string, cwd?: string;
filename?: string, filename?: string;
filenameRelative?: string, filenameRelative?: string;
babelrc?: boolean, babelrc?: boolean;
babelrcRoots?: BabelrcSearch, babelrcRoots?: BabelrcSearch;
configFile?: ConfigFileSearch, configFile?: ConfigFileSearch;
root?: string, root?: string;
rootMode?: RootMode, rootMode?: RootMode;
code?: boolean, code?: boolean;
ast?: boolean, ast?: boolean;
cloneInputAst?: boolean, cloneInputAst?: boolean;
inputSourceMap?: RootInputSourceMapOption, inputSourceMap?: RootInputSourceMapOption;
envName?: string, envName?: string;
caller?: CallerMetadata, caller?: CallerMetadata;
extends?: string;
extends?: string, env?: EnvSet<ValidatedOptions>;
env?: EnvSet<ValidatedOptions>, ignore?: IgnoreList;
ignore?: IgnoreList, only?: IgnoreList;
only?: IgnoreList, overrides?: OverridesList;
overrides?: OverridesList,
// Generally verify if a given config object should be applied to the given file. // Generally verify if a given config object should be applied to the given file.
test?: ConfigApplicableTest, test?: ConfigApplicableTest;
include?: ConfigApplicableTest, include?: ConfigApplicableTest;
exclude?: ConfigApplicableTest, exclude?: ConfigApplicableTest;
presets?: PluginList;
presets?: PluginList, plugins?: PluginList;
plugins?: PluginList, passPerPreset?: boolean;
passPerPreset?: boolean, assumptions?: {
[name: string]: boolean;
assumptions?: { [name: string]: boolean }, };
// browserslists-related options // browserslists-related options
targets?: TargetsListOrObject, targets?: TargetsListOrObject;
browserslistConfigFile?: ConfigFileSearch, browserslistConfigFile?: ConfigFileSearch;
browserslistEnv?: string, browserslistEnv?: string;
// Options for @babel/generator // Options for @babel/generator
retainLines?: boolean, retainLines?: boolean;
comments?: boolean, comments?: boolean;
shouldPrintComment?: Function, shouldPrintComment?: Function;
compact?: CompactOption, compact?: CompactOption;
minified?: boolean, minified?: boolean;
auxiliaryCommentBefore?: string, auxiliaryCommentBefore?: string;
auxiliaryCommentAfter?: string, auxiliaryCommentAfter?: string;
// Parser // Parser
sourceType?: SourceTypeOption, sourceType?: SourceTypeOption;
wrapPluginVisitorMethod?: Function;
wrapPluginVisitorMethod?: Function, highlightCode?: boolean;
highlightCode?: boolean,
// Sourcemap generation options. // Sourcemap generation options.
sourceMaps?: SourceMapsOption, sourceMaps?: SourceMapsOption;
sourceMap?: SourceMapsOption, sourceMap?: SourceMapsOption;
sourceFileName?: string, sourceFileName?: string;
sourceRoot?: string, sourceRoot?: string;
// Deprecate top level parserOpts // Deprecate top level parserOpts
parserOpts?: {}, parserOpts?: {};
// Deprecate top level generatorOpts // Deprecate top level generatorOpts
generatorOpts?: {}, generatorOpts?: {};
}; };
export type NormalizedOptions = { export type NormalizedOptions = {
...$Diff<ValidatedOptions, { targets: any }>, readonly targets: Targets;
+targets: Targets, } & Omit<ValidatedOptions, "targets">;
};
export type CallerMetadata = { export type CallerMetadata = {
// If 'caller' is specified, require that the name is given for debugging // If 'caller' is specified, require that the name is given for debugging
// messages. // messages.
name: string, name: string;
}; };
export type EnvSet<T> = { export type EnvSet<T> = {
[string]: ?T, [x: string]: T;
}; };
export type IgnoreItem = string | Function | RegExp; export type IgnoreItem = string | Function | RegExp;
export type IgnoreList = $ReadOnlyArray<IgnoreItem>; export type IgnoreList = ReadonlyArray<IgnoreItem>;
export type PluginOptions = {} | void | false; export type PluginOptions = object | void | false;
export type PluginTarget = string | {} | Function; export type PluginTarget = string | object | Function;
export type PluginItem = export type PluginItem =
| ConfigItem | ConfigItem
| Plugin | Plugin
| PluginTarget | PluginTarget
| [PluginTarget, PluginOptions] | [PluginTarget, PluginOptions]
| [PluginTarget, PluginOptions, string | void]; | [PluginTarget, PluginOptions, string | void];
export type PluginList = $ReadOnlyArray<PluginItem>; export type PluginList = ReadonlyArray<PluginItem>;
export type OverridesList = Array<ValidatedOptions>; export type OverridesList = Array<ValidatedOptions>;
export type ConfigApplicableTest = IgnoreItem | Array<IgnoreItem>; export type ConfigApplicableTest = IgnoreItem | Array<IgnoreItem>;
@ -296,7 +225,7 @@ export type RootMode = "root" | "upward" | "upward-optional";
export type TargetsListOrObject = export type TargetsListOrObject =
| Targets | Targets
| InputTargets | InputTargets
| $PropertyType<InputTargets, "browsers">; | InputTargets["browsers"];
export type OptionsSource = export type OptionsSource =
| "arguments" | "arguments"
@ -306,20 +235,23 @@ export type OptionsSource =
| "preset" | "preset"
| "plugin"; | "plugin";
export type RootPath = $ReadOnly<{ export type RootPath = Readonly<{
type: "root", type: "root";
source: OptionsSource, source: OptionsSource;
}>; }>;
type OverridesPath = $ReadOnly<{
type: "overrides", type OverridesPath = Readonly<{
index: number, type: "overrides";
parent: RootPath, index: number;
parent: RootPath;
}>; }>;
type EnvPath = $ReadOnly<{
type: "env", type EnvPath = Readonly<{
name: string, type: "env";
parent: RootPath | OverridesPath, name: string;
parent: RootPath | OverridesPath;
}>; }>;
export type NestingPath = RootPath | OverridesPath | EnvPath; export type NestingPath = RootPath | OverridesPath | EnvPath;
export const assumptionsNames = new Set<string>([ export const assumptionsNames = new Set<string>([
@ -369,7 +301,7 @@ function validateNested(loc: NestingPath, opts: {}) {
type: "option", type: "option",
name: key, name: key,
parent: loc, parent: loc,
}; } as const;
if (type === "preset" && NONPRESET_VALIDATORS[key]) { if (type === "preset" && NONPRESET_VALIDATORS[key]) {
throw new Error(`${msg(optLoc)} is not allowed in preset options`); throw new Error(`${msg(optLoc)} is not allowed in preset options`);
@ -405,22 +337,19 @@ function validateNested(loc: NestingPath, opts: {}) {
NONPRESET_VALIDATORS[key] || NONPRESET_VALIDATORS[key] ||
BABELRC_VALIDATORS[key] || BABELRC_VALIDATORS[key] ||
ROOT_VALIDATORS[key] || ROOT_VALIDATORS[key] ||
(throwUnknownError: Validator<void>); (throwUnknownError as Validator<void>);
validator(optLoc, opts[key]); validator(optLoc, opts[key]);
}); });
return (opts: any); return opts;
} }
function throwUnknownError(loc: OptionPath) { function throwUnknownError(loc: OptionPath) {
const key = loc.name; const key = loc.name;
if (removed[key]) { if (removed[key]) {
const { const { message, version = 5 } = removed[key];
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}`,
@ -432,7 +361,7 @@ function throwUnknownError(loc: OptionPath) {
loc, loc,
)}. Check out https://babeljs.io/docs/en/babel-core/#options for more information about options.`, )}. Check out https://babeljs.io/docs/en/babel-core/#options for more information about options.`,
); );
// $FlowIgnore // @ts-expect-error todo(flow->ts): consider creating something like BabelConfigError with code field in it
unknownOptErr.code = "BABEL_UNKNOWN_OPTION"; unknownOptErr.code = "BABEL_UNKNOWN_OPTION";
throw unknownOptErr; throw unknownOptErr;
@ -449,7 +378,10 @@ function assertNoDuplicateSourcemap(opts: {}): void {
} }
} }
function assertEnvSet(loc: OptionPath, value: mixed): EnvSet<ValidatedOptions> { function assertEnvSet(
loc: OptionPath,
value: unknown,
): void | EnvSet<ValidatedOptions> {
if (loc.parent.type === "env") { if (loc.parent.type === "env") {
throw new Error(`${msg(loc)} is not allowed inside of another .env block`); throw new Error(`${msg(loc)} is not allowed inside of another .env block`);
} }
@ -467,14 +399,17 @@ function assertEnvSet(loc: OptionPath, value: mixed): EnvSet<ValidatedOptions> {
type: "env", type: "env",
name: envName, name: envName,
parent, parent,
}; } as const;
validateNested(envLoc, env); validateNested(envLoc, env);
} }
} }
return (obj: any); return obj;
} }
function assertOverridesList(loc: OptionPath, value: mixed): OverridesList { function assertOverridesList(
loc: OptionPath,
value: unknown[],
): undefined | OverridesList {
if (loc.parent.type === "env") { if (loc.parent.type === "env") {
throw new Error(`${msg(loc)} is not allowed inside an .env block`); throw new Error(`${msg(loc)} is not allowed inside an .env block`);
} }
@ -494,11 +429,12 @@ function assertOverridesList(loc: OptionPath, value: mixed): OverridesList {
type: "overrides", type: "overrides",
index, index,
parent, parent,
}; } as const;
validateNested(overridesLoc, env); validateNested(overridesLoc, env);
} }
} }
return (arr: any); // @ts-expect-error
return arr;
} }
export function checkNoUnwrappedItemOptionPairs( export function checkNoUnwrappedItemOptionPairs(

View File

@ -1,45 +1,42 @@
// @flow
import { import {
assertString, assertString,
assertFunction, assertFunction,
assertObject, assertObject,
msg, msg,
type ValidatorSet, } from "./option-assertions";
type Validator,
type OptionPath, import type {
type RootPath, ValidatorSet,
Validator,
OptionPath,
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
// that the assertion functions actually assert that the value's type matches // that the assertion functions actually assert that the value's type matches
// the declared types. // the declared types.
const VALIDATORS: ValidatorSet = { const VALIDATORS: ValidatorSet = {
name: (assertString: Validator<$PropertyType<PluginObject, "name">>), name: assertString as Validator<PluginObject["name"]>,
manipulateOptions: (assertFunction: Validator< manipulateOptions: assertFunction as Validator<
$PropertyType<PluginObject, "manipulateOptions">, PluginObject["manipulateOptions"]
>), >,
pre: (assertFunction: Validator<$PropertyType<PluginObject, "pre">>), pre: assertFunction as Validator<PluginObject["pre"]>,
post: (assertFunction: Validator<$PropertyType<PluginObject, "post">>), post: assertFunction as Validator<PluginObject["post"]>,
inherits: (assertFunction: Validator< inherits: assertFunction as Validator<PluginObject["inherits"]>,
$PropertyType<PluginObject, "inherits">, visitor: assertVisitorMap as Validator<PluginObject["visitor"]>,
>),
visitor: (assertVisitorMap: Validator<
$PropertyType<PluginObject, "visitor">,
>),
parserOverride: (assertFunction: Validator< parserOverride: assertFunction as Validator<PluginObject["parserOverride"]>,
$PropertyType<PluginObject, "parserOverride">, generatorOverride: assertFunction as Validator<
>), PluginObject["generatorOverride"]
generatorOverride: (assertFunction: Validator< >,
$PropertyType<PluginObject, "generatorOverride">,
>),
}; };
function assertVisitorMap(loc: OptionPath, value: mixed): VisitorMap { function assertVisitorMap(loc: OptionPath, value: unknown): VisitorMap {
const obj = assertObject(loc, 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]));
// @ts-ignore
if (obj.enter || obj.exit) { if (obj.enter || obj.exit) {
throw new Error( throw new Error(
`${msg( `${msg(
@ -48,12 +45,12 @@ function assertVisitorMap(loc: OptionPath, value: mixed): VisitorMap {
); );
} }
} }
return (obj: any); return obj as VisitorMap;
} }
function assertVisitorHandler( function assertVisitorHandler(
key: string, key: string,
value: mixed, value: unknown,
): VisitorHandler | void { ): VisitorHandler | void {
if (value && typeof value === "object") { if (value && typeof value === "object") {
Object.keys(value).forEach((handler: string) => { Object.keys(value).forEach((handler: string) => {
@ -67,26 +64,29 @@ function assertVisitorHandler(
throw new Error(`.visitor["${key}"] must be a function`); throw new Error(`.visitor["${key}"] must be a function`);
} }
return (value: any); return value as any;
} }
type VisitorHandler = Function | { enter?: Function, exit?: Function }; type VisitorHandler =
| Function
| {
enter?: Function;
exit?: Function;
};
export type VisitorMap = { export type VisitorMap = {
[string]: VisitorHandler, [x: string]: VisitorHandler;
}; };
export type PluginObject = { export type PluginObject = {
name?: string, name?: string;
manipulateOptions?: (options: mixed, parserOpts: mixed) => void, manipulateOptions?: (options: unknown, parserOpts: unknown) => void;
pre?: Function;
pre?: Function, post?: Function;
post?: Function, inherits?: Function;
visitor?: VisitorMap;
inherits?: Function, parserOverride?: Function;
visitor?: VisitorMap, generatorOverride?: Function;
parserOverride?: Function,
generatorOverride?: Function,
}; };
export function validatePluginObject(obj: {}): PluginObject { export function validatePluginObject(obj: {}): PluginObject {
@ -108,11 +108,11 @@ export function validatePluginObject(obj: {}): PluginObject {
const invalidPluginPropertyError = new Error( const invalidPluginPropertyError = new Error(
`.${key} is not a valid Plugin property`, `.${key} is not a valid Plugin property`,
); );
// $FlowIgnore // @ts-expect-error todo(flow->ts) consider additing BabelConfigError with code field
invalidPluginPropertyError.code = "BABEL_UNKNOWN_PLUGIN_PROPERTY"; invalidPluginPropertyError.code = "BABEL_UNKNOWN_PLUGIN_PROPERTY";
throw invalidPluginPropertyError; throw invalidPluginPropertyError;
} }
}); });
return (obj: any); return obj as any;
} }

View File

@ -1,5 +1,3 @@
// @flow
export default { export default {
auxiliaryComment: { auxiliaryComment: {
message: "Use `auxiliaryCommentBefore` or `auxiliaryCommentAfter`", message: "Use `auxiliaryCommentBefore` or `auxiliaryCommentAfter`",
@ -64,17 +62,15 @@ export default {
version: 6, version: 6,
message: "Use `babel-plugin-module-resolver@3`'s 'resolvePath' options", message: "Use `babel-plugin-module-resolver@3`'s 'resolvePath' options",
}, },
metadata: { metadata: {
version: 6, version: 6,
message: message:
"Generated plugin metadata is always included in the output result", "Generated plugin metadata is always included in the output result",
}, },
sourceMapTarget: { sourceMapTarget: {
version: 6, version: 6,
message: message:
"The `sourceMapTarget` option has been removed because it makes more sense for the tooling " + "The `sourceMapTarget` option has been removed because it makes more sense for the tooling " +
"that calls Babel to assign `map.file` themselves.", "that calls Babel to assign `map.file` themselves.",
}, },
}; } as { [name: string]: { version?: number; message: string } };

View File

@ -1,18 +1,26 @@
// @flow import gensync from "gensync";
import gensync, { type Gensync, type Handler } from "gensync";
import type { Gensync, Handler } from "gensync";
type MaybePromise<T> = T | Promise<T>; type MaybePromise<T> = T | Promise<T>;
const id = x => x; const id = x => x;
const runGenerator = gensync(function* (item) { const runGenerator: {
sync<Return>(gen: Generator<unknown, Return>): Return;
async<Return>(gen: Generator<unknown, Return>): Promise<Return>;
errback<Return>(
gen: Generator<unknown, Return>,
cb: (err: Error, val: Return) => void,
): void;
} = gensync<(item: Generator) => any>(function* <Return>(
item: Generator<unknown, Return>,
) {
return yield* item; return yield* item;
}); });
// This Gensync returns true if the current execution context is // This Gensync returns true if the current execution context is
// asynchronous, otherwise it returns false. // asynchronous, otherwise it returns false.
export const isAsync = gensync<[], boolean>({ export const isAsync = gensync<() => boolean>({
sync: () => false, sync: () => false,
errback: cb => cb(null, true), errback: cb => cb(null, true),
}); });
@ -22,13 +30,13 @@ export const isAsync = gensync<[], boolean>({
// but the current execution context is synchronous, it will throw the // but the current execution context is synchronous, it will throw the
// provided error. // provided error.
// This is used to handle user-provided functions which could be asynchronous. // This is used to handle user-provided functions which could be asynchronous.
export function maybeAsync<T, Args: any[]>( export function maybeAsync<Fn extends (...args: any) => any>(
fn: (...args: Args) => T, fn: Fn,
message: string, message: string,
): Gensync<Args, T> { ): Gensync<Fn> {
return gensync({ return gensync({
sync(...args) { sync(...args) {
const result = fn.apply(this, args); const result = fn.apply(this, args) as ReturnType<Fn>;
if (isThenable(result)) throw new Error(message); if (isThenable(result)) throw new Error(message);
return result; return result;
}, },
@ -38,10 +46,10 @@ export function maybeAsync<T, Args: any[]>(
}); });
} }
const withKind = (gensync<[any], any>({ const withKind = gensync<(cb: (kind: "sync" | "async") => any) => any>({
sync: cb => cb("sync"), sync: cb => cb("sync"),
async: cb => cb("async"), async: cb => cb("async"),
}): <T>(cb: (kind: "sync" | "async") => MaybePromise<T>) => Handler<T>); }) as <T>(cb: (kind: "sync" | "async") => MaybePromise<T>) => Handler<T>;
// This function wraps a generator (or a Gensync) into another function which, // This function wraps a generator (or a Gensync) into another function which,
// when called, will run the provided generator in a sync or async way, depending // when called, will run the provided generator in a sync or async way, depending
@ -57,14 +65,17 @@ const withKind = (gensync<[any], any>({
// return wrappedFn(x); // return wrappedFn(x);
// }) // })
// ) // )
export function forwardAsync<ActionArgs: mixed[], ActionReturn, Return>( export function forwardAsync<
action: (...args: ActionArgs) => Handler<ActionReturn>, Action extends (...args: unknown[]) => any,
Return
>(
action: (...args: Parameters<Action>) => Handler<ReturnType<Action>>,
cb: ( cb: (
adapted: (...args: ActionArgs) => MaybePromise<ActionReturn>, adapted: (...args: Parameters<Action>) => MaybePromise<ReturnType<Action>>,
) => MaybePromise<Return>, ) => MaybePromise<Return>,
): Handler<Return> { ): Handler<Return> {
const g = gensync<ActionArgs, ActionReturn>(action); const g = gensync<Action>(action);
return withKind<Return>(kind => { return withKind(kind => {
const adapted = g[kind]; const adapted = g[kind];
return cb(adapted); return cb(adapted);
}); });
@ -73,7 +84,7 @@ export function forwardAsync<ActionArgs: mixed[], ActionReturn, Return>(
// If the given generator is executed asynchronously, the first time that it // If the given generator is executed asynchronously, the first time that it
// is paused (i.e. When it yields a gensync generator which can't be run // is paused (i.e. When it yields a gensync generator which can't be run
// synchronously), call the "firstPause" callback. // synchronously), call the "firstPause" callback.
export const onFirstPause = (gensync<[any, any], any>({ export const onFirstPause = gensync<(gen: Generator, cb: Function) => any>({
name: "onFirstPause", name: "onFirstPause",
arity: 2, arity: 2,
sync: function (item) { sync: function (item) {
@ -91,17 +102,16 @@ export const onFirstPause = (gensync<[any, any], any>({
firstPause(); firstPause();
} }
}, },
}): <T>(gen: Generator<*, T, *>, cb: Function) => Handler<T>); }) as <T>(gen: Generator<any, T, any>, cb: Function) => Handler<T>;
// Wait for the given promise to be resolved // Wait for the given promise to be resolved
export const waitFor = (gensync<[any], any>({ export const waitFor = gensync({
sync: id, sync: id,
async: id, async: id,
}): <T>(p: T | Promise<T>) => Handler<T>); }) as <T>(p: T | Promise<T>) => Handler<T>;
export function isThenable(val: mixed): boolean %checks { export function isThenable<T = any>(val: any): val is PromiseLike<T> {
return ( return (
/*:: val instanceof Promise && */
!!val && !!val &&
(typeof val === "object" || typeof val === "function") && (typeof val === "object" || typeof val === "function") &&
!!val.then && !!val.then &&

View File

@ -1,14 +1,14 @@
// @flow
import fs from "fs"; import fs from "fs";
import gensync from "gensync"; import gensync from "gensync";
export const readFile = gensync<[string, "utf8"], string>({ export const readFile = gensync<(filepath: string, encoding: "utf8") => string>(
sync: fs.readFileSync, {
errback: fs.readFile, sync: fs.readFileSync,
}); errback: fs.readFile,
},
);
export const exists = gensync<[string], boolean>({ export const exists = gensync<(filepath: string) => boolean>({
sync(path) { sync(path) {
try { try {
fs.accessSync(path); fs.accessSync(path);
@ -20,7 +20,7 @@ export const exists = gensync<[string], boolean>({
errback: (path, cb) => fs.access(path, undefined, err => cb(null, !err)), errback: (path, cb) => fs.access(path, undefined, err => cb(null, !err)),
}); });
export const stat = gensync<[string], *>({ export const stat = gensync<typeof fs.statSync>({
sync: fs.statSync, sync: fs.statSync,
errback: fs.stat, errback: fs.stat,
}); });

View File

@ -0,0 +1,37 @@
declare module "gensync" {
declare type Next = undefined | Function;
declare type Yield = mixed;
declare type Callback<Return> =
| ((err: Error, val: Return) => void)
| ((err: unknown) => void);
export type Gensync<Fn extends (...args: any) => any> = {
(...args: Parameters<Fn>): Handler<ReturnType<Fn>>;
sync(...args: Parameters<Fn>): ReturnType<Fn>;
async(...args: Parameters<Fn>): Promise<ReturnType<Fn>>;
errback(...args: [...Parameters<Fn>, Callback<ReturnType<Fn>>]): void;
};
export type Handler<Return> = Generator<Yield, Return, Next>;
export type Options<Fn extends (...args: any) => any> = {
sync(...args: Parameters<Fn>): ReturnType<Fn>;
arity?: number;
name?: string;
} & (
| { async?: (...args: Parameters<Fn>) => Promise<ReturnType<Fn>> }
| {
errback(...args: [...Parameters<Fn>, Callback<ReturnType<Fn>>]): void;
}
);
declare const gensync: {
<Fn extends (...args: any) => any>(
_: Options<Fn> | ((...args: Parameters<Fn>) => Handler<ReturnType<Fn>>),
): Gensync<Fn>;
all<Return>(gensyncs: Array<Handler<Return>>): Handler<Return[]>;
race<Return>(gensyncs: Array<Handler<Return>>): Handler<Return>;
};
export default gensync;
}

View File

@ -1,5 +1,4 @@
// @flow declare const PACKAGE_JSON: { name: string; version: string };
export const version = PACKAGE_JSON.version; export const version = PACKAGE_JSON.version;
export { default as File } from "./transformation/file/file"; export { default as File } from "./transformation/file/file";
@ -53,7 +52,7 @@ export const DEFAULT_EXTENSIONS = Object.freeze([
".es", ".es",
".mjs", ".mjs",
".cjs", ".cjs",
]); ] as const);
// For easier backward-compatibility, provide an API like the one we exposed in Babel 6. // For easier backward-compatibility, provide an API like the one we exposed in Babel 6.
import { loadOptions } from "./config"; import { loadOptions } from "./config";

View File

@ -1,39 +1,39 @@
// @flow
import gensync from "gensync"; import gensync from "gensync";
import loadConfig, { type InputOptions } from "./config"; import loadConfig from "./config";
import type { InputOptions } from "./config";
import parser from "./parser"; import parser from "./parser";
import type { ParseResult } from "./parser"; import type { ParseResult } from "./parser";
import normalizeOptions from "./transformation/normalize-opts"; import normalizeOptions from "./transformation/normalize-opts";
type FileParseCallback = { type FileParseCallback = {
(Error, null): any, (err: Error, ast: null): any;
(null, ParseResult | null): any, (err: null, ast: ParseResult | null): any;
}; };
type Parse = { type Parse = {
(code: string, callback: FileParseCallback): void, (code: string, callback: FileParseCallback): void;
(code: string, opts: ?InputOptions, callback: FileParseCallback): void, (
code: string,
// Here for backward-compatibility. Ideally use ".parseSync" if you want opts: InputOptions | undefined | null,
// a synchronous API. callback: FileParseCallback,
(code: string, opts: ?InputOptions): ParseResult | null, ): void;
(code: string, opts?: InputOptions | null): ParseResult | null;
}; };
const parseRunner = gensync<[string, ?InputOptions], ParseResult | null>( const parseRunner = gensync<
function* parse(code, opts) { (code: string, opts: InputOptions | undefined | null) => ParseResult | null
const config = yield* loadConfig(opts); >(function* parse(code, opts) {
const config = yield* loadConfig(opts);
if (config === null) { if (config === null) {
return null; return null;
} }
return yield* parser(config.passes, normalizeOptions(config), code); return yield* parser(config.passes, normalizeOptions(config), code);
}, });
);
export const parse: Parse = (function parse(code, opts, callback) { export const parse: Parse = function parse(code, opts?, callback?) {
if (typeof opts === "function") { if (typeof opts === "function") {
callback = opts; callback = opts;
opts = undefined; opts = undefined;
@ -44,7 +44,7 @@ export const parse: Parse = (function parse(code, opts, callback) {
if (callback === undefined) return parseRunner.sync(code, opts); if (callback === undefined) return parseRunner.sync(code, opts);
parseRunner.errback(code, opts, callback); parseRunner.errback(code, opts, callback);
}: Function); };
export const parseSync = parseRunner.sync; export const parseSync = parseRunner.sync;
export const parseAsync = parseRunner.async; export const parseAsync = parseRunner.async;

View File

@ -1,15 +1,17 @@
import type { Handler } from "gensync"; import type { Handler } from "gensync";
import { parse } from "@babel/parser"; import { parse } from "@babel/parser";
import type * as t from "@babel/types";
import { codeFrameColumns } from "@babel/code-frame"; import { codeFrameColumns } from "@babel/code-frame";
import generateMissingPluginMessage from "./util/missing-plugin-helper"; import generateMissingPluginMessage from "./util/missing-plugin-helper";
import type { PluginPasses } from "../config";
type AstRoot = BabelNodeFile | BabelNodeProgram; type AstRoot = t.File | t.Program;
export type ParseResult = AstRoot; export type ParseResult = AstRoot;
export default function* parser( export default function* parser(
pluginPasses: PluginPasses, pluginPasses: PluginPasses,
{ parserOpts, highlightCode = true, filename = "unknown" }: Object, { parserOpts, highlightCode = true, filename = "unknown" }: any,
code: string, code: string,
): Handler<ParseResult> { ): Handler<ParseResult> {
try { try {
@ -28,7 +30,8 @@ export default function* parser(
if (results.length === 0) { if (results.length === 0) {
return parse(code, parserOpts); return parse(code, parserOpts);
} else if (results.length === 1) { } else if (results.length === 1) {
yield* []; // If we want to allow async parsers // @ts-expect-error - If we want to allow async parsers
yield* [];
if (typeof results[0].then === "function") { if (typeof results[0].then === "function") {
throw new Error( throw new Error(
`You appear to be using an async parser plugin, ` + `You appear to be using an async parser plugin, ` +

View File

@ -1,5 +1,3 @@
// @flow
const pluginNameMap = { const pluginNameMap = {
classProperties: { classProperties: {
syntax: { syntax: {
@ -290,7 +288,10 @@ to enable [parsing|transformation].
*/ */
export default function generateMissingPluginMessage( export default function generateMissingPluginMessage(
missingPluginName: string, missingPluginName: string,
loc: { line: number, column: number }, loc: {
line: number;
column: number;
},
codeFrame: string, codeFrame: string,
): string { ): string {
let helpMessage = let helpMessage =

View File

@ -105,7 +105,7 @@ function buildUmd(allowlist) {
AMD_ARGUMENTS: t.arrayExpression([t.stringLiteral("exports")]), AMD_ARGUMENTS: t.arrayExpression([t.stringLiteral("exports")]),
FACTORY_BODY: body, FACTORY_BODY: body,
UMD_ROOT: t.identifier("this"), UMD_ROOT: t.identifier("this"),
}), }) as t.Statement,
]); ]);
} }

View File

@ -1,33 +1,30 @@
// @flow
import gensync from "gensync"; import gensync from "gensync";
import loadConfig, { type InputOptions, type ResolvedConfig } from "./config"; import loadConfig from "./config";
import { import type { InputOptions, ResolvedConfig } from "./config";
run, import { run } from "./transformation";
type FileResult, import type * as t from "@babel/types";
type FileResultCallback,
} from "./transformation";
type AstRoot = BabelNodeFile | BabelNodeProgram; import type { FileResult, FileResultCallback } from "./transformation";
type AstRoot = t.File | t.Program;
type TransformFromAst = { type TransformFromAst = {
(ast: AstRoot, code: string, callback: FileResultCallback): void, (ast: AstRoot, code: string, callback: FileResultCallback): void;
( (
ast: AstRoot, ast: AstRoot,
code: string, code: string,
opts: ?InputOptions, opts: InputOptions | undefined | null,
callback: FileResultCallback, callback: FileResultCallback,
): void, ): void;
(ast: AstRoot, code: string, opts?: InputOptions | null): FileResult | null;
// Here for backward-compatibility. Ideally use ".transformSync" if you want
// a synchronous API.
(ast: AstRoot, code: string, opts: ?InputOptions): FileResult | null,
}; };
const transformFromAstRunner = gensync< const transformFromAstRunner = gensync<
[AstRoot, string, ?InputOptions], (
FileResult | null, ast: AstRoot,
code: string,
opts: InputOptions | undefined | null,
) => FileResult | null
>(function* (ast, code, opts) { >(function* (ast, code, opts) {
const config: ResolvedConfig | null = yield* loadConfig(opts); const config: ResolvedConfig | null = yield* loadConfig(opts);
if (config === null) return null; if (config === null) return null;
@ -37,11 +34,11 @@ const transformFromAstRunner = gensync<
return yield* run(config, code, ast); return yield* run(config, code, ast);
}); });
export const transformFromAst: TransformFromAst = (function transformFromAst( export const transformFromAst: TransformFromAst = function transformFromAst(
ast, ast,
code, code,
opts, opts,
callback, callback?,
) { ) {
if (typeof opts === "function") { if (typeof opts === "function") {
callback = opts; callback = opts;
@ -55,7 +52,7 @@ export const transformFromAst: TransformFromAst = (function transformFromAst(
} }
transformFromAstRunner.errback(ast, code, opts, callback); transformFromAstRunner.errback(ast, code, opts, callback);
}: Function); };
export const transformFromAstSync = transformFromAstRunner.sync; export const transformFromAstSync = transformFromAstRunner.sync;
export const transformFromAstAsync = transformFromAstRunner.async; export const transformFromAstAsync = transformFromAstRunner.async;

View File

@ -1,24 +1,22 @@
// @flow
// duplicated from transform-file so we do not have to import anything here // duplicated from transform-file so we do not have to import anything here
type TransformFile = { type TransformFile = {
(filename: string, callback: Function): void, (filename: string, callback: Function): void;
(filename: string, opts: ?Object, callback: Function): void, (filename: string, opts: any, callback: Function): void;
}; };
export const transformFile: TransformFile = (function transformFile( export const transformFile: TransformFile = function transformFile(
filename, filename,
opts, opts,
callback, callback?,
) { ) {
if (typeof opts === "function") { if (typeof opts === "function") {
callback = opts; callback = opts;
} }
callback(new Error("Transforming files is not supported in browsers"), null); callback(new Error("Transforming files is not supported in browsers"), null);
}: Function); };
export function transformFileSync() { export function transformFileSync(): never {
throw new Error("Transforming files is not supported in browsers"); throw new Error("Transforming files is not supported in browsers");
} }

View File

@ -1,40 +1,40 @@
// @flow
import gensync from "gensync"; import gensync from "gensync";
import loadConfig, { type InputOptions, type ResolvedConfig } from "./config"; import loadConfig from "./config";
import { import type { InputOptions, ResolvedConfig } from "./config";
run, import { run } from "./transformation";
type FileResult, import type { FileResult, FileResultCallback } from "./transformation";
type FileResultCallback,
} from "./transformation";
import * as fs from "./gensync-utils/fs"; import * as fs from "./gensync-utils/fs";
import typeof * as transformFileBrowserType from "./transform-file-browser"; type transformFileBrowserType = typeof import("./transform-file-browser");
import typeof * as transformFileType from "./transform-file"; type transformFileType = typeof import("./transform-file");
// Kind of gross, but essentially asserting that the exports of this module are the same as the // Kind of gross, but essentially asserting that the exports of this module are the same as the
// exports of transform-file-browser, since this file may be replaced at bundle time with // exports of transform-file-browser, since this file may be replaced at bundle time with
// transform-file-browser. // transform-file-browser.
((({}: any): $Exact<transformFileBrowserType>): $Exact<transformFileType>); ((({} as any) as transformFileBrowserType) as transformFileType);
type TransformFile = { type TransformFile = {
(filename: string, callback: FileResultCallback): void, (filename: string, callback: FileResultCallback): void;
(filename: string, opts: ?InputOptions, callback: FileResultCallback): void, (
filename: string,
opts: InputOptions | undefined | null,
callback: FileResultCallback,
): void;
}; };
const transformFileRunner = gensync<[string, ?InputOptions], FileResult | null>( const transformFileRunner = gensync<
function* (filename, opts) { (filename: string, opts?: InputOptions) => FileResult | null
const options = { ...opts, filename }; >(function* (filename, opts: InputOptions) {
const options = { ...opts, filename };
const config: ResolvedConfig | null = yield* loadConfig(options); const config: ResolvedConfig | null = yield* loadConfig(options);
if (config === null) return null; if (config === null) return null;
const code = yield* fs.readFile(filename, "utf8"); const code = yield* fs.readFile(filename, "utf8");
return yield* run(config, code); return yield* run(config, code);
}, });
);
export const transformFile: TransformFile = transformFileRunner.errback; export const transformFile = transformFileRunner.errback as TransformFile;
export const transformFileSync = transformFileRunner.sync; export const transformFileSync = transformFileRunner.sync;
export const transformFileAsync = transformFileRunner.async; export const transformFileAsync = transformFileRunner.async;

View File

@ -1,33 +1,31 @@
// @flow
import gensync from "gensync"; import gensync from "gensync";
import loadConfig, { type InputOptions, type ResolvedConfig } from "./config"; import loadConfig from "./config";
import { import type { InputOptions, ResolvedConfig } from "./config";
run, import { run } from "./transformation";
type FileResult,
type FileResultCallback, import type { FileResult, FileResultCallback } from "./transformation";
} from "./transformation";
type Transform = { type Transform = {
(code: string, callback: FileResultCallback): void, (code: string, callback: FileResultCallback): void;
(code: string, opts: ?InputOptions, callback: FileResultCallback): void, (
code: string,
// Here for backward-compatibility. Ideally use ".transformSync" if you want opts: InputOptions | undefined | null,
// a synchronous API. callback: FileResultCallback,
(code: string, opts: ?InputOptions): FileResult | null, ): void;
(code: string, opts?: InputOptions | null): FileResult | null;
}; };
const transformRunner = gensync<[string, ?InputOptions], FileResult | null>( const transformRunner = gensync<
function* transform(code, opts) { (code: string, opts?: InputOptions) => FileResult | null
const config: ResolvedConfig | null = yield* loadConfig(opts); >(function* transform(code, opts) {
if (config === null) return null; const config: ResolvedConfig | null = yield* loadConfig(opts);
if (config === null) return null;
return yield* run(config, code); return yield* run(config, code);
}, });
);
export const transform: Transform = (function transform(code, opts, callback) { export const transform: Transform = function transform(code, opts?, callback?) {
if (typeof opts === "function") { if (typeof opts === "function") {
callback = opts; callback = opts;
opts = undefined; opts = undefined;
@ -38,7 +36,7 @@ export const transform: Transform = (function transform(code, opts, callback) {
if (callback === undefined) return transformRunner.sync(code, opts); if (callback === undefined) return transformRunner.sync(code, opts);
transformRunner.errback(code, opts, callback); transformRunner.errback(code, opts, callback);
}: Function); };
export const transformSync = transformRunner.sync; export const transformSync = transformRunner.sync;
export const transformAsync = transformRunner.async; export const transformAsync = transformRunner.async;

View File

@ -1,6 +1,6 @@
// @flow import loadConfig from "../config";
import loadConfig, { type Plugin } from "../config"; import type { Plugin } from "../config";
let LOADED_PLUGIN: Plugin | void; let LOADED_PLUGIN: Plugin | void;

View File

@ -1,7 +1,6 @@
// @flow
import * as helpers from "@babel/helpers"; import * as helpers from "@babel/helpers";
import { NodePath, Scope, type HubInterface } from "@babel/traverse"; import { NodePath, Scope } from "@babel/traverse";
import type { HubInterface } from "@babel/traverse";
import { codeFrameColumns } from "@babel/code-frame"; import { codeFrameColumns } from "@babel/code-frame";
import traverse from "@babel/traverse"; import traverse from "@babel/traverse";
import * as t from "@babel/types"; import * as t from "@babel/types";
@ -22,27 +21,39 @@ const errorVisitor = {
export type NodeLocation = { export type NodeLocation = {
loc?: { loc?: {
end?: { line: number, column: number }, end?: {
start: { line: number, column: number }, line: number;
}, column: number;
};
start: {
line: number;
column: number;
};
};
_loc?: { _loc?: {
end?: { line: number, column: number }, end?: {
start: { line: number, column: number }, line: number;
}, column: number;
};
start: {
line: number;
column: number;
};
};
}; };
export default class File { export default class File {
_map: Map<any, any> = new Map(); _map: Map<any, any> = new Map();
opts: Object; opts: any;
declarations: Object = {}; declarations: any = {};
path: NodePath = null; path: NodePath<t.Program> = null;
ast: Object = {}; ast: any = {};
scope: Scope; scope: Scope;
metadata: {} = {}; metadata: {} = {};
code: string = ""; code: string = "";
inputMap: Object | null = null; inputMap: any | null = null;
hub: HubInterface = { hub: HubInterface & { file: File } = {
// keep it for the usage in babel-core, ex: path.hub.file.opts.filename // keep it for the usage in babel-core, ex: path.hub.file.opts.filename
file: this, file: this,
getCode: () => this.code, getCode: () => this.code,
@ -63,7 +74,7 @@ export default class File {
parent: this.ast, parent: this.ast,
container: this.ast, container: this.ast,
key: "program", key: "program",
}).setContext(); }).setContext() as NodePath<t.Program>;
this.scope = this.path.scope; this.scope = this.path.scope;
} }
@ -76,7 +87,7 @@ export default class File {
const { interpreter } = this.path.node; const { interpreter } = this.path.node;
return interpreter ? interpreter.value : ""; return interpreter ? interpreter.value : "";
} }
set shebang(value: string): void { set shebang(value: string) {
if (value) { if (value) {
this.path.get("interpreter").replaceWith(t.interpreterDirective(value)); this.path.get("interpreter").replaceWith(t.interpreterDirective(value));
} else { } else {
@ -84,7 +95,7 @@ export default class File {
} }
} }
set(key: mixed, val: mixed) { set(key: unknown, val: unknown) {
if (key === "helpersNamespace") { if (key === "helpersNamespace") {
throw new Error( throw new Error(
"Babel 7.0.0-beta.56 has dropped support for the 'helpersNamespace' utility." + "Babel 7.0.0-beta.56 has dropped support for the 'helpersNamespace' utility." +
@ -98,15 +109,15 @@ export default class File {
this._map.set(key, val); this._map.set(key, val);
} }
get(key: mixed): any { get(key: unknown): any {
return this._map.get(key); return this._map.get(key);
} }
has(key: mixed): boolean { has(key: unknown): boolean {
return this._map.has(key); return this._map.has(key);
} }
getModuleName(): ?string { getModuleName(): string | undefined | null {
return getModuleName(this.opts, this.opts); return getModuleName(this.opts, this.opts);
} }
@ -126,7 +137,7 @@ export default class File {
* helper exists, but was not available for the full given range, it will be * helper exists, but was not available for the full given range, it will be
* considered unavailable. * considered unavailable.
*/ */
availableHelper(name: string, versionRange: ?string): boolean { availableHelper(name: string, versionRange?: string | null): boolean {
let minVersion; let minVersion;
try { try {
minVersion = helpers.minVersion(name); minVersion = helpers.minVersion(name);
@ -163,7 +174,7 @@ export default class File {
); );
} }
addHelper(name: string): Object { addHelper(name: string): any {
const declar = this.declarations[name]; const declar = this.declarations[name];
if (declar) return t.cloneNode(declar); if (declar) return t.cloneNode(declar);
@ -220,9 +231,9 @@ export default class File {
} }
buildCodeFrameError( buildCodeFrameError(
node: ?NodeLocation, node: NodeLocation | undefined | null,
msg: string, msg: string,
Error: typeof Error = SyntaxError, _Error: typeof Error = SyntaxError,
): Error { ): Error {
let loc = node && (node.loc || node._loc); let loc = node && (node.loc || node._loc);
@ -230,7 +241,7 @@ export default class File {
const state = { const state = {
loc: null, loc: null,
}; };
traverse(node, errorVisitor, this.scope, state); traverse(node as t.Node, errorVisitor, this.scope, state);
loc = state.loc; loc = state.loc;
let txt = let txt =
@ -264,6 +275,6 @@ export default class File {
); );
} }
return new Error(msg); return new _Error(msg);
} }
} }

View File

@ -1,7 +1,6 @@
// @flow
import type { PluginPasses } from "../../config"; import type { PluginPasses } from "../../config";
import convertSourceMap, { typeof SourceMap } from "convert-source-map"; import convertSourceMap from "convert-source-map";
type SourceMap = any;
import generate from "@babel/generator"; import generate from "@babel/generator";
import type File from "./file"; import type File from "./file";
@ -11,8 +10,8 @@ export default function generateCode(
pluginPasses: PluginPasses, pluginPasses: PluginPasses,
file: File, file: File,
): { ): {
outputCode: string, outputCode: string;
outputMap: SourceMap | null, outputMap: SourceMap | null;
} { } {
const { opts, ast, code, inputMap } = file; const { opts, ast, code, inputMap } = file;

View File

@ -1,6 +1,4 @@
// @flow type SourceMap = any;
import typeof { SourceMap } from "convert-source-map";
import sourceMap from "source-map"; import sourceMap from "source-map";
export default function mergeSourceMap( export default function mergeSourceMap(
@ -74,6 +72,7 @@ export default function mergeSourceMap(
// Insert mappings with no original position to terminate any mappings // Insert mappings with no original position to terminate any mappings
// that were found above, so that they don't expand beyond their correct // that were found above, so that they don't expand beyond their correct
// range. // range.
// @ts-expect-error todo(flow->ts) original and source field are missing
mergedGenerator.addMapping({ mergedGenerator.addMapping({
generated: { generated: {
line: clearItem.line, line: clearItem.line,
@ -93,14 +92,14 @@ export default function mergeSourceMap(
return result; return result;
} }
function makeMappingKey(item: { line: number, columnStart: number }) { function makeMappingKey(item: { line: number; columnStart: number }) {
return `${item.line}/${item.columnStart}`; return `${item.line}/${item.columnStart}`;
} }
function eachOverlappingGeneratedOutputRange( function eachOverlappingGeneratedOutputRange(
outputFile: ResolvedFileMappings, outputFile: ResolvedFileMappings,
inputGeneratedRange: ResolvedGeneratedRange, inputGeneratedRange: ResolvedGeneratedRange,
callback: ResolvedGeneratedRange => mixed, callback: (range: ResolvedGeneratedRange) => unknown,
) { ) {
// Find the Babel-generated mappings that overlap with this range in the // Find the Babel-generated mappings that overlap with this range in the
// input sourcemap. Generated locations within the input sourcemap // input sourcemap. Generated locations within the input sourcemap
@ -137,10 +136,10 @@ function filterApplicableOriginalRanges(
function eachInputGeneratedRange( function eachInputGeneratedRange(
map: ResolvedMappings, map: ResolvedMappings,
callback: ( callback: (
ResolvedGeneratedRange, c: ResolvedGeneratedRange,
ResolvedOriginalRange, b: ResolvedOriginalRange,
ResolvedSource, a: ResolvedSource,
) => mixed, ) => unknown,
) { ) {
for (const { source, mappings } of map.sources) { for (const { source, mappings } of map.sources) {
for (const { original, generated } of mappings) { for (const { original, generated } of mappings) {
@ -151,34 +150,39 @@ function eachInputGeneratedRange(
} }
} }
type ResolvedMappings = {| type ResolvedMappings = {
file: ?string, file: string | undefined | null;
sourceRoot: ?string, sourceRoot: string | undefined | null;
sources: Array<ResolvedFileMappings>, sources: Array<ResolvedFileMappings>;
|}; };
type ResolvedFileMappings = {|
source: ResolvedSource, type ResolvedFileMappings = {
mappings: OriginalMappings, source: ResolvedSource;
|}; mappings: OriginalMappings;
type OriginalMappings = Array<{| };
original: ResolvedOriginalRange,
generated: Array<ResolvedGeneratedRange>, type OriginalMappings = Array<{
|}>; original: ResolvedOriginalRange;
type ResolvedSource = {| generated: Array<ResolvedGeneratedRange>;
path: string, }>;
content: string | null,
|}; type ResolvedSource = {
type ResolvedOriginalRange = {| path: string;
line: number, content: string | null;
columnStart: number, };
columnEnd: number,
name: string | null, type ResolvedOriginalRange = {
|}; line: number;
type ResolvedGeneratedRange = {| columnStart: number;
line: number, columnEnd: number;
columnStart: number, name: string | null;
columnEnd: number, };
|};
type ResolvedGeneratedRange = {
line: number;
columnStart: number;
columnEnd: number;
};
function buildMappingData(map: SourceMap): ResolvedMappings { function buildMappingData(map: SourceMap): ResolvedMappings {
const consumer = new sourceMap.SourceMapConsumer({ const consumer = new sourceMap.SourceMapConsumer({
@ -270,7 +274,7 @@ function buildMappingData(map: SourceMap): ResolvedMappings {
function findInsertionLocation<T>( function findInsertionLocation<T>(
array: Array<T>, array: Array<T>,
callback: T => number, callback: (item: T) => number,
): number { ): number {
let left = 0; let left = 0;
let right = array.length; let right = array.length;
@ -304,7 +308,7 @@ function findInsertionLocation<T>(
function filterSortedArray<T>( function filterSortedArray<T>(
array: Array<T>, array: Array<T>,
callback: T => number, callback: (item: T) => number,
): Array<T> { ): Array<T> {
const start = findInsertionLocation(array, callback); const start = findInsertionLocation(array, callback);

View File

@ -1,6 +1,6 @@
// @flow
import traverse from "@babel/traverse"; import traverse from "@babel/traverse";
import typeof { SourceMap } from "convert-source-map"; import type * as t from "@babel/types";
type SourceMap = any;
import type { Handler } from "gensync"; import type { Handler } from "gensync";
import type { ResolvedConfig, PluginPasses } from "../config"; import type { ResolvedConfig, PluginPasses } from "../config";
@ -14,22 +14,23 @@ import generateCode from "./file/generate";
import type File from "./file/file"; import type File from "./file/file";
export type FileResultCallback = { export type FileResultCallback = {
(Error, null): any, (err: Error, file: null): any;
(null, FileResult | null): any, (err: null, file: FileResult | null): any;
}; };
export type FileResult = { export type FileResult = {
metadata: {}, metadata: {};
options: {}, options: {};
ast: {} | null, ast: {} | null;
code: string | null, code: string | null;
map: SourceMap | null, map: SourceMap | null;
sourceType: "string" | "module";
}; };
export function* run( export function* run(
config: ResolvedConfig, config: ResolvedConfig,
code: string, code: string,
ast: ?(BabelNodeFile | BabelNodeProgram), ast?: t.File | t.Program | null,
): Handler<FileResult> { ): Handler<FileResult> {
const file = yield* normalizeFile( const file = yield* normalizeFile(
config.passes, config.passes,
@ -91,7 +92,9 @@ function* transformFile(file: File, pluginPasses: PluginPasses): Handler<void> {
if (fn) { if (fn) {
const result = fn.call(pass, file); const result = fn.call(pass, file);
// @ts-expect-error - If we want to support async .pre
yield* []; yield* [];
if (isThenable(result)) { if (isThenable(result)) {
throw new Error( throw new Error(
`You appear to be using an plugin with an async .pre, ` + `You appear to be using an plugin with an async .pre, ` +
@ -116,7 +119,9 @@ function* transformFile(file: File, pluginPasses: PluginPasses): Handler<void> {
if (fn) { if (fn) {
const result = fn.call(pass, file); const result = fn.call(pass, file);
// @ts-expect-error - If we want to support async .post
yield* []; yield* [];
if (isThenable(result)) { if (isThenable(result)) {
throw new Error( throw new Error(
`You appear to be using an plugin with an async .post, ` + `You appear to be using an plugin with an async .post, ` +
@ -130,7 +135,7 @@ function* transformFile(file: File, pluginPasses: PluginPasses): Handler<void> {
} }
} }
function isThenable(val: mixed): boolean { function isThenable<T extends PromiseLike<any>>(val: any): val is T {
return ( return (
!!val && !!val &&
(typeof val === "object" || typeof val === "function") && (typeof val === "object" || typeof val === "function") &&

View File

@ -1,12 +1,11 @@
// @flow
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import buildDebug from "debug"; import buildDebug from "debug";
import type { Handler } from "gensync"; import type { Handler } from "gensync";
import * as t from "@babel/types"; import * as t from "@babel/types";
import type { PluginPasses } from "../config"; import type { PluginPasses } from "../config";
import convertSourceMap, { typeof Converter } from "convert-source-map"; import convertSourceMap from "convert-source-map";
import type { SourceMapConverter as Converter } from "convert-source-map";
import File from "./file/file"; import File from "./file/file";
import parser from "../parser"; import parser from "../parser";
import cloneDeep from "./util/clone-deep"; import cloneDeep from "./util/clone-deep";
@ -15,16 +14,16 @@ const debug = buildDebug("babel:transform:file");
const LARGE_INPUT_SOURCEMAP_THRESHOLD = 1_000_000; const LARGE_INPUT_SOURCEMAP_THRESHOLD = 1_000_000;
export type NormalizedFile = { export type NormalizedFile = {
code: string, code: string;
ast: {}, ast: {};
inputMap: Converter | null, inputMap: Converter | null;
}; };
export default function* normalizeFile( export default function* normalizeFile(
pluginPasses: PluginPasses, pluginPasses: PluginPasses,
options: Object, options: any,
code: string, code: string,
ast: ?(BabelNodeFile | BabelNodeProgram), ast?: t.File | t.Program | null,
): Handler<File> { ): Handler<File> {
code = `${code || ""}`; code = `${code || ""}`;
@ -66,16 +65,19 @@ export default function* normalizeFile(
if (typeof options.filename === "string" && lastComment) { if (typeof options.filename === "string" && lastComment) {
try { try {
// when `lastComment` is non-null, EXTERNAL_SOURCEMAP_REGEX must have matches // when `lastComment` is non-null, EXTERNAL_SOURCEMAP_REGEX must have matches
const match: [string, string] = (EXTERNAL_SOURCEMAP_REGEX.exec( const match: [string, string] = EXTERNAL_SOURCEMAP_REGEX.exec(
lastComment, lastComment,
): any); ) as any;
const inputMapContent: Buffer = fs.readFileSync( const inputMapContent = fs.readFileSync(
path.resolve(path.dirname(options.filename), match[1]), path.resolve(path.dirname(options.filename), match[1]),
); );
if (inputMapContent.length > LARGE_INPUT_SOURCEMAP_THRESHOLD) { if (inputMapContent.length > LARGE_INPUT_SOURCEMAP_THRESHOLD) {
debug("skip merging input map > 1 MB"); debug("skip merging input map > 1 MB");
} else { } else {
inputMap = convertSourceMap.fromJSON(inputMapContent); inputMap = convertSourceMap.fromJSON(
// todo:
(inputMapContent as unknown) as string,
);
} }
} catch (err) { } catch (err) {
debug("discarding unknown file input sourcemap", err); debug("discarding unknown file input sourcemap", err);
@ -116,19 +118,16 @@ function extractCommentsFromList(regex, comments, lastComment) {
function extractComments(regex, ast) { function extractComments(regex, ast) {
let lastComment = null; let lastComment = null;
t.traverseFast(ast, node => { t.traverseFast(ast, node => {
// $FlowIgnore destructuring with expressions is not supported
[node.leadingComments, lastComment] = extractCommentsFromList( [node.leadingComments, lastComment] = extractCommentsFromList(
regex, regex,
node.leadingComments, node.leadingComments,
lastComment, lastComment,
); );
// $FlowIgnore destructuring with expressions is not supported
[node.innerComments, lastComment] = extractCommentsFromList( [node.innerComments, lastComment] = extractCommentsFromList(
regex, regex,
node.innerComments, node.innerComments,
lastComment, lastComment,
); );
// $FlowIgnore destructuring with expressions is not supported
[node.trailingComments, lastComment] = extractCommentsFromList( [node.trailingComments, lastComment] = extractCommentsFromList(
regex, regex,
node.trailingComments, node.trailingComments,

View File

@ -1,5 +1,3 @@
// @flow
import path from "path"; import path from "path";
import type { ResolvedConfig } from "../config"; import type { ResolvedConfig } from "../config";

View File

@ -1,13 +1,11 @@
// @flow
import type File from "./file/file"; import type File from "./file/file";
import type NodeLocation from "./file/file"; import type { NodeLocation } from "./file/file";
export default class PluginPass { export default class PluginPass {
_map: Map<mixed, mixed> = new Map(); _map: Map<unknown, unknown> = new Map();
key: ?string; key: string | undefined | null;
file: File; file: File;
opts: Object; opts: any;
// The working directory that Babel's programmatic options are loaded // The working directory that Babel's programmatic options are loaded
// relative to. // relative to.
@ -16,7 +14,7 @@ export default class PluginPass {
// The absolute path of the file being compiled. // The absolute path of the file being compiled.
filename: string | void; filename: string | void;
constructor(file: File, key: ?string, options: ?Object) { constructor(file: File, key?: string | null, options?: any | null) {
this.key = key; this.key = key;
this.file = file; this.file = file;
this.opts = options || {}; this.opts = options || {};
@ -24,15 +22,15 @@ export default class PluginPass {
this.filename = file.opts.filename; this.filename = file.opts.filename;
} }
set(key: mixed, val: mixed) { set(key: unknown, val: unknown) {
this._map.set(key, val); this._map.set(key, val);
} }
get(key: mixed): any { get(key: unknown): any {
return this._map.get(key); return this._map.get(key);
} }
availableHelper(name: string, versionRange: ?string) { availableHelper(name: string, versionRange?: string | null) {
return this.file.availableHelper(name, versionRange); return this.file.availableHelper(name, versionRange);
} }
@ -44,14 +42,19 @@ export default class PluginPass {
return this.file.addImport(); return this.file.addImport();
} }
buildCodeFrameError(node: ?NodeLocation, msg: string, Error?: typeof Error) { buildCodeFrameError(
return this.file.buildCodeFrameError(node, msg, Error); node: NodeLocation | undefined | null,
msg: string,
_Error?: typeof Error,
) {
return this.file.buildCodeFrameError(node, msg, _Error);
} }
} }
if (!process.env.BABEL_8_BREAKING) { if (!process.env.BABEL_8_BREAKING) {
// $FlowIgnore (PluginPass as any).prototype.getModuleName = function getModuleName():
PluginPass.prototype.getModuleName = function getModuleName(): ?string { | string
| undefined {
return this.file.getModuleName(); return this.file.getModuleName();
}; };
} }

View File

@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.base.json",
"include": [
"./typings"
],
"references": [
{
"path": "../babel-code-frame"
},
{
"path": "../babel-helper-fixtures"
},
{
"path": "../babel-helper-validator-identifier"
}
]
}

View File

@ -167,3 +167,8 @@ export interface RecordAndTuplePluginOptions {
export interface FlowPluginOptions { export interface FlowPluginOptions {
all?: boolean; all?: boolean;
} }
export const tokTypes: {
// todo(flow->ts) real token type
[name: string]: any;
};

View File

@ -211,6 +211,12 @@ __metadata:
"@babel/template": "workspace:^7.12.13" "@babel/template": "workspace:^7.12.13"
"@babel/traverse": "workspace:^7.13.13" "@babel/traverse": "workspace:^7.13.13"
"@babel/types": "workspace:^7.13.14" "@babel/types": "workspace:^7.13.14"
"@types/convert-source-map": ^1.5.1
"@types/debug": ^4.1.0
"@types/lodash": ^4.14.150
"@types/resolve": ^1.3.2
"@types/semver": ^5.4.0
"@types/source-map": ^0.5.0
convert-source-map: ^1.7.0 convert-source-map: ^1.7.0
debug: ^4.1.0 debug: ^4.1.0
gensync: ^1.0.0-beta.2 gensync: ^1.0.0-beta.2
@ -659,6 +665,7 @@ __metadata:
resolution: "@babel/helper-module-transforms@condition:BABEL_8_BREAKING?:workspace:^7.13.14#f57fb3" resolution: "@babel/helper-module-transforms@condition:BABEL_8_BREAKING?:workspace:^7.13.14#f57fb3"
dependencies: dependencies:
"@babel/helper-module-transforms-BABEL_8_BREAKING-false": "npm:@babel/helper-module-transforms@workspace:^7.13.14" "@babel/helper-module-transforms-BABEL_8_BREAKING-false": "npm:@babel/helper-module-transforms@workspace:^7.13.14"
checksum: 82d133091e69e2b2c742cfeb03c3f9acb3d0a00391d3ab2624154aa537dc714eedc5d8145c6c671bacd63d5314de09982a36b216b520c22466e4af3e375aff2d
languageName: node languageName: node
linkType: hard linkType: hard
@ -3992,6 +3999,20 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/convert-source-map@npm:^1.5.1":
version: 1.5.1
resolution: "@types/convert-source-map@npm:1.5.1"
checksum: 36cd50ea42b5e5c41db2415e4f42bdbc426e6b963a7d0d0a511164b789d4140629fbc0b3c5a29306ad3731ab41708088bb63e95972060cd3983af1f22b33f414
languageName: node
linkType: hard
"@types/debug@npm:^4.1.0":
version: 4.1.5
resolution: "@types/debug@npm:4.1.5"
checksum: 416ad24bc589be0fb8c78bea972aa7d4ffdf6b136239701b1792674463b2dbf8c6707f6055ec484f79ec1f2b528ffef90c87e55df7e4a0f458184cad5bf0cfc8
languageName: node
linkType: hard
"@types/eslint-scope@npm:^3.7.0": "@types/eslint-scope@npm:^3.7.0":
version: 3.7.0 version: 3.7.0
resolution: "@types/eslint-scope@npm:3.7.0" resolution: "@types/eslint-scope@npm:3.7.0"
@ -4163,6 +4184,20 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/resolve@npm:^1.3.2":
version: 1.20.0
resolution: "@types/resolve@npm:1.20.0"
checksum: 3c75135d5cf3652453ef8f099b109f7fec5e82fe67bf38048226614dbcd11a943affee383e5d28c12c5f03b049281a3e486395326b9810297f9649c7b00f41fd
languageName: node
linkType: hard
"@types/semver@npm:^5.4.0":
version: 5.5.0
resolution: "@types/semver@npm:5.5.0"
checksum: df74589466e171c36dd868b760609e518830f212134c238674ddd6eb83653368c59f4510aa6523b7692ec99c5d8ab40b818e30f9d65e0df97c56bdbacef06661
languageName: node
linkType: hard
"@types/semver@npm:^7.3.4": "@types/semver@npm:^7.3.4":
version: 7.3.4 version: 7.3.4
resolution: "@types/semver@npm:7.3.4" resolution: "@types/semver@npm:7.3.4"