HarmonyExportDependencyParserPlugin.js 6.7 KB

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