Skip to content

Commit e130225

Browse files
authored
Polish(standalone): improve message on invalid preset/plugin (#17606)
1 parent beea88c commit e130225

5 files changed

Lines changed: 65 additions & 5 deletions

File tree

eslint.config.mts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,18 @@ export default defineConfig([
181181
allowNamedExports: true,
182182
},
183183
],
184+
"@typescript-eslint/no-base-to-string": [
185+
"error",
186+
{
187+
ignoredTypeNames: [
188+
"Error",
189+
"RegExp",
190+
"URL",
191+
"URLSearchParams",
192+
"SemVer",
193+
],
194+
},
195+
],
184196
"@typescript-eslint/no-confusing-void-expression": [
185197
"error",
186198
{ ignoreArrowShorthand: true },
@@ -197,7 +209,6 @@ export default defineConfig([
197209

198210
// Todo: Investigate, for each of these, whether we want them
199211
"@typescript-eslint/consistent-type-definitions": "off",
200-
"@typescript-eslint/no-base-to-string": "off",
201212
"@typescript-eslint/no-duplicate-type-constituents": "off",
202213
"@typescript-eslint/no-empty-function": "off",
203214
"@typescript-eslint/no-empty-interface": "off",

packages/babel-core/src/config/config-descriptors.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ export function* createDescriptor<API>(
331331
}
332332

333333
if (!value) {
334+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
334335
throw new Error(`Unexpected falsy value: ${String(value)}`);
335336
}
336337

packages/babel-core/src/errors/rewrite-stack-trace.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,5 +169,6 @@ function setupPrepareStackTrace() {
169169

170170
function defaultPrepareStackTrace(err: Error, trace: CallSite[]) {
171171
if (trace.length === 0) return ErrorToString(err);
172+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
172173
return `${ErrorToString(err)}\n at ${trace.join("\n at ")}`;
173174
}

packages/babel-standalone/src/index.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ import presetEnv from "@babel/preset-env";
2626
import presetFlow from "@babel/preset-flow";
2727
import presetReact from "@babel/preset-react";
2828
import presetTypescript from "@babel/preset-typescript";
29-
import type { InputOptions } from "@babel/core";
29+
import type { InputOptions, PluginItem } from "@babel/core";
30+
type PresetItem = NonNullable<InputOptions["presets"]>[number];
3031

3132
import { runScripts } from "./transformScriptTags.ts";
3233

@@ -85,7 +86,9 @@ export const availablePresets = {
8586

8687
const isArray =
8788
Array.isArray ||
88-
(arg => Object.prototype.toString.call(arg) === "[object Array]");
89+
((arg =>
90+
Object.prototype.toString.call(arg) ===
91+
"[object Array]") as typeof Array.isArray);
8992

9093
/**
9194
* Loads the given name (or [name, options] pair) from the given table object
@@ -107,6 +110,22 @@ function loadBuiltin(builtinTable: Record<string, unknown>, name: any) {
107110
return name;
108111
}
109112

113+
/**
114+
* This function will be called only when the preset or plugin, specified via string or [string, object],
115+
* is not available in the builtin table. Therefore we do not handle the case when the plugin/preset is an
116+
* object or a function here.
117+
* @param item
118+
* @returns
119+
*/
120+
function getPluginOrPresetName(item: PluginItem | PresetItem) {
121+
if (typeof item === "string") {
122+
return item;
123+
} else if (isArray(item)) {
124+
return getPluginOrPresetName(item[0]);
125+
}
126+
return JSON.stringify(item);
127+
}
128+
110129
/**
111130
* Parses plugin names and presets from the specified options.
112131
*/
@@ -128,7 +147,7 @@ function processOptions(options: InputOptions) {
128147
}
129148
} else {
130149
throw new Error(
131-
`Invalid preset specified in Babel options: "${presetName}"`,
150+
`Invalid preset specified in Babel options: "${getPluginOrPresetName(presetName)}"`,
132151
);
133152
}
134153
return preset;
@@ -140,7 +159,7 @@ function processOptions(options: InputOptions) {
140159

141160
if (!plugin) {
142161
throw new Error(
143-
`Invalid plugin specified in Babel options: "${pluginName}"`,
162+
`Invalid plugin specified in Babel options: "${getPluginOrPresetName(pluginName)}"`,
144163
);
145164
}
146165
return plugin;

packages/babel-standalone/test/babel.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,40 @@ describe("@babel/standalone", () => {
129129
);
130130
});
131131

132+
it("throws on invalid preset name with options", () => {
133+
expect(() =>
134+
Babel.transform("var foo", {
135+
presets: [["lolfail", { option: function () {} }]],
136+
}),
137+
).toThrow(/Invalid preset specified in Babel options: "lolfail"/);
138+
});
139+
140+
it("throws on falsy preset", () => {
141+
expect(() => Babel.transform("var foo", { presets: [null] })).toThrow(
142+
/Invalid preset specified in Babel options: "null"/,
143+
);
144+
});
145+
132146
it("throws on invalid plugin name", () => {
133147
expect(() => Babel.transform("var foo", { plugins: ["lolfail"] })).toThrow(
134148
/Invalid plugin specified in Babel options: "lolfail"/,
135149
);
136150
});
137151

152+
it("throws on invalid plugin name with options", () => {
153+
expect(() =>
154+
Babel.transform("var foo", {
155+
plugins: [["lolfail", { option: function () {} }]],
156+
}),
157+
).toThrow(/Invalid plugin specified in Babel options: "lolfail"/);
158+
});
159+
160+
it("throws on falsy plugin", () => {
161+
expect(() => Babel.transform("var foo", { plugins: [null] })).toThrow(
162+
/Invalid plugin specified in Babel options: "null"/,
163+
);
164+
});
165+
138166
describe("env preset", () => {
139167
it("works w/o targets", () => {
140168
const output = Babel.transform("const a = 1;", {

0 commit comments

Comments
 (0)