1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | "use strict";
|
7 |
|
8 | const DynamicExports = require("./DynamicExports");
|
9 | const HarmonyCompatibilityDependency = require("./HarmonyCompatibilityDependency");
|
10 | const HarmonyExports = require("./HarmonyExports");
|
11 |
|
12 | module.exports = class HarmonyDetectionParserPlugin {
|
13 | constructor(options) {
|
14 | const { topLevelAwait = false } = options || {};
|
15 | this.topLevelAwait = topLevelAwait;
|
16 | }
|
17 |
|
18 | apply(parser) {
|
19 | parser.hooks.program.tap("HarmonyDetectionParserPlugin", ast => {
|
20 | const isStrictHarmony = parser.state.module.type === "javascript/esm";
|
21 | const isHarmony =
|
22 | isStrictHarmony ||
|
23 | ast.body.some(
|
24 | statement =>
|
25 | statement.type === "ImportDeclaration" ||
|
26 | statement.type === "ExportDefaultDeclaration" ||
|
27 | statement.type === "ExportNamedDeclaration" ||
|
28 | statement.type === "ExportAllDeclaration"
|
29 | );
|
30 | if (isHarmony) {
|
31 | const module = parser.state.module;
|
32 | const compatDep = new HarmonyCompatibilityDependency();
|
33 | compatDep.loc = {
|
34 | start: {
|
35 | line: -1,
|
36 | column: 0
|
37 | },
|
38 | end: {
|
39 | line: -1,
|
40 | column: 0
|
41 | },
|
42 | index: -3
|
43 | };
|
44 | module.addPresentationalDependency(compatDep);
|
45 | DynamicExports.bailout(parser.state);
|
46 | HarmonyExports.enable(parser.state, isStrictHarmony);
|
47 | parser.scope.isStrict = true;
|
48 | }
|
49 | });
|
50 |
|
51 | parser.hooks.topLevelAwait.tap("HarmonyDetectionParserPlugin", () => {
|
52 | const module = parser.state.module;
|
53 | if (!this.topLevelAwait) {
|
54 | throw new Error(
|
55 | "The top-level-await experiment is not enabled (set experiments.topLevelAwait: true to enabled it)"
|
56 | );
|
57 | }
|
58 | if (!HarmonyExports.isEnabled(parser.state)) {
|
59 | throw new Error(
|
60 | "Top-level-await is only supported in EcmaScript Modules"
|
61 | );
|
62 | }
|
63 | module.buildMeta.async = true;
|
64 | });
|
65 |
|
66 | const skipInHarmony = () => {
|
67 | if (HarmonyExports.isEnabled(parser.state)) {
|
68 | return true;
|
69 | }
|
70 | };
|
71 |
|
72 | const nullInHarmony = () => {
|
73 | if (HarmonyExports.isEnabled(parser.state)) {
|
74 | return null;
|
75 | }
|
76 | };
|
77 |
|
78 | const nonHarmonyIdentifiers = ["define", "exports"];
|
79 | for (const identifier of nonHarmonyIdentifiers) {
|
80 | parser.hooks.evaluateTypeof
|
81 | .for(identifier)
|
82 | .tap("HarmonyDetectionParserPlugin", nullInHarmony);
|
83 | parser.hooks.typeof
|
84 | .for(identifier)
|
85 | .tap("HarmonyDetectionParserPlugin", skipInHarmony);
|
86 | parser.hooks.evaluate
|
87 | .for(identifier)
|
88 | .tap("HarmonyDetectionParserPlugin", nullInHarmony);
|
89 | parser.hooks.expression
|
90 | .for(identifier)
|
91 | .tap("HarmonyDetectionParserPlugin", skipInHarmony);
|
92 | parser.hooks.call
|
93 | .for(identifier)
|
94 | .tap("HarmonyDetectionParserPlugin", skipInHarmony);
|
95 | }
|
96 | }
|
97 | };
|