HarmonyDetectionParserPlugin.js 2.7 KB

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