Skip to content

Commit

Permalink
Improve babel-core typings (#14622)
Browse files Browse the repository at this point in the history
Co-authored-by: Nicol貌 Ribaudo <nicolo.ribaudo@gmail.com>
  • Loading branch information
liuxingbaoyu and nicolo-ribaudo committed Jun 11, 2022
1 parent b22e21b commit ac8bb49
Show file tree
Hide file tree
Showing 30 changed files with 243 additions and 127 deletions.
8 changes: 5 additions & 3 deletions packages/babel-core/src/config/caching.ts
Expand Up @@ -348,7 +348,7 @@ class CacheConfigurator<SideChannel = void> {
function makeSimpleConfigurator(
cache: CacheConfigurator<any>,
): SimpleCacheConfigurator {
function cacheFn(val) {
function cacheFn(val: any) {
if (typeof val === "boolean") {
if (val) cache.forever();
else cache.never();
Expand All @@ -359,8 +359,10 @@ function makeSimpleConfigurator(
}
cacheFn.forever = () => cache.forever();
cacheFn.never = () => cache.never();
cacheFn.using = cb => cache.using(() => assertSimpleType(cb()));
cacheFn.invalidate = cb => cache.invalidate(() => assertSimpleType(cb()));
cacheFn.using = (cb: { (): SimpleType }) =>
cache.using(() => assertSimpleType(cb()));
cacheFn.invalidate = (cb: { (): SimpleType }) =>
cache.invalidate(() => assertSimpleType(cb()));

return cacheFn as any;
}
Expand Down
67 changes: 48 additions & 19 deletions packages/babel-core/src/config/config-chain.ts
Expand Up @@ -383,7 +383,12 @@ const loadFileChainWalker = makeChainWalker<ValidatedFile>({
buildFileLogger(file.filepath, context, baseLogger),
});

function* loadFileChain(input, context, files, baseLogger) {
function* loadFileChain(
input: ValidatedFile,
context: ConfigContext,
files: Set<ConfigFile>,
baseLogger: ConfigPrinter,
) {
const chain = yield* loadFileChainWalker(input, context, files, baseLogger);
if (chain) {
chain.files.add(input.filepath);
Expand Down Expand Up @@ -443,11 +448,23 @@ function buildFileLogger(
});
}

function buildRootDescriptors({ dirname, options }, alias, descriptors) {
function buildRootDescriptors(
{ dirname, options }: Partial<ValidatedFile>,
alias: string,
descriptors: (
dirname: string,
options: ValidatedOptions,
alias: string,
) => OptionsAndDescriptors,
) {
return descriptors(dirname, options, alias);
}

function buildProgrammaticLogger(_, context, baseLogger: ConfigPrinter | void) {
function buildProgrammaticLogger(
_: unknown,
context: ConfigContext,
baseLogger: ConfigPrinter | void,
) {
if (!baseLogger) {
return () => {};
}
Expand All @@ -457,20 +474,28 @@ function buildProgrammaticLogger(_, context, baseLogger: ConfigPrinter | void) {
}

function buildEnvDescriptors(
{ dirname, options },
alias,
descriptors,
envName,
{ dirname, options }: Partial<ValidatedFile>,
alias: string,
descriptors: (
dirname: string,
options: ValidatedOptions,
alias: string,
) => OptionsAndDescriptors,
envName: string,
) {
const opts = options.env && options.env[envName];
return opts ? descriptors(dirname, opts, `${alias}.env["${envName}"]`) : null;
}

function buildOverrideDescriptors(
{ dirname, options },
alias,
descriptors,
index,
{ dirname, options }: Partial<ValidatedFile>,
alias: string,
descriptors: (
dirname: string,
options: ValidatedOptions,
alias: string,
) => OptionsAndDescriptors,
index: number,
) {
const opts = options.overrides && options.overrides[index];
if (!opts) throw new Error("Assertion failure - missing override");
Expand All @@ -479,11 +504,15 @@ function buildOverrideDescriptors(
}

function buildOverrideEnvDescriptors(
{ dirname, options },
alias,
descriptors,
index,
envName,
{ dirname, options }: Partial<ValidatedFile>,
alias: string,
descriptors: (
dirname: string,
options: ValidatedOptions,
alias: string,
) => OptionsAndDescriptors,
index: number,
envName: string,
) {
const override = options.overrides && options.overrides[index];
if (!override) throw new Error("Assertion failure - missing override");
Expand Down Expand Up @@ -850,9 +879,9 @@ function matchesPatterns(
}

function matchPattern(
pattern,
dirname,
pathToTest,
pattern: IgnoreItem,
dirname: string,
pathToTest: unknown,
context: ConfigContext,
): boolean {
if (typeof pattern === "function") {
Expand Down
4 changes: 2 additions & 2 deletions packages/babel-core/src/config/config-descriptors.ts
Expand Up @@ -126,8 +126,8 @@ export function createUncachedDescriptors(
// The returned result here is cached to represent a config object in
// memory, so we build and memoize the descriptors to ensure the same
// values are returned consistently.
let plugins;
let presets;
let plugins: UnloadedDescriptor[];
let presets: UnloadedDescriptor[];

return {
options: optionsWithResolvedBrowserslistConfigFile(options, dirname),
Expand Down
6 changes: 5 additions & 1 deletion packages/babel-core/src/config/files/configuration.ts
Expand Up @@ -150,7 +150,11 @@ export function* loadConfig(
* Read the given config file, returning the result. Returns null if no config was found, but will
* throw if there are parsing errors while loading a config.
*/
function readConfig(filepath, envName, caller): Handler<ConfigFile | null> {
function readConfig(
filepath: string,
envName: string,
caller: CallerMetadata | undefined,
): Handler<ConfigFile | null> {
const ext = path.extname(filepath);
return ext === ".js" || ext === ".cjs" || ext === ".mjs"
? readConfigJS(filepath, { envName, caller })
Expand Down
3 changes: 2 additions & 1 deletion packages/babel-core/src/config/files/import-meta-resolve.ts
Expand Up @@ -34,7 +34,8 @@ const importMetaResolveP: Promise<ImportMeta["resolve"]> =
// it throws because it's a module, will fallback to import().
process.execArgv.includes("--experimental-import-meta-resolve")
? import_("data:text/javascript,export default import.meta.resolve").then(
m => m.default || polyfill,
(m: { default: ImportMeta["resolve"] | undefined }) =>
m.default || polyfill,
() => polyfill,
)
: Promise.resolve(polyfill);
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-core/src/config/files/index-browser.ts
Expand Up @@ -72,7 +72,7 @@ export function* resolveShowConfigPath(
return null;
}

export const ROOT_CONFIG_FILENAMES = [];
export const ROOT_CONFIG_FILENAMES: string[] = [];

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function resolvePlugin(name: string, dirname: string): string | null {
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-core/src/config/files/module-types.ts
Expand Up @@ -6,7 +6,7 @@ import { createRequire } from "module";

const require = createRequire(import.meta.url);

let import_;
let import_: ((specifier: string | URL) => any) | undefined;
try {
// Node < 13.3 doesn't support import() syntax.
import_ = require("./import").default;
Expand Down
4 changes: 3 additions & 1 deletion packages/babel-core/src/config/files/types.ts
@@ -1,7 +1,9 @@
import type { InputOptions } from "..";

export type ConfigFile = {
filepath: string;
dirname: string;
options: {};
options: InputOptions & { babel?: unknown };
};

export type IgnoreFile = {
Expand Down
15 changes: 9 additions & 6 deletions packages/babel-core/src/config/full.ts
Expand Up @@ -181,7 +181,7 @@ export default gensync<(inputOpts: unknown) => ResolvedConfig | null>(
pluginDescriptorsByPass[0].unshift(...initialPluginsDescriptors);

for (const descs of pluginDescriptorsByPass) {
const pass = [];
const pass: Plugin[] = [];
passes.push(pass);

for (let i = 0; i < descs.length; i++) {
Expand Down Expand Up @@ -223,8 +223,8 @@ export default gensync<(inputOpts: unknown) => ResolvedConfig | null>(
},
);

function enhanceError<T extends Function>(context, fn: T): T {
return function* (arg1, arg2) {
function enhanceError<T extends Function>(context: ConfigContext, fn: T): T {
return function* (arg1: unknown, arg2: unknown) {
try {
return yield* fn(arg1, arg2);
} catch (e) {
Expand Down Expand Up @@ -376,7 +376,7 @@ const instantiatePlugin = makeWeakCache(function* (
}

if (plugin.inherits) {
const inheritsDescriptor = {
const inheritsDescriptor: UnloadedDescriptor = {
name: undefined,
alias: `${alias}$inherits`,
value: plugin.inherits,
Expand Down Expand Up @@ -490,11 +490,14 @@ const instantiatePreset = makeWeakCacheSync(
},
);

function chain(a, b) {
function chain<Args extends any[]>(
a: undefined | ((...args: Args) => void),
b: undefined | ((...args: Args) => void),
) {
const fns = [a, b].filter(Boolean);
if (fns.length <= 1) return fns[0];

return function (this: unknown, ...args) {
return function (this: unknown, ...args: unknown[]) {
for (const fn of fns) {
fn.apply(this, args);
}
Expand Down
21 changes: 14 additions & 7 deletions packages/babel-core/src/config/helpers/config-api.ts
Expand Up @@ -47,23 +47,29 @@ export type PluginAPI = {
export function makeConfigAPI<SideChannel extends Context.SimpleConfig>(
cache: CacheConfigurator<SideChannel>,
): ConfigAPI {
const env: any = value =>
// TODO(@nicolo-ribaudo): If we remove the explicit type from `value`
// and the `as any` type cast, TypeScript crashes in an infinite
// recursion. After upgrading to TS4.7 and finishing the noImplicitAny
// PR, we should check if it still crashes and report it to the TS team.
const env: EnvFunction = ((
value: string | string[] | (<T>(babelEnv: string) => T),
) =>
cache.using(data => {
if (typeof value === "undefined") return data.envName;
if (typeof value === "function") {
return assertSimpleType(value(data.envName));
}
if (!Array.isArray(value)) value = [value];

return value.some((entry: unknown) => {
return (Array.isArray(value) ? value : [value]).some(entry => {
if (typeof entry !== "string") {
throw new Error("Unexpected non-string value");
}
return entry === data.envName;
});
});
})) as any;

const caller = cb => cache.using(data => assertSimpleType(cb(data.caller)));
const caller = (cb: {
(CallerMetadata: CallerMetadata | undefined): SimpleType;
}) => cache.using(data => assertSimpleType(cb(data.caller)));

return {
version: coreVersion,
Expand Down Expand Up @@ -98,7 +104,8 @@ export function makePluginAPI<SideChannel extends Context.SimplePlugin>(
cache: CacheConfigurator<SideChannel>,
externalDependencies: Array<string>,
): PluginAPI {
const assumption = name => cache.using(data => data.assumptions[name]);
const assumption = (name: string) =>
cache.using(data => data.assumptions[name]);

return { ...makePresetAPI(cache, externalDependencies), assumption };
}
Expand Down
33 changes: 19 additions & 14 deletions packages/babel-core/src/config/index.ts
@@ -1,4 +1,5 @@
import gensync from "gensync";
import type { Gensync } from "gensync";

export type {
ResolvedConfig,
Expand All @@ -23,7 +24,7 @@ export type {
ValidatedOptions as PresetObject,
} from "./validation/options";

import loadFullConfig from "./full";
import loadFullConfig, { type ResolvedConfig } from "./full";
import { loadPartialConfig as loadPartialConfigRunner } from "./partial";

export { loadFullConfig as default };
Expand All @@ -32,24 +33,28 @@ export type { PartialConfig } from "./partial";
import { createConfigItem as createConfigItemImpl } from "./item";
import type { ConfigItem } from "./item";

const loadOptionsRunner = gensync<(opts: unknown) => any>(function* (opts) {
const config = yield* loadFullConfig(opts);
// NOTE: We want to return "null" explicitly, while ?. alone returns undefined
return config?.options ?? null;
});
const loadOptionsRunner = gensync<(opts: unknown) => ResolvedConfig | null>(
function* (opts) {
const config = yield* loadFullConfig(opts);
// NOTE: We want to return "null" explicitly, while ?. alone returns undefined
return config?.options ?? null;
},
);

const createConfigItemRunner =
gensync<(...args: Parameters<typeof createConfigItemImpl>) => ConfigItem>(
createConfigItemImpl,
);

const maybeErrback = runner => (opts: unknown, callback?: Function) => {
if (callback === undefined && typeof opts === "function") {
callback = opts;
opts = undefined;
}
return callback ? runner.errback(opts, callback) : runner.sync(opts);
};
const maybeErrback =
(runner: Gensync<(...args: any) => any>) =>
(opts: unknown, callback?: any) => {
if (callback === undefined && typeof opts === "function") {
callback = opts;
opts = undefined;
}
return callback ? runner.errback(opts, callback) : runner.sync(opts);
};

export const loadPartialConfig = maybeErrback(loadPartialConfigRunner);
export const loadPartialConfigSync = loadPartialConfigRunner.sync;
Expand All @@ -63,7 +68,7 @@ export const createConfigItemSync = createConfigItemRunner.sync;
export const createConfigItemAsync = createConfigItemRunner.async;
export function createConfigItem(
target: PluginTarget,
options: any,
options: Parameters<typeof createConfigItemImpl>[1],
callback?: (err: Error, val: ConfigItem | null) => void,
) {
if (callback !== undefined) {
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-core/src/config/pattern-to-regex.ts
Expand Up @@ -11,7 +11,7 @@ const starPatLast = `(?:${substitution}${endSep})`;
const starStarPat = `${starPat}*?`;
const starStarPatLast = `${starPat}*?${starPatLast}?`;

function escapeRegExp(string) {
function escapeRegExp(string: string) {
return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
}

Expand Down
6 changes: 3 additions & 3 deletions packages/babel-core/src/config/plugin.ts
Expand Up @@ -5,9 +5,9 @@ import type { PluginObject } from "./validation/plugins";
export default class Plugin {
key: string | undefined | null;
manipulateOptions?: (options: unknown, parserOpts: unknown) => void;
post?: Function;
pre?: Function;
visitor: {};
post?: PluginObject["post"];
pre?: PluginObject["pre"];
visitor: PluginObject["visitor"];

parserOverride?: Function;
generatorOverride?: Function;
Expand Down

0 comments on commit ac8bb49

Please sign in to comment.