feat(errors): validate preset when filename is absent (#10181)

* feat(errors): validate preset when filename is absent

Closes #10154

* fix: test overrides for filename compulsory

* docs: rewrite validate error message

per https://github.com/babel/babel/pull/10181#discussion_r301607986

* polish error message
This commit is contained in:
Huáng Jùnliàng 2019-09-06 12:09:19 -04:00 committed by Nicolò Ribaudo
parent 3e4889d649
commit 8da9d8b4b8
4 changed files with 76 additions and 4 deletions

View File

@ -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: {},
@ -278,6 +279,42 @@ 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.
*/
@ -285,10 +322,9 @@ 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(

View File

@ -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/);
});
});
});

View File

@ -0,0 +1,6 @@
module.exports = function() {
return {
test: /\.ts$/,
plugins: []
}
};

View File

@ -0,0 +1,8 @@
module.exports = function() {
return {
overrides: [{
test: /\.ts$/,
plugins: []
}]
}
};