Validate @babel/preset-env options (#8031)
This commit is contained in:
parent
110779e9f3
commit
3de053cc6c
@ -166,3 +166,9 @@ declare module "convert-source-map" {
|
|||||||
generateMapFileComment(path: string, options?: ?{ multiline: boolean }): string,
|
generateMapFileComment(path: string, options?: ?{ multiline: boolean }): string,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module "js-levenshtein" {
|
||||||
|
declare module.exports: {
|
||||||
|
(string, string): number,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -49,6 +49,7 @@
|
|||||||
"@babel/plugin-transform-unicode-regex": "7.0.0-beta.49",
|
"@babel/plugin-transform-unicode-regex": "7.0.0-beta.49",
|
||||||
"browserslist": "^3.0.0",
|
"browserslist": "^3.0.0",
|
||||||
"invariant": "^2.2.2",
|
"invariant": "^2.2.2",
|
||||||
|
"js-levenshtein": "^1.1.3",
|
||||||
"semver": "^5.3.0"
|
"semver": "^5.3.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@ -5,9 +5,23 @@ import browserslist from "browserslist";
|
|||||||
import builtInsList from "../data/built-ins.json";
|
import builtInsList from "../data/built-ins.json";
|
||||||
import { defaultWebIncludes } from "./default-includes";
|
import { defaultWebIncludes } from "./default-includes";
|
||||||
import moduleTransformations from "./module-transformations";
|
import moduleTransformations from "./module-transformations";
|
||||||
|
import { getValues, findSuggestion } from "./utils";
|
||||||
import pluginsList from "../data/plugins.json";
|
import pluginsList from "../data/plugins.json";
|
||||||
|
import { TopLevelOptions, ModulesOption, UseBuiltInsOption } from "./options";
|
||||||
import type { Targets, Options, ModuleOption, BuiltInsOption } from "./types";
|
import type { Targets, Options, ModuleOption, BuiltInsOption } from "./types";
|
||||||
|
|
||||||
|
const validateTopLevelOptions = (options: Options) => {
|
||||||
|
for (const option in options) {
|
||||||
|
if (!TopLevelOptions[option]) {
|
||||||
|
const validOptions = getValues(TopLevelOptions);
|
||||||
|
throw new Error(
|
||||||
|
`Invalid Option: ${option} is not a valid top-level option.
|
||||||
|
Maybe you meant to use '${findSuggestion(validOptions, option)}'?`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const validIncludesAndExcludes = new Set([
|
const validIncludesAndExcludes = new Set([
|
||||||
...Object.keys(pluginsList),
|
...Object.keys(pluginsList),
|
||||||
...Object.keys(moduleTransformations).map(m => moduleTransformations[m]),
|
...Object.keys(moduleTransformations).map(m => moduleTransformations[m]),
|
||||||
@ -108,17 +122,17 @@ export const validateIgnoreBrowserslistConfig = (
|
|||||||
ignoreBrowserslistConfig: boolean,
|
ignoreBrowserslistConfig: boolean,
|
||||||
) =>
|
) =>
|
||||||
validateBoolOption(
|
validateBoolOption(
|
||||||
"ignoreBrowserslistConfig",
|
TopLevelOptions.ignoreBrowserslistConfig,
|
||||||
ignoreBrowserslistConfig,
|
ignoreBrowserslistConfig,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
export const validateModulesOption = (
|
export const validateModulesOption = (
|
||||||
modulesOpt: ModuleOption = "commonjs",
|
modulesOpt: ModuleOption = ModulesOption.commonjs,
|
||||||
) => {
|
) => {
|
||||||
invariant(
|
invariant(
|
||||||
modulesOpt === false ||
|
ModulesOption[modulesOpt] ||
|
||||||
Object.keys(moduleTransformations).indexOf(modulesOpt) > -1,
|
ModulesOption[modulesOpt] === ModulesOption.false,
|
||||||
`Invalid Option: The 'modules' option must be either 'false' to indicate no modules, or a
|
`Invalid Option: The 'modules' option must be either 'false' to indicate no modules, or a
|
||||||
module type which can be be one of: 'commonjs' (default), 'amd', 'umd', 'systemjs'.`,
|
module type which can be be one of: 'commonjs' (default), 'amd', 'umd', 'systemjs'.`,
|
||||||
);
|
);
|
||||||
@ -140,7 +154,8 @@ export const validateUseBuiltInsOption = (
|
|||||||
builtInsOpt: BuiltInsOption = false,
|
builtInsOpt: BuiltInsOption = false,
|
||||||
): BuiltInsOption => {
|
): BuiltInsOption => {
|
||||||
invariant(
|
invariant(
|
||||||
builtInsOpt === "usage" || builtInsOpt === false || builtInsOpt === "entry",
|
UseBuiltInsOption[builtInsOpt] ||
|
||||||
|
UseBuiltInsOption[builtInsOpt] === UseBuiltInsOption.false,
|
||||||
`Invalid Option: The 'useBuiltIns' option must be either
|
`Invalid Option: The 'useBuiltIns' option must be either
|
||||||
'false' (default) to indicate no polyfill,
|
'false' (default) to indicate no polyfill,
|
||||||
'"entry"' to indicate replacing the entry polyfill, or
|
'"entry"' to indicate replacing the entry polyfill, or
|
||||||
@ -151,32 +166,40 @@ export const validateUseBuiltInsOption = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function normalizeOptions(opts: Options) {
|
export default function normalizeOptions(opts: Options) {
|
||||||
const include = expandIncludesAndExcludes(opts.include, "include");
|
validateTopLevelOptions(opts);
|
||||||
const exclude = expandIncludesAndExcludes(opts.exclude, "exclude");
|
|
||||||
|
const include = expandIncludesAndExcludes(
|
||||||
|
opts.include,
|
||||||
|
TopLevelOptions.include,
|
||||||
|
);
|
||||||
|
const exclude = expandIncludesAndExcludes(
|
||||||
|
opts.exclude,
|
||||||
|
TopLevelOptions.exclude,
|
||||||
|
);
|
||||||
|
|
||||||
checkDuplicateIncludeExcludes(include, exclude);
|
checkDuplicateIncludeExcludes(include, exclude);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
configPath: validateConfigPathOption(opts.configPath),
|
configPath: validateConfigPathOption(opts.configPath),
|
||||||
debug: opts.debug,
|
debug: validateBoolOption(TopLevelOptions.debug, opts.debug, false),
|
||||||
include,
|
include,
|
||||||
exclude,
|
exclude,
|
||||||
forceAllTransforms: validateBoolOption(
|
forceAllTransforms: validateBoolOption(
|
||||||
"forceAllTransforms",
|
TopLevelOptions.forceAllTransforms,
|
||||||
opts.forceAllTransforms,
|
opts.forceAllTransforms,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
ignoreBrowserslistConfig: validateIgnoreBrowserslistConfig(
|
ignoreBrowserslistConfig: validateIgnoreBrowserslistConfig(
|
||||||
opts.ignoreBrowserslistConfig,
|
opts.ignoreBrowserslistConfig,
|
||||||
),
|
),
|
||||||
loose: validateBoolOption("loose", opts.loose, false),
|
loose: validateBoolOption(TopLevelOptions.loose, opts.loose, false),
|
||||||
modules: validateModulesOption(opts.modules),
|
modules: validateModulesOption(opts.modules),
|
||||||
shippedProposals: validateBoolOption(
|
shippedProposals: validateBoolOption(
|
||||||
"shippedProposals",
|
TopLevelOptions.shippedProposals,
|
||||||
opts.shippedProposals,
|
opts.shippedProposals,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
spec: validateBoolOption("loose", opts.spec, false),
|
spec: validateBoolOption(TopLevelOptions.spec, opts.spec, false),
|
||||||
targets: {
|
targets: {
|
||||||
...opts.targets,
|
...opts.targets,
|
||||||
},
|
},
|
||||||
|
|||||||
44
packages/babel-preset-env/src/options.js
Normal file
44
packages/babel-preset-env/src/options.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
export const TopLevelOptions = {
|
||||||
|
configPath: "configPath",
|
||||||
|
debug: "debug",
|
||||||
|
exclude: "exclude",
|
||||||
|
forceAllTransforms: "forceAllTransforms",
|
||||||
|
ignoreBrowserslistConfig: "ignoreBrowserslistConfig",
|
||||||
|
include: "include",
|
||||||
|
loose: "loose",
|
||||||
|
modules: "modules",
|
||||||
|
shippedProposals: "shippedProposals",
|
||||||
|
spec: "spec",
|
||||||
|
targets: "targets",
|
||||||
|
useBuiltIns: "useBuiltIns",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ModulesOption = {
|
||||||
|
false: false,
|
||||||
|
amd: "amd",
|
||||||
|
commonjs: "commonjs",
|
||||||
|
cjs: "cjs",
|
||||||
|
systemjs: "systemjs",
|
||||||
|
umd: "umd",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const UseBuiltInsOption = {
|
||||||
|
false: false,
|
||||||
|
entry: "entry",
|
||||||
|
usage: "usage",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TargetNames = {
|
||||||
|
esmodules: "esmodules",
|
||||||
|
node: "node",
|
||||||
|
browsers: "browsers",
|
||||||
|
chrome: "chrome",
|
||||||
|
opera: "opera",
|
||||||
|
edge: "edge",
|
||||||
|
firefox: "firefox",
|
||||||
|
safari: "safari",
|
||||||
|
ie: "ie",
|
||||||
|
ios: "ios",
|
||||||
|
android: "android",
|
||||||
|
electron: "electron",
|
||||||
|
};
|
||||||
@ -1,12 +1,32 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import browserslist from "browserslist";
|
import browserslist from "browserslist";
|
||||||
|
import invariant from "invariant";
|
||||||
import semver from "semver";
|
import semver from "semver";
|
||||||
import { semverify, isUnreleasedVersion, getLowestUnreleased } from "./utils";
|
import {
|
||||||
|
semverify,
|
||||||
|
isUnreleasedVersion,
|
||||||
|
getLowestUnreleased,
|
||||||
|
getValues,
|
||||||
|
findSuggestion,
|
||||||
|
} from "./utils";
|
||||||
import { objectToBrowserslist } from "./normalize-options";
|
import { objectToBrowserslist } from "./normalize-options";
|
||||||
import browserModulesData from "../data/built-in-modules.json";
|
import browserModulesData from "../data/built-in-modules.json";
|
||||||
|
import { TargetNames } from "./options";
|
||||||
import type { Targets } from "./types";
|
import type { Targets } from "./types";
|
||||||
|
|
||||||
|
const validateTargetNames = (validTargets, targets) => {
|
||||||
|
for (const target in targets) {
|
||||||
|
if (!TargetNames[target]) {
|
||||||
|
const validOptions = getValues(TargetNames);
|
||||||
|
throw new Error(
|
||||||
|
`Invalid Option: '${target}' is not a valid target
|
||||||
|
Maybe you meant to use '${findSuggestion(validOptions, target)}'?`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const browserNameMap = {
|
const browserNameMap = {
|
||||||
android: "android",
|
android: "android",
|
||||||
chrome: "chrome",
|
chrome: "chrome",
|
||||||
@ -21,13 +41,21 @@ const browserNameMap = {
|
|||||||
const isBrowsersQueryValid = (browsers: string | Array<string>): boolean =>
|
const isBrowsersQueryValid = (browsers: string | Array<string>): boolean =>
|
||||||
typeof browsers === "string" || Array.isArray(browsers);
|
typeof browsers === "string" || Array.isArray(browsers);
|
||||||
|
|
||||||
|
const validateBrowsers = browsers => {
|
||||||
|
invariant(
|
||||||
|
typeof browsers === "undefined" || isBrowsersQueryValid(browsers),
|
||||||
|
`Invalid Option: '${browsers}' is not a valid browserslist query`,
|
||||||
|
);
|
||||||
|
return browsers;
|
||||||
|
};
|
||||||
|
|
||||||
export const semverMin = (first: ?string, second: string): string => {
|
export const semverMin = (first: ?string, second: string): string => {
|
||||||
return first && semver.lt(first, second) ? first : second;
|
return first && semver.lt(first, second) ? first : second;
|
||||||
};
|
};
|
||||||
|
|
||||||
const mergeBrowsers = (fromQuery: Targets, fromTarget: Targets) => {
|
const mergeBrowsers = (fromQuery: Targets, fromTarget: Targets) => {
|
||||||
return Object.keys(fromTarget).reduce((queryObj, targKey) => {
|
return Object.keys(fromTarget).reduce((queryObj, targKey) => {
|
||||||
if (targKey !== "browsers") {
|
if (targKey !== TargetNames.browsers) {
|
||||||
queryObj[targKey] = fromTarget[targKey];
|
queryObj[targKey] = fromTarget[targKey];
|
||||||
}
|
}
|
||||||
return queryObj;
|
return queryObj;
|
||||||
@ -85,11 +113,21 @@ const outputDecimalWarning = (decimalTargets: Array<Object>): void => {
|
|||||||
console.log("");
|
console.log("");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const semverifyTarget = (target, value) => {
|
||||||
|
try {
|
||||||
|
return semverify(value);
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid Option: '${value}' is not a valid value for 'targets.${target}'.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const targetParserMap = {
|
const targetParserMap = {
|
||||||
__default: (target, value) => {
|
__default: (target, value) => {
|
||||||
const version = isUnreleasedVersion(value, target)
|
const version = isUnreleasedVersion(value, target)
|
||||||
? value.toLowerCase()
|
? value.toLowerCase()
|
||||||
: semverify(value);
|
: semverifyTarget(target, value);
|
||||||
return [target, version];
|
return [target, version];
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -98,8 +136,7 @@ const targetParserMap = {
|
|||||||
const parsed =
|
const parsed =
|
||||||
value === true || value === "current"
|
value === true || value === "current"
|
||||||
? process.versions.node
|
? process.versions.node
|
||||||
: semverify(value);
|
: semverifyTarget(target, value);
|
||||||
|
|
||||||
return [target, parsed];
|
return [target, parsed];
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -108,9 +145,12 @@ type ParsedResult = {
|
|||||||
targets: Targets,
|
targets: Targets,
|
||||||
decimalWarnings: Array<Object>,
|
decimalWarnings: Array<Object>,
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTargets = (targets: Object = {}, options: Object = {}): Targets => {
|
const getTargets = (targets: Object = {}, options: Object = {}): Targets => {
|
||||||
const targetOpts: Targets = {};
|
const targetOpts: Targets = {};
|
||||||
|
|
||||||
|
validateTargetNames(targets);
|
||||||
|
|
||||||
// `esmodules` as a target indicates the specific set of browsers supporting ES Modules.
|
// `esmodules` as a target indicates the specific set of browsers supporting ES Modules.
|
||||||
// These values OVERRIDE the `browsers` field.
|
// These values OVERRIDE the `browsers` field.
|
||||||
if (targets.esmodules) {
|
if (targets.esmodules) {
|
||||||
@ -119,23 +159,24 @@ const getTargets = (targets: Object = {}, options: Object = {}): Targets => {
|
|||||||
.map(browser => `${browser} ${supportsESModules[browser]}`)
|
.map(browser => `${browser} ${supportsESModules[browser]}`)
|
||||||
.join(", ");
|
.join(", ");
|
||||||
}
|
}
|
||||||
// Parse browsers target via browserslist;
|
|
||||||
const queryIsValid = isBrowsersQueryValid(targets.browsers);
|
// Parse browsers target via browserslist
|
||||||
const browsersquery = queryIsValid ? targets.browsers : null;
|
const browsersquery = validateBrowsers(targets.browsers);
|
||||||
if (queryIsValid || !options.ignoreBrowserslistConfig) {
|
if (!options.ignoreBrowserslistConfig) {
|
||||||
browserslist.defaults = objectToBrowserslist(targets);
|
browserslist.defaults = objectToBrowserslist(targets);
|
||||||
|
|
||||||
const browsers = browserslist(browsersquery, { path: options.configPath });
|
const browsers = browserslist(browsersquery, { path: options.configPath });
|
||||||
const queryBrowsers = getLowestVersions(browsers);
|
const queryBrowsers = getLowestVersions(browsers);
|
||||||
targets = mergeBrowsers(queryBrowsers, targets);
|
targets = mergeBrowsers(queryBrowsers, targets);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse remaining targets
|
// Parse remaining targets
|
||||||
const parsed = Object.keys(targets)
|
const parsed = Object.keys(targets)
|
||||||
.filter(value => value !== "esmodules")
|
.filter(value => value !== TargetNames.esmodules)
|
||||||
.sort()
|
.sort()
|
||||||
.reduce(
|
.reduce(
|
||||||
(results: ParsedResult, target: string): ParsedResult => {
|
(results: ParsedResult, target: string): ParsedResult => {
|
||||||
if (target !== "browsers") {
|
if (target !== TargetNames.browsers) {
|
||||||
const value = targets[target];
|
const value = targets[target];
|
||||||
|
|
||||||
// Warn when specifying minor/patch as a decimal
|
// Warn when specifying minor/patch as a decimal
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
//@flow
|
//@flow
|
||||||
|
|
||||||
|
import { TargetNames, ModulesOption, UseBuiltInsOption } from "./options";
|
||||||
|
|
||||||
// Targets
|
// Targets
|
||||||
export type Target = string;
|
export type Target = $Keys<typeof TargetNames>;
|
||||||
export type Targets = {
|
export type Targets = {
|
||||||
[target: string]: Target,
|
[target: Target]: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Options
|
// Options
|
||||||
// Use explicit modules to prevent typo errors.
|
// Use explicit modules to prevent typo errors.
|
||||||
export type ModuleOption = false | "amd" | "commonjs" | "systemjs" | "umd";
|
export type ModuleOption = $Values<typeof ModulesOption>;
|
||||||
export type BuiltInsOption = false | "entry" | "usage";
|
export type BuiltInsOption = $Values<typeof UseBuiltInsOption>;
|
||||||
|
|
||||||
export type Options = {
|
export type Options = {
|
||||||
configPath: string,
|
configPath: string,
|
||||||
|
|||||||
@ -1,26 +1,51 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import invariant from "invariant";
|
||||||
import semver from "semver";
|
import semver from "semver";
|
||||||
|
import levenshtein from "js-levenshtein";
|
||||||
import { addSideEffect } from "@babel/helper-module-imports";
|
import { addSideEffect } from "@babel/helper-module-imports";
|
||||||
import unreleasedLabels from "../data/unreleased-labels";
|
import unreleasedLabels from "../data/unreleased-labels";
|
||||||
import { semverMin } from "./targets-parser";
|
import { semverMin } from "./targets-parser";
|
||||||
import type { Targets } from "./types";
|
import type { Targets } from "./types";
|
||||||
|
|
||||||
|
const versionRegExp = /^(\d+|\d+.\d+)$/;
|
||||||
|
|
||||||
// Convert version to a semver value.
|
// Convert version to a semver value.
|
||||||
// 2.5 -> 2.5.0; 1 -> 1.0.0;
|
// 2.5 -> 2.5.0; 1 -> 1.0.0;
|
||||||
export const semverify = (version: string | number): string => {
|
export const semverify = (version: string | number): string => {
|
||||||
if (typeof version === "string" && semver.valid(version)) {
|
const isString = typeof version === "string";
|
||||||
|
|
||||||
|
if (isString && semver.valid(version)) {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
const split = version.toString().split(".");
|
invariant(
|
||||||
|
typeof version === "number" || (isString && versionRegExp.test(version)),
|
||||||
|
`'${version}' is not a valid version`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const split = version.toString().split(".");
|
||||||
while (split.length < 3) {
|
while (split.length < 3) {
|
||||||
split.push("0");
|
split.push("0");
|
||||||
}
|
}
|
||||||
|
|
||||||
return split.join(".");
|
return split.join(".");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getValues = (object: Object): Array<any> =>
|
||||||
|
Object.keys(object).map(key => object[key]);
|
||||||
|
|
||||||
|
export const findSuggestion = (options: Array<string>, option: string) => {
|
||||||
|
let levenshteinValue = Infinity;
|
||||||
|
return options.reduce((suggestion, validOption) => {
|
||||||
|
const value = levenshtein(validOption, option);
|
||||||
|
if (value < levenshteinValue) {
|
||||||
|
levenshteinValue = value;
|
||||||
|
return validOption;
|
||||||
|
}
|
||||||
|
return suggestion;
|
||||||
|
}, undefined);
|
||||||
|
};
|
||||||
|
|
||||||
export const prettifyVersion = (version: string): string => {
|
export const prettifyVersion = (version: string): string => {
|
||||||
if (typeof version !== "string") {
|
if (typeof version !== "string") {
|
||||||
return version;
|
return version;
|
||||||
|
|||||||
@ -36,6 +36,15 @@ describe("normalize-options", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Config format validation", () => {
|
||||||
|
it("should throw if top-level option not found", () => {
|
||||||
|
const unknownTopLevelOption = () => {
|
||||||
|
normalizeOptions({ unknown: "option" });
|
||||||
|
};
|
||||||
|
expect(unknownTopLevelOption).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("RegExp include/exclude", () => {
|
describe("RegExp include/exclude", () => {
|
||||||
it("should not allow invalid plugins in `include` and `exclude`", () => {
|
it("should not allow invalid plugins in `include` and `exclude`", () => {
|
||||||
const normalizeWithNonExistingPlugin = () => {
|
const normalizeWithNonExistingPlugin = () => {
|
||||||
|
|||||||
@ -19,6 +19,35 @@ describe("getTargets", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("validation", () => {
|
||||||
|
it("throws on invalid target name", () => {
|
||||||
|
const invalidTargetName = () => {
|
||||||
|
getTargets({
|
||||||
|
unknown: "unknown",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
expect(invalidTargetName).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws on invalid browsers target", () => {
|
||||||
|
const invalidBrowsersTarget = () => {
|
||||||
|
getTargets({
|
||||||
|
browsers: 59,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
expect(invalidBrowsersTarget).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws on invalid target version", () => {
|
||||||
|
const invalidTargetVersion = () => {
|
||||||
|
getTargets({
|
||||||
|
chrome: "unknown",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
expect(invalidTargetVersion).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("browser", () => {
|
describe("browser", () => {
|
||||||
it("merges browser key targets", () => {
|
it("merges browser key targets", () => {
|
||||||
expect(
|
expect(
|
||||||
@ -55,21 +84,6 @@ describe("getTargets", () => {
|
|||||||
safari: "tp",
|
safari: "tp",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("ignores invalid", () => {
|
|
||||||
expect(
|
|
||||||
getTargets({
|
|
||||||
browsers: 59,
|
|
||||||
chrome: "49",
|
|
||||||
firefox: "55",
|
|
||||||
ie: "11",
|
|
||||||
}),
|
|
||||||
).toEqual({
|
|
||||||
chrome: "49.0.0",
|
|
||||||
firefox: "55.0.0",
|
|
||||||
ie: "11.0.0",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("esmodules", () => {
|
describe("esmodules", () => {
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const utils = require("../lib/utils");
|
const utils = require("../lib/utils");
|
||||||
|
|
||||||
const { prettifyTargets, prettifyVersion, semverify } = utils;
|
const { prettifyTargets, prettifyVersion, semverify, findSuggestion } = utils;
|
||||||
|
|
||||||
describe("utils", () => {
|
describe("utils", () => {
|
||||||
describe("semverify", () => {
|
describe("semverify", () => {
|
||||||
@ -13,6 +13,13 @@ describe("utils", () => {
|
|||||||
expect(semverify(1)).toBe("1.0.0");
|
expect(semverify(1)).toBe("1.0.0");
|
||||||
expect(semverify(1.2)).toBe("1.2.0");
|
expect(semverify(1.2)).toBe("1.2.0");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("throws", () => {
|
||||||
|
const invalidSemver = () => {
|
||||||
|
semverify("invalid");
|
||||||
|
};
|
||||||
|
expect(invalidSemver).toThrow();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("prettifyVersion", () => {
|
describe("prettifyVersion", () => {
|
||||||
@ -43,4 +50,12 @@ describe("utils", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("findSuggestion", () => {
|
||||||
|
it("returns", () => {
|
||||||
|
const options = ["one", "two", "three"];
|
||||||
|
expect(findSuggestion(options, "onr")).toEqual("one");
|
||||||
|
expect(findSuggestion(options, "tree")).toEqual("three");
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user