HarmonyDetectionParserPlugin.js 2.6 KB

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