forked from babel/babel
/
config-api.js
131 lines (111 loc) · 3.54 KB
/
config-api.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// @flow
import semver from "semver";
import type { Targets } from "@babel/helper-compilation-targets";
import { version as coreVersion } from "../../";
import {
assertSimpleType,
type CacheConfigurator,
type SimpleCacheConfigurator,
type SimpleType,
} from "../caching";
import type { CallerMetadata } from "../validation/options";
type EnvFunction = {
(): string,
<T>((string) => T): T,
(string): boolean,
(Array<string>): boolean,
};
type CallerFactory = ((CallerMetadata | void) => mixed) => SimpleType;
type TargetsFunction = () => Targets;
export type ConfigAPI = {|
version: string,
cache: SimpleCacheConfigurator,
env: EnvFunction,
async: () => boolean,
assertVersion: typeof assertVersion,
caller?: CallerFactory,
|};
export type PluginAPI = {|
...ConfigAPI,
targets: TargetsFunction,
|};
export function makeConfigAPI<
SideChannel: { envName: string, caller: CallerMetadata | void },
>(cache: CacheConfigurator<SideChannel>): ConfigAPI {
const env: any = value =>
cache.using(data => {
if (typeof value === "undefined") return data.envName;
if (typeof value === "function") {
return assertSimpleType(value(data.envName));
}
if (!Array.isArray(value)) value = [value];
return value.some((entry: mixed) => {
if (typeof entry !== "string") {
throw new Error("Unexpected non-string value");
}
return entry === data.envName;
});
});
const caller = cb => cache.using(data => assertSimpleType(cb(data.caller)));
return {
version: coreVersion,
cache: cache.simple(),
// Expose ".env()" so people can easily get the same env that we expose using the "env" key.
env,
async: () => false,
caller,
assertVersion,
};
}
export function makePluginAPI(
cache: CacheConfigurator<{
envName: string,
caller: CallerMetadata | void,
targets: Targets,
}>,
): PluginAPI {
const targets = () =>
// We are using JSON.parse/JSON.stringify because it's only possible to cache
// primitive values. We can safely stringify the targets object because it
// only contains strings as its properties.
// Please make the Record and Tuple proposal happen!
JSON.parse(cache.using(data => JSON.stringify(data.targets)));
return { ...makeConfigAPI(cache), targets };
}
function assertVersion(range: string | number): void {
if (typeof range === "number") {
if (!Number.isInteger(range)) {
throw new Error("Expected string or integer value.");
}
range = `^${range}.0.0-0`;
}
if (typeof range !== "string") {
throw new Error("Expected string or integer value.");
}
if (semver.satisfies(coreVersion, range)) return;
const limit = Error.stackTraceLimit;
if (typeof limit === "number" && limit < 25) {
// Bump up the limit if needed so that users are more likely
// to be able to see what is calling Babel.
Error.stackTraceLimit = 25;
}
const err = new Error(
`Requires Babel "${range}", but was loaded with "${coreVersion}". ` +
`If you are sure you have a compatible version of @babel/core, ` +
`it is likely that something in your build process is loading the ` +
`wrong version. Inspect the stack trace of this error to look for ` +
`the first entry that doesn't mention "@babel/core" or "babel-core" ` +
`to see what is calling Babel.`,
);
if (typeof limit === "number") {
Error.stackTraceLimit = limit;
}
throw Object.assign(
err,
({
code: "BABEL_VERSION_UNSUPPORTED",
version: coreVersion,
range,
}: any),
);
}