Skip to content

Commit

Permalink
feat(errors): validate preset when filename is absent (#10181)
Browse files Browse the repository at this point in the history
* feat(errors): validate preset when filename is absent

Closes #10154

* fix: test overrides for filename compulsory

* docs: rewrite validate error message

per #10181 (comment)

* polish error message
  • Loading branch information
JLHwung authored and nicolo-ribaudo committed Sep 6, 2019
1 parent 3e4889d commit 8da9d8b
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 4 deletions.
44 changes: 40 additions & 4 deletions packages/babel-core/src/config/full.js
Expand Up @@ -18,6 +18,7 @@ import { validatePluginObject } from "./validation/plugins";
import makeAPI from "./helpers/config-api";

import loadPrivatePartialConfig from "./partial";
import type { ValidatedOptions } from "./validation/options";

type LoadedDescriptor = {
value: {},
Expand Down Expand Up @@ -278,17 +279,52 @@ const instantiatePlugin = makeWeakCache(
},
);

const validateIfOptionNeedsFilename = (
options: ValidatedOptions,
descriptor: UnloadedDescriptor,
): void => {
if (options.test || options.include || options.exclude) {
const formattedPresetName = descriptor.name
? `"${descriptor.name}"`
: "/* your preset */";
throw new Error(
[
`Preset ${formattedPresetName} requires a filename to be set when babel is called directly,`,
`\`\`\``,
`babel.transform(code, { filename: 'file.ts', presets: [${formattedPresetName}] });`,
`\`\`\``,
`See https://babeljs.io/docs/en/options#filename for more information.`,
].join("\n"),
);
}
};

const validatePreset = (
preset: PresetInstance,
context: ConfigContext,
descriptor: UnloadedDescriptor,
): void => {
if (!context.filename) {
const { options } = preset;
validateIfOptionNeedsFilename(options, descriptor);
if (options.overrides) {
options.overrides.forEach(overrideOptions =>
validateIfOptionNeedsFilename(overrideOptions, descriptor),
);
}
}
};

/**
* Generate a config object that will act as the root of a new nested config.
*/
const loadPresetDescriptor = (
descriptor: UnloadedDescriptor,
context: ConfigContext,
): ConfigChain | null => {
return buildPresetChain(
instantiatePreset(loadDescriptor(descriptor, context)),
context,
);
const preset = instantiatePreset(loadDescriptor(descriptor, context));
validatePreset(preset, context, descriptor);
return buildPresetChain(preset, context);
};

const instantiatePreset = makeWeakCache(
Expand Down
22 changes: 22 additions & 0 deletions packages/babel-core/test/config-chain.js
Expand Up @@ -1049,5 +1049,27 @@ describe("buildConfigChain", function() {
loadOptions({ filename, cwd: path.dirname(filename) }),
).toThrow(/Error while parsing JSON - /);
});

it("should throw when `test` presents but `filename` is not passed", () => {
expect(() => loadOptions({ test: /\.ts$/, plugins: [] })).toThrow(
/Configuration contains string\/RegExp pattern/,
);
});

it("should throw when `preset` requires `filename` but it was not passed", () => {
expect(() => {
loadOptions({
presets: [require("./fixtures/config-loading/preset4")],
});
}).toThrow(/Preset \/\* your preset \*\/ requires a filename/);
});

it("should throw when `preset.overrides` requires `filename` but it was not passed", () => {
expect(() => {
loadOptions({
presets: [require("./fixtures/config-loading/preset5")],
});
}).toThrow(/Preset \/\* your preset \*\/ requires a filename/);
});
});
});
6 changes: 6 additions & 0 deletions packages/babel-core/test/fixtures/config-loading/preset4.js
@@ -0,0 +1,6 @@
module.exports = function() {
return {
test: /\.ts$/,
plugins: []
}
};
8 changes: 8 additions & 0 deletions packages/babel-core/test/fixtures/config-loading/preset5.js
@@ -0,0 +1,8 @@
module.exports = function() {
return {
overrides: [{
test: /\.ts$/,
plugins: []
}]
}
};

0 comments on commit 8da9d8b

Please sign in to comment.