RequireEnsureDependenciesBlockParserPlugin.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const RequireEnsureDependenciesBlock = require("./RequireEnsureDependenciesBlock");
  7. const RequireEnsureDependency = require("./RequireEnsureDependency");
  8. const RequireEnsureItemDependency = require("./RequireEnsureItemDependency");
  9. const getFunctionExpression = require("./getFunctionExpression");
  10. module.exports = class RequireEnsureDependenciesBlockParserPlugin {
  11. apply(parser) {
  12. parser.hooks.call
  13. .for("require.ensure")
  14. .tap("RequireEnsureDependenciesBlockParserPlugin", expr => {
  15. let chunkName = null;
  16. let errorExpressionArg = null;
  17. let errorExpression = null;
  18. switch (expr.arguments.length) {
  19. case 4: {
  20. const chunkNameExpr = parser.evaluateExpression(expr.arguments[3]);
  21. if (!chunkNameExpr.isString()) return;
  22. chunkName = chunkNameExpr.string;
  23. }
  24. // falls through
  25. case 3: {
  26. errorExpressionArg = expr.arguments[2];
  27. errorExpression = getFunctionExpression(errorExpressionArg);
  28. if (!errorExpression && !chunkName) {
  29. const chunkNameExpr = parser.evaluateExpression(
  30. expr.arguments[2]
  31. );
  32. if (!chunkNameExpr.isString()) return;
  33. chunkName = chunkNameExpr.string;
  34. }
  35. }
  36. // falls through
  37. case 2: {
  38. const dependenciesExpr = parser.evaluateExpression(
  39. expr.arguments[0]
  40. );
  41. const dependenciesItems = dependenciesExpr.isArray()
  42. ? dependenciesExpr.items
  43. : [dependenciesExpr];
  44. const successExpressionArg = expr.arguments[1];
  45. const successExpression =
  46. getFunctionExpression(successExpressionArg);
  47. if (successExpression) {
  48. parser.walkExpressions(successExpression.expressions);
  49. }
  50. if (errorExpression) {
  51. parser.walkExpressions(errorExpression.expressions);
  52. }
  53. const depBlock = new RequireEnsureDependenciesBlock(
  54. chunkName,
  55. expr.loc
  56. );
  57. const errorCallbackExists =
  58. expr.arguments.length === 4 ||
  59. (!chunkName && expr.arguments.length === 3);
  60. const dep = new RequireEnsureDependency(
  61. expr.range,
  62. expr.arguments[1].range,
  63. errorCallbackExists && expr.arguments[2].range
  64. );
  65. dep.loc = expr.loc;
  66. depBlock.addDependency(dep);
  67. const old = parser.state.current;
  68. parser.state.current = depBlock;
  69. try {
  70. let failed = false;
  71. parser.inScope([], () => {
  72. for (const ee of dependenciesItems) {
  73. if (ee.isString()) {
  74. const ensureDependency = new RequireEnsureItemDependency(
  75. ee.string
  76. );
  77. ensureDependency.loc = ee.loc || expr.loc;
  78. depBlock.addDependency(ensureDependency);
  79. } else {
  80. failed = true;
  81. }
  82. }
  83. });
  84. if (failed) {
  85. return;
  86. }
  87. if (successExpression) {
  88. if (successExpression.fn.body.type === "BlockStatement") {
  89. parser.walkStatement(successExpression.fn.body);
  90. } else {
  91. parser.walkExpression(successExpression.fn.body);
  92. }
  93. }
  94. old.addBlock(depBlock);
  95. } finally {
  96. parser.state.current = old;
  97. }
  98. if (!successExpression) {
  99. parser.walkExpression(successExpressionArg);
  100. }
  101. if (errorExpression) {
  102. if (errorExpression.fn.body.type === "BlockStatement") {
  103. parser.walkStatement(errorExpression.fn.body);
  104. } else {
  105. parser.walkExpression(errorExpression.fn.body);
  106. }
  107. } else if (errorExpressionArg) {
  108. parser.walkExpression(errorExpressionArg);
  109. }
  110. return true;
  111. }
  112. }
  113. });
  114. }
  115. };