forked from babel/babel
/
plugin-utils.js
137 lines (118 loc) 路 3.86 KB
/
plugin-utils.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
132
133
134
135
136
137
// @flow
import type Parser from "./parser";
export type Plugin = string | [string, Object];
export type PluginList = $ReadOnlyArray<Plugin>;
export type MixinPlugin = (superClass: Class<Parser>) => Class<Parser>;
export function hasPlugin(plugins: PluginList, name: string): boolean {
return plugins.some(plugin => {
if (Array.isArray(plugin)) {
return plugin[0] === name;
} else {
return plugin === name;
}
});
}
export function getPluginOption(
plugins: PluginList,
name: string,
option: string,
) {
const plugin = plugins.find(plugin => {
if (Array.isArray(plugin)) {
return plugin[0] === name;
} else {
return plugin === name;
}
});
if (plugin && Array.isArray(plugin)) {
return plugin[1][option];
}
return null;
}
const PIPELINE_PROPOSALS = ["minimal", "smart", "fsharp"];
const RECORD_AND_TUPLE_SYNTAX_TYPES = ["hash", "bar"];
export function validatePlugins(plugins: PluginList) {
if (hasPlugin(plugins, "decorators")) {
if (hasPlugin(plugins, "decorators-legacy")) {
throw new Error(
"Cannot use the decorators and decorators-legacy plugin together",
);
}
const decoratorsBeforeExport = getPluginOption(
plugins,
"decorators",
"decoratorsBeforeExport",
);
if (decoratorsBeforeExport == null) {
throw new Error(
"The 'decorators' plugin requires a 'decoratorsBeforeExport' option," +
" whose value must be a boolean. If you are migrating from" +
" Babylon/Babel 6 or want to use the old decorators proposal, you" +
" should use the 'decorators-legacy' plugin instead of 'decorators'.",
);
} else if (typeof decoratorsBeforeExport !== "boolean") {
throw new Error("'decoratorsBeforeExport' must be a boolean.");
}
}
if (hasPlugin(plugins, "flow") && hasPlugin(plugins, "typescript")) {
throw new Error("Cannot combine flow and typescript plugins.");
}
if (hasPlugin(plugins, "placeholders") && hasPlugin(plugins, "v8intrinsic")) {
throw new Error("Cannot combine placeholders and v8intrinsic plugins.");
}
if (
hasPlugin(plugins, "pipelineOperator") &&
!PIPELINE_PROPOSALS.includes(
getPluginOption(plugins, "pipelineOperator", "proposal"),
)
) {
throw new Error(
"'pipelineOperator' requires 'proposal' option whose value should be one of: " +
PIPELINE_PROPOSALS.map(p => `'${p}'`).join(", "),
);
}
if (hasPlugin(plugins, "moduleAttributes")) {
const moduleAttributesVerionPluginOption = getPluginOption(
plugins,
"moduleAttributes",
"version",
);
if (moduleAttributesVerionPluginOption !== "apr-2020") {
throw new Error(
"The 'moduleAttributes' plugin requires a 'version' option," +
" representing the last proposal update. Currently, the" +
" only supported value is 'apr-2020'.",
);
}
}
if (
hasPlugin(plugins, "recordAndTuple") &&
!RECORD_AND_TUPLE_SYNTAX_TYPES.includes(
getPluginOption(plugins, "recordAndTuple", "syntaxType"),
)
) {
throw new Error(
"'recordAndTuple' requires 'syntaxType' option whose value should be one of: " +
RECORD_AND_TUPLE_SYNTAX_TYPES.map(p => `'${p}'`).join(", "),
);
}
}
// These plugins are defined using a mixin which extends the parser class.
import estree from "./plugins/estree";
import flow from "./plugins/flow";
import jsx from "./plugins/jsx";
import typescript from "./plugins/typescript";
import placeholders from "./plugins/placeholders";
import v8intrinsic from "./plugins/v8intrinsic";
// NOTE: order is important. estree must come first; placeholders must come last.
export const mixinPlugins: { [name: string]: MixinPlugin } = {
estree,
jsx,
flow,
typescript,
v8intrinsic,
placeholders,
};
export const mixinPluginNames: $ReadOnlyArray<string> = Object.keys(
mixinPlugins,
);