Skip to content

Commit

Permalink
Disallow sync createConfigItem,loadPartialConfig,loadOptions (#15869)
Browse files Browse the repository at this point in the history
  • Loading branch information
JLHwung committed Aug 17, 2023
1 parent 866ea43 commit 05c4089
Show file tree
Hide file tree
Showing 8 changed files with 320 additions and 168 deletions.
9 changes: 8 additions & 1 deletion eslint/babel-eslint-parser/src/worker/babel-core.cjs
Expand Up @@ -7,7 +7,14 @@ function initialize(babel) {
exports.parseSync = babel.parseSync;
exports.loadPartialConfigSync = babel.loadPartialConfigSync;
exports.loadPartialConfigAsync = babel.loadPartialConfigAsync;
exports.createConfigItem = babel.createConfigItem;
if (process.env.BABEL_8_BREAKING) {
exports.createConfigItemSync = babel.createConfigItemSync;
} else {
// babel.createConfigItemSync is available on 7.13+
// we support Babel 7.11+
exports.createConfigItemSync =
babel.createConfigItemSync || babel.createConfigItem;
}
}

if (USE_ESM) {
Expand Down
2 changes: 1 addition & 1 deletion eslint/babel-eslint-parser/src/worker/maybeParse.cjs
Expand Up @@ -10,7 +10,7 @@ const MULTIPLE_OVERRIDES = /More than one plugin attempted to override parsing/;

module.exports = function maybeParse(code, options) {
if (!extractParserOptionsConfigItem) {
extractParserOptionsConfigItem = babel.createConfigItem(
extractParserOptionsConfigItem = babel.createConfigItemSync(
[extractParserOptionsPlugin, ref],
{ dirname: __dirname, type: "plugin" },
);
Expand Down
137 changes: 100 additions & 37 deletions packages/babel-core/src/config/index.ts
@@ -1,4 +1,4 @@
import gensync, { type Handler, type Callback } from "gensync";
import gensync, { type Handler } from "gensync";

export type {
ResolvedConfig,
Expand All @@ -24,62 +24,125 @@ export type {
} from "./validation/options";

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

export { loadFullConfig as default };
export type { PartialConfig } from "./partial";

import { createConfigItem as createConfigItemImpl } from "./item";
import type { ConfigItem } from "./item";

const loadOptionsRunner = gensync(function* (
opts: unknown,
): Handler<ResolvedConfig | null> {
import { beginHiddenCallStack } from "../errors/rewrite-stack-trace";

const loadPartialConfigRunner = gensync(loadPartialConfigImpl);
export function loadPartialConfigAsync(
...args: Parameters<typeof loadPartialConfigRunner.async>
) {
return beginHiddenCallStack(loadPartialConfigRunner.async)(...args);
}
export function loadPartialConfigSync(
...args: Parameters<typeof loadPartialConfigRunner.sync>
) {
return beginHiddenCallStack(loadPartialConfigRunner.sync)(...args);
}
export function loadPartialConfig(
opts: Parameters<typeof loadPartialConfigImpl>[0],
callback?: (err: Error, val: PartialConfig | null) => void,
) {
if (callback !== undefined) {
beginHiddenCallStack(loadPartialConfigRunner.errback)(opts, callback);
} else if (typeof opts === "function") {
beginHiddenCallStack(loadPartialConfigRunner.errback)(
undefined,
opts as (err: Error, val: PartialConfig | null) => void,
);
} else {
if (process.env.BABEL_8_BREAKING) {
throw new Error(
"Starting from Babel 8.0.0, the 'loadPartialConfig' function expects a callback. If you need to call it synchronously, please use 'loadPartialConfigSync'.",
);
} else {
return loadPartialConfigSync(opts);
}
}
}

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

const createConfigItemRunner = gensync(createConfigItemImpl);

const maybeErrback =
<Arg, Return>(runner: gensync.Gensync<[Arg], Return>) =>
(argOrCallback: Arg | Callback<Return>, maybeCallback?: Callback<Return>) => {
let arg: Arg | undefined;
let callback: Callback<Return>;
if (maybeCallback === undefined && typeof argOrCallback === "function") {
callback = argOrCallback as Callback<Return>;
arg = undefined;
}
const loadOptionsRunner = gensync(loadOptionsImpl);
export function loadOptionsAsync(
...args: Parameters<typeof loadOptionsRunner.async>
) {
return beginHiddenCallStack(loadOptionsRunner.async)(...args);
}
export function loadOptionsSync(
...args: Parameters<typeof loadOptionsRunner.sync>
) {
return beginHiddenCallStack(loadOptionsRunner.sync)(...args);
}
export function loadOptions(
opts: Parameters<typeof loadOptionsImpl>[0],
callback?: (err: Error, val: ResolvedConfig | null) => void,
) {
if (callback !== undefined) {
beginHiddenCallStack(loadOptionsRunner.errback)(opts, callback);
} else if (typeof opts === "function") {
beginHiddenCallStack(loadOptionsRunner.errback)(
undefined,
opts as (err: Error, val: ResolvedConfig | null) => void,
);
} else {
if (process.env.BABEL_8_BREAKING) {
throw new Error(
"Starting from Babel 8.0.0, the 'loadOptions' function expects a callback. If you need to call it synchronously, please use 'loadOptionsSync'.",
);
} else {
callback = maybeCallback;
arg = argOrCallback as Arg;
}
if (!callback) {
return runner.sync(arg);
return loadOptionsSync(opts);
}
runner.errback(arg, callback);
};

export const loadPartialConfig = maybeErrback(loadPartialConfigRunner);
export const loadPartialConfigSync = loadPartialConfigRunner.sync;
export const loadPartialConfigAsync = loadPartialConfigRunner.async;

export const loadOptions = maybeErrback(loadOptionsRunner);
export const loadOptionsSync = loadOptionsRunner.sync;
export const loadOptionsAsync = loadOptionsRunner.async;
}
}

export const createConfigItemSync = createConfigItemRunner.sync;
export const createConfigItemAsync = createConfigItemRunner.async;
const createConfigItemRunner = gensync(createConfigItemImpl);
export function createConfigItemAsync(
...args: Parameters<typeof createConfigItemRunner.async>
) {
return beginHiddenCallStack(createConfigItemRunner.async)(...args);
}
export function createConfigItemSync(
...args: Parameters<typeof createConfigItemRunner.sync>
) {
return beginHiddenCallStack(createConfigItemRunner.sync)(...args);
}
export function createConfigItem(
target: PluginTarget,
options: Parameters<typeof createConfigItemImpl>[1],
callback?: (err: Error, val: ConfigItem<PluginAPI> | null) => void,
) {
if (callback !== undefined) {
createConfigItemRunner.errback(target, options, callback);
beginHiddenCallStack(createConfigItemRunner.errback)(
target,
options,
callback,
);
} else if (typeof options === "function") {
createConfigItemRunner.errback(target, undefined, callback);
beginHiddenCallStack(createConfigItemRunner.errback)(
target,
undefined,
callback,
);
} else {
return createConfigItemRunner.sync(target, options);
if (process.env.BABEL_8_BREAKING) {
throw new Error(
"Starting from Babel 8.0.0, the 'createConfigItem' function expects a callback. If you need to call it synchronously, please use 'createConfigItemSync'.",
);
} else {
return createConfigItemSync(target, options);
}
}
}
5 changes: 2 additions & 3 deletions packages/babel-core/src/config/partial.ts
@@ -1,5 +1,4 @@
import path from "path";
import gensync from "gensync";
import type { Handler } from "gensync";
import Plugin from "./plugin";
import { mergeOptions } from "./util";
Expand Down Expand Up @@ -159,7 +158,7 @@ type LoadPartialConfigOpts = {
showIgnoredFiles?: boolean;
};

export const loadPartialConfig = gensync(function* (
export function* loadPartialConfig(
opts?: LoadPartialConfigOpts,
): Handler<PartialConfig | null> {
let showIgnoredFiles = false;
Expand Down Expand Up @@ -197,7 +196,7 @@ export const loadPartialConfig = gensync(function* (
fileHandling,
files,
);
});
}

export type { PartialConfig };

Expand Down
19 changes: 11 additions & 8 deletions packages/babel-core/test/assumptions.js
@@ -1,16 +1,19 @@
import path from "path";
import { fileURLToPath } from "url";
import { loadOptions as loadOptionsOrig, transformSync } from "../lib/index.js";
import {
loadOptionsSync as loadOptionsSyncOrig,
transformSync,
} from "../lib/index.js";
import pluginCommonJS from "@babel/plugin-transform-modules-commonjs";

const cwd = path.dirname(fileURLToPath(import.meta.url));

function loadOptions(opts) {
return loadOptionsOrig({ cwd, ...opts });
function loadOptionsSync(opts) {
return loadOptionsSyncOrig({ cwd, ...opts });
}

function withAssumptions(assumptions) {
return loadOptions({ assumptions });
return loadOptionsSync({ assumptions });
}

describe("assumptions", () => {
Expand All @@ -35,7 +38,7 @@ describe("assumptions", () => {

it("can be enabled by presets", () => {
expect(
loadOptions({
loadOptionsSync({
assumptions: {
setPublicClassFields: true,
},
Expand All @@ -49,7 +52,7 @@ describe("assumptions", () => {

it("cannot be disabled by presets", () => {
expect(() =>
loadOptions({
loadOptionsSync({
presets: [() => ({ assumptions: { mutableTemplateObject: false } })],
}),
).toThrow(
Expand Down Expand Up @@ -116,7 +119,7 @@ describe("assumptions", () => {
it("plugin defined outside preset", () => {
const ref = {};

loadOptions({
loadOptionsSync({
configFile: false,
presets: [presetEnumerableModuleMeta],
plugins: [[pluginExtractEnumerableModuleMeta, ref]],
Expand All @@ -128,7 +131,7 @@ describe("assumptions", () => {
it("plugin defined inside preset", () => {
const ref = {};

loadOptions({
loadOptionsSync({
configFile: false,
presets: [
() => ({
Expand Down

0 comments on commit 05c4089

Please sign in to comment.