HarmonyExportDependencyParserPlugin.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const InnerGraph = require("../optimize/InnerGraph");
  7. const ConstDependency = require("./ConstDependency");
  8. const HarmonyExportExpressionDependency = require("./HarmonyExportExpressionDependency");
  9. const HarmonyExportHeaderDependency = require("./HarmonyExportHeaderDependency");
  10. const HarmonyExportImportedSpecifierDependency = require("./HarmonyExportImportedSpecifierDependency");
  11. const HarmonyExportSpecifierDependency = require("./HarmonyExportSpecifierDependency");
  12. const { ExportPresenceModes } = require("./HarmonyImportDependency");
  13. const {
  14. harmonySpecifierTag,
  15. getAssertions
  16. } = require("./HarmonyImportDependencyParserPlugin");
  17. const HarmonyImportSideEffectDependency = require("./HarmonyImportSideEffectDependency");
  18. /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
  19. const { HarmonyStarExportsList } = HarmonyExportImportedSpecifierDependency;
  20. module.exports = class HarmonyExportDependencyParserPlugin {
  21. /**
  22. * @param {import("../../declarations/WebpackOptions").JavascriptParserOptions} options options
  23. */
  24. constructor(options) {
  25. this.exportPresenceMode =
  26. options.reexportExportsPresence !== undefined
  27. ? ExportPresenceModes.fromUserOption(options.reexportExportsPresence)
  28. : options.exportsPresence !== undefined
  29. ? ExportPresenceModes.fromUserOption(options.exportsPresence)
  30. : options.strictExportPresence
  31. ? ExportPresenceModes.ERROR
  32. : ExportPresenceModes.AUTO;
  33. }
  34. apply(parser) {
  35. const { exportPresenceMode } = this;
  36. parser.hooks.export.tap(
  37. "HarmonyExportDependencyParserPlugin",
  38. statement => {
  39. const dep = new HarmonyExportHeaderDependency(
  40. statement.declaration && statement.declaration.range,
  41. statement.range
  42. );
  43. dep.loc = Object.create(statement.loc);
  44. dep.loc.index = -1;
  45. parser.state.module.addPresentationalDependency(dep);
  46. return true;
  47. }
  48. );
  49. parser.hooks.exportImport.tap(
  50. "HarmonyExportDependencyParserPlugin",
  51. (statement, source) => {
  52. parser.state.lastHarmonyImportOrder =
  53. (parser.state.lastHarmonyImportOrder || 0) + 1;
  54. const clearDep = new ConstDependency("", statement.range);
  55. clearDep.loc = Object.create(statement.loc);
  56. clearDep.loc.index = -1;
  57. parser.state.module.addPresentationalDependency(clearDep);
  58. const sideEffectDep = new HarmonyImportSideEffectDependency(
  59. source,
  60. parser.state.lastHarmonyImportOrder,
  61. getAssertions(statement)
  62. );
  63. sideEffectDep.loc = Object.create(statement.loc);
  64. sideEffectDep.loc.index = -1;
  65. parser.state.current.addDependency(sideEffectDep);
  66. return true;
  67. }
  68. );
  69. parser.hooks.exportExpression.tap(
  70. "HarmonyExportDependencyParserPlugin",
  71. (statement, expr) => {
  72. const isFunctionDeclaration = expr.type === "FunctionDeclaration";
  73. const comments = parser.getComments([
  74. statement.range[0],
  75. expr.range[0]
  76. ]);
  77. const dep = new HarmonyExportExpressionDependency(
  78. expr.range,
  79. statement.range,
  80. comments
  81. .map(c => {
  82. switch (c.type) {
  83. case "Block":
  84. return `/*${c.value}*/`;
  85. case "Line":
  86. return `//${c.value}\n`;
  87. }
  88. return "";
  89. })
  90. .join(""),
  91. expr.type.endsWith("Declaration") && expr.id
  92. ? expr.id.name
  93. : isFunctionDeclaration
  94. ? {
  95. id: expr.id ? expr.id.name : undefined,
  96. range: [
  97. expr.range[0],
  98. expr.params.length > 0
  99. ? expr.params[0].range[0]
  100. : expr.body.range[0]
  101. ],
  102. prefix: `${expr.async ? "async " : ""}function${
  103. expr.generator ? "*" : ""
  104. } `,
  105. suffix: `(${expr.params.length > 0 ? "" : ") "}`
  106. }
  107. : undefined
  108. );
  109. dep.loc = Object.create(statement.loc);
  110. dep.loc.index = -1;
  111. parser.state.current.addDependency(dep);
  112. InnerGraph.addVariableUsage(
  113. parser,
  114. expr.type.endsWith("Declaration") && expr.id
  115. ? expr.id.name
  116. : "*default*",
  117. "default"
  118. );
  119. return true;
  120. }
  121. );
  122. parser.hooks.exportSpecifier.tap(
  123. "HarmonyExportDependencyParserPlugin",
  124. (statement, id, name, idx) => {
  125. const settings = parser.getTagData(id, harmonySpecifierTag);
  126. let dep;
  127. const harmonyNamedExports = (parser.state.harmonyNamedExports =
  128. parser.state.harmonyNamedExports || new Set());
  129. harmonyNamedExports.add(name);
  130. InnerGraph.addVariableUsage(parser, id, name);
  131. if (settings) {
  132. dep = new HarmonyExportImportedSpecifierDependency(
  133. settings.source,
  134. settings.sourceOrder,
  135. settings.ids,
  136. name,
  137. harmonyNamedExports,
  138. null,
  139. exportPresenceMode,
  140. null,
  141. settings.assertions
  142. );
  143. } else {
  144. dep = new HarmonyExportSpecifierDependency(id, name);
  145. }
  146. dep.loc = Object.create(statement.loc);
  147. dep.loc.index = idx;
  148. parser.state.current.addDependency(dep);
  149. return true;
  150. }
  151. );
  152. parser.hooks.exportImportSpecifier.tap(
  153. "HarmonyExportDependencyParserPlugin",
  154. (statement, source, id, name, idx) => {
  155. const harmonyNamedExports = (parser.state.harmonyNamedExports =
  156. parser.state.harmonyNamedExports || new Set());
  157. let harmonyStarExports = null;
  158. if (name) {
  159. harmonyNamedExports.add(name);
  160. } else {
  161. harmonyStarExports = parser.state.harmonyStarExports =
  162. parser.state.harmonyStarExports || new HarmonyStarExportsList();
  163. }
  164. const dep = new HarmonyExportImportedSpecifierDependency(
  165. source,
  166. parser.state.lastHarmonyImportOrder,
  167. id ? [id] : [],
  168. name,
  169. harmonyNamedExports,
  170. harmonyStarExports && harmonyStarExports.slice(),
  171. exportPresenceMode,
  172. harmonyStarExports
  173. );
  174. if (harmonyStarExports) {
  175. harmonyStarExports.push(dep);
  176. }
  177. dep.loc = Object.create(statement.loc);
  178. dep.loc.index = idx;
  179. parser.state.current.addDependency(dep);
  180. return true;
  181. }
  182. );
  183. }
  184. };