ImportParserPlugin.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const AsyncDependenciesBlock = require("../AsyncDependenciesBlock");
  7. const {
  8. VariableInfo,
  9. getImportAttributes
  10. } = require("../javascript/JavascriptParser");
  11. const memoize = require("../util/memoize");
  12. const traverseDestructuringAssignmentProperties = require("../util/traverseDestructuringAssignmentProperties");
  13. const ContextDependencyHelpers = require("./ContextDependencyHelpers");
  14. const { getNonOptionalPart } = require("./HarmonyImportDependency");
  15. const HarmonyImportGuard = require("./HarmonyImportGuard");
  16. const ImportContextDependency = require("./ImportContextDependency");
  17. const ImportDependency = require("./ImportDependency");
  18. const ImportEagerDependency = require("./ImportEagerDependency");
  19. const { createGetImportPhase } = require("./ImportPhase");
  20. const ImportWeakDependency = require("./ImportWeakDependency");
  21. const getUnsupportedFeatureWarning = memoize(() =>
  22. require("../errors/UnsupportedFeatureWarning")
  23. );
  24. const getCommentCompilationWarning = memoize(() =>
  25. require("../errors/CommentCompilationWarning")
  26. );
  27. /**
  28. * @import {
  29. * ArrowFunctionExpression,
  30. * FunctionExpression,
  31. * Identifier,
  32. * ObjectPattern,
  33. * CallExpression
  34. * } from "estree"
  35. */
  36. /**
  37. * @import {
  38. * JavascriptParserOptions
  39. * } from "../../declarations/WebpackOptions"
  40. */
  41. /** @import { RawChunkGroupOptions } from "../ChunkGroup" */
  42. /** @import { ContextMode } from "../ContextModule" */
  43. /** @import { RawReferencedExports } from "../Dependency" */
  44. /** @import { BuildMeta } from "../Module" */
  45. /**
  46. * @import JavascriptParser, {
  47. * ImportExpression,
  48. * Range,
  49. * JavascriptParserState
  50. * } from "../javascript/JavascriptParser"
  51. */
  52. /** @typedef {{ references: RawReferencedExports, expression: ImportExpression }} ImportSettings */
  53. /** @typedef {WeakMap<ImportExpression, RawReferencedExports>} State */
  54. /** @type {WeakMap<JavascriptParserState, State>} */
  55. const parserStateMap = new WeakMap();
  56. const dynamicImportTag = Symbol("import()");
  57. /**
  58. * Returns import parser plugin state.
  59. * @param {JavascriptParser} parser javascript parser
  60. * @returns {State} import parser plugin state
  61. */
  62. function getState(parser) {
  63. if (!parserStateMap.has(parser.state)) {
  64. parserStateMap.set(parser.state, new WeakMap());
  65. }
  66. return /** @type {State} */ (parserStateMap.get(parser.state));
  67. }
  68. /**
  69. * Tag dynamic import referenced.
  70. * @param {JavascriptParser} parser javascript parser
  71. * @param {ImportExpression} importCall import expression
  72. * @param {string} variableName variable name
  73. */
  74. function tagDynamicImportReferenced(parser, importCall, variableName) {
  75. const state = getState(parser);
  76. /** @type {RawReferencedExports} */
  77. const references = state.get(importCall) || [];
  78. state.set(importCall, references);
  79. parser.tagVariable(
  80. variableName,
  81. dynamicImportTag,
  82. /** @type {ImportSettings} */ ({
  83. references,
  84. expression: importCall
  85. })
  86. );
  87. }
  88. /**
  89. * Gets fulfilled callback namespace obj.
  90. * @param {CallExpression} importThen import().then() call
  91. * @returns {Identifier | ObjectPattern | undefined} the dynamic imported namespace obj
  92. */
  93. function getFulfilledCallbackNamespaceObj(importThen) {
  94. const fulfilledCallback = importThen.arguments[0];
  95. if (
  96. fulfilledCallback &&
  97. (fulfilledCallback.type === "ArrowFunctionExpression" ||
  98. fulfilledCallback.type === "FunctionExpression") &&
  99. fulfilledCallback.params[0] &&
  100. (fulfilledCallback.params[0].type === "Identifier" ||
  101. fulfilledCallback.params[0].type === "ObjectPattern")
  102. ) {
  103. return fulfilledCallback.params[0];
  104. }
  105. }
  106. /**
  107. * Walk import then fulfilled callback.
  108. * @param {JavascriptParser} parser javascript parser
  109. * @param {ImportExpression} importCall import expression
  110. * @param {ArrowFunctionExpression | FunctionExpression} fulfilledCallback the fulfilled callback
  111. * @param {Identifier | ObjectPattern} namespaceObjArg the argument of namespace object=
  112. */
  113. function walkImportThenFulfilledCallback(
  114. parser,
  115. importCall,
  116. fulfilledCallback,
  117. namespaceObjArg
  118. ) {
  119. const arrow = fulfilledCallback.type === "ArrowFunctionExpression";
  120. const wasTopLevel = parser.scope.topLevelScope;
  121. parser.scope.topLevelScope = arrow ? (wasTopLevel ? "arrow" : false) : false;
  122. const scopeParams = [...fulfilledCallback.params];
  123. // Add function name in scope for recursive calls
  124. if (!arrow && fulfilledCallback.id) {
  125. scopeParams.push(fulfilledCallback.id);
  126. }
  127. parser.inFunctionScope(!arrow, scopeParams, () => {
  128. if (namespaceObjArg.type === "Identifier") {
  129. tagDynamicImportReferenced(parser, importCall, namespaceObjArg.name);
  130. } else {
  131. parser.enterDestructuringAssignment(namespaceObjArg, importCall);
  132. const referencedPropertiesInDestructuring =
  133. parser.destructuringAssignmentPropertiesFor(importCall);
  134. if (referencedPropertiesInDestructuring) {
  135. const state = getState(parser);
  136. const references = /** @type {RawReferencedExports} */ (
  137. state.get(importCall)
  138. );
  139. /** @type {RawReferencedExports} */
  140. const refsInDestructuring = [];
  141. traverseDestructuringAssignmentProperties(
  142. referencedPropertiesInDestructuring,
  143. (stack) => refsInDestructuring.push(stack.map((p) => p.id))
  144. );
  145. for (const ids of refsInDestructuring) {
  146. references.push(ids);
  147. }
  148. }
  149. }
  150. for (const param of fulfilledCallback.params) {
  151. parser.walkPattern(param);
  152. }
  153. if (fulfilledCallback.body.type === "BlockStatement") {
  154. parser.detectMode(fulfilledCallback.body.body);
  155. const prev = parser.prevStatement;
  156. parser.preWalkStatement(fulfilledCallback.body);
  157. parser.prevStatement = prev;
  158. parser.walkStatement(fulfilledCallback.body);
  159. } else {
  160. parser.walkExpression(fulfilledCallback.body);
  161. }
  162. });
  163. parser.scope.topLevelScope = wasTopLevel;
  164. }
  165. /**
  166. * Exports from enumerable.
  167. * @template T
  168. * @param {Iterable<T>} enumerable enumerable
  169. * @returns {T[][]} array of array
  170. */
  171. const exportsFromEnumerable = (enumerable) =>
  172. Array.from(enumerable, (e) => [e]);
  173. const PLUGIN_NAME = "ImportParserPlugin";
  174. /**
  175. * Whether an `import()` second argument is a fully static attributes object
  176. * (every `with`/`assert` value is a string literal). Only then can webpack use
  177. * the attributes at build time; otherwise the argument must be evaluated and
  178. * validated at runtime per spec.
  179. * @param {import("estree").Expression | null | undefined} node the second-argument AST node
  180. * @returns {boolean} true if statically extractable
  181. */
  182. const isStaticStringAttributes = (node) => {
  183. if (!node || node.type !== "ObjectExpression") return false;
  184. for (const prop of node.properties) {
  185. if (prop.type !== "Property" || prop.kind !== "init" || prop.computed) {
  186. return false;
  187. }
  188. const key = prop.key;
  189. const keyName =
  190. key.type === "Identifier"
  191. ? key.name
  192. : key.type === "Literal"
  193. ? key.value
  194. : undefined;
  195. if (keyName === "with" || keyName === "assert") {
  196. const value = prop.value;
  197. if (value.type !== "ObjectExpression") return false;
  198. for (const attr of value.properties) {
  199. if (attr.type !== "Property" || attr.kind !== "init" || attr.computed) {
  200. return false;
  201. }
  202. const attrValue = attr.value;
  203. if (
  204. attrValue.type !== "Literal" ||
  205. typeof attrValue.value !== "string"
  206. ) {
  207. return false;
  208. }
  209. }
  210. }
  211. }
  212. return true;
  213. };
  214. class ImportParserPlugin {
  215. /**
  216. * Creates an instance of ImportParserPlugin.
  217. * @param {JavascriptParserOptions} options options
  218. */
  219. constructor(options) {
  220. /** @type {JavascriptParserOptions} */
  221. this.options = options;
  222. }
  223. /**
  224. * Applies the plugin by registering its hooks on the compiler.
  225. * @param {JavascriptParser} parser the parser
  226. * @returns {void}
  227. */
  228. apply(parser) {
  229. parser.hooks.collectDestructuringAssignmentProperties.tap(
  230. PLUGIN_NAME,
  231. (expr) => {
  232. if (expr.type === "ImportExpression") return true;
  233. const nameInfo = parser.getNameForExpression(expr);
  234. if (
  235. nameInfo &&
  236. nameInfo.rootInfo instanceof VariableInfo &&
  237. nameInfo.rootInfo.name &&
  238. parser.getTagData(nameInfo.rootInfo.name, dynamicImportTag)
  239. ) {
  240. return true;
  241. }
  242. }
  243. );
  244. parser.hooks.preDeclarator.tap(PLUGIN_NAME, (decl) => {
  245. if (
  246. decl.init &&
  247. decl.init.type === "AwaitExpression" &&
  248. decl.init.argument.type === "ImportExpression" &&
  249. decl.id.type === "Identifier"
  250. ) {
  251. parser.defineVariable(decl.id.name);
  252. tagDynamicImportReferenced(parser, decl.init.argument, decl.id.name);
  253. }
  254. });
  255. parser.hooks.expression.for(dynamicImportTag).tap(PLUGIN_NAME, (expr) => {
  256. const settings = /** @type {ImportSettings} */ (parser.currentTagData);
  257. const referencedPropertiesInDestructuring =
  258. parser.destructuringAssignmentPropertiesFor(expr);
  259. if (referencedPropertiesInDestructuring) {
  260. /** @type {RawReferencedExports} */
  261. const refsInDestructuring = [];
  262. traverseDestructuringAssignmentProperties(
  263. referencedPropertiesInDestructuring,
  264. (stack) => refsInDestructuring.push(stack.map((p) => p.id))
  265. );
  266. for (const ids of refsInDestructuring) {
  267. settings.references.push(ids);
  268. }
  269. } else {
  270. settings.references.push([]);
  271. }
  272. return true;
  273. });
  274. parser.hooks.expressionMemberChain
  275. .for(dynamicImportTag)
  276. .tap(PLUGIN_NAME, (_expression, members, membersOptionals) => {
  277. const settings = /** @type {ImportSettings} */ (parser.currentTagData);
  278. const ids = getNonOptionalPart(members, membersOptionals);
  279. settings.references.push(ids);
  280. return true;
  281. });
  282. parser.hooks.callMemberChain
  283. .for(dynamicImportTag)
  284. .tap(PLUGIN_NAME, (expression, members, membersOptionals) => {
  285. const { arguments: args } = expression;
  286. const settings = /** @type {ImportSettings} */ (parser.currentTagData);
  287. let ids = getNonOptionalPart(members, membersOptionals);
  288. const directImport = members.length === 0;
  289. if (
  290. !directImport &&
  291. (this.options.strictThisContextOnImports || ids.length > 1)
  292. ) {
  293. ids = ids.slice(0, -1);
  294. }
  295. settings.references.push(ids);
  296. if (args) parser.walkExpressions(args);
  297. return true;
  298. });
  299. parser.hooks.importCall.tap(PLUGIN_NAME, (expr, importThen) => {
  300. const param = parser.evaluateExpression(expr.source);
  301. /** @type {null | string} */
  302. let chunkName = null;
  303. let mode = /** @type {ContextMode} */ (this.options.dynamicImportMode);
  304. /** @type {null | RegExp} */
  305. let include = null;
  306. /** @type {null | RegExp} */
  307. let exclude = null;
  308. /** @type {null | RawReferencedExports} */
  309. let exports = null;
  310. /** @type {RawChunkGroupOptions} */
  311. const groupOptions = {};
  312. const {
  313. dynamicImportPreload,
  314. dynamicImportCssPreload,
  315. dynamicImportPrefetch,
  316. dynamicImportFetchPriority
  317. } = this.options;
  318. if (
  319. dynamicImportPreload !== undefined &&
  320. dynamicImportPreload !== false
  321. ) {
  322. groupOptions.preloadOrder =
  323. dynamicImportPreload === true ? 0 : dynamicImportPreload;
  324. }
  325. if (
  326. dynamicImportCssPreload !== undefined &&
  327. dynamicImportCssPreload !== false
  328. ) {
  329. groupOptions.cssPreloadOrder =
  330. dynamicImportCssPreload === true ? 0 : dynamicImportCssPreload;
  331. }
  332. if (
  333. dynamicImportPrefetch !== undefined &&
  334. dynamicImportPrefetch !== false
  335. ) {
  336. groupOptions.prefetchOrder =
  337. dynamicImportPrefetch === true ? 0 : dynamicImportPrefetch;
  338. }
  339. if (
  340. dynamicImportFetchPriority !== undefined &&
  341. dynamicImportFetchPriority !== false
  342. ) {
  343. groupOptions.fetchPriority = dynamicImportFetchPriority;
  344. }
  345. const { options: importOptions, errors: commentErrors } =
  346. parser.parseCommentOptions(/** @type {Range} */ (expr.range));
  347. if (commentErrors) {
  348. for (const e of commentErrors) {
  349. const { comment } = e;
  350. parser.state.module.addWarning(
  351. new (getCommentCompilationWarning())(
  352. `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,
  353. parser.getLocation(comment)
  354. )
  355. );
  356. }
  357. }
  358. const phase = createGetImportPhase(
  359. this.options.deferImport,
  360. this.options.sourceImport
  361. )(parser, expr, () => importOptions);
  362. if (importOptions) {
  363. if (importOptions.webpackIgnore !== undefined) {
  364. if (typeof importOptions.webpackIgnore !== "boolean") {
  365. parser.state.module.addWarning(
  366. new (getUnsupportedFeatureWarning())(
  367. `\`webpackIgnore\` expected a boolean, but received: ${importOptions.webpackIgnore}.`,
  368. parser.getLocation(expr)
  369. )
  370. );
  371. } else if (importOptions.webpackIgnore) {
  372. // Do not instrument `import()` if `webpackIgnore` is `true`
  373. return false;
  374. }
  375. }
  376. if (importOptions.webpackChunkName !== undefined) {
  377. if (typeof importOptions.webpackChunkName !== "string") {
  378. parser.state.module.addWarning(
  379. new (getUnsupportedFeatureWarning())(
  380. `\`webpackChunkName\` expected a string, but received: ${importOptions.webpackChunkName}.`,
  381. parser.getLocation(expr)
  382. )
  383. );
  384. } else {
  385. chunkName = importOptions.webpackChunkName;
  386. }
  387. }
  388. if (importOptions.webpackMode !== undefined) {
  389. if (typeof importOptions.webpackMode !== "string") {
  390. parser.state.module.addWarning(
  391. new (getUnsupportedFeatureWarning())(
  392. `\`webpackMode\` expected a string, but received: ${importOptions.webpackMode}.`,
  393. parser.getLocation(expr)
  394. )
  395. );
  396. } else {
  397. mode = /** @type {ContextMode} */ (importOptions.webpackMode);
  398. }
  399. }
  400. if (importOptions.webpackPrefetch !== undefined) {
  401. if (importOptions.webpackPrefetch === true) {
  402. groupOptions.prefetchOrder = 0;
  403. } else if (typeof importOptions.webpackPrefetch === "number") {
  404. groupOptions.prefetchOrder = importOptions.webpackPrefetch;
  405. } else {
  406. parser.state.module.addWarning(
  407. new (getUnsupportedFeatureWarning())(
  408. `\`webpackPrefetch\` expected true or a number, but received: ${importOptions.webpackPrefetch}.`,
  409. parser.getLocation(expr)
  410. )
  411. );
  412. }
  413. }
  414. if (importOptions.webpackPreload !== undefined) {
  415. if (importOptions.webpackPreload === true) {
  416. groupOptions.preloadOrder = 0;
  417. } else if (typeof importOptions.webpackPreload === "number") {
  418. groupOptions.preloadOrder = importOptions.webpackPreload;
  419. } else {
  420. parser.state.module.addWarning(
  421. new (getUnsupportedFeatureWarning())(
  422. `\`webpackPreload\` expected true or a number, but received: ${importOptions.webpackPreload}.`,
  423. parser.getLocation(expr)
  424. )
  425. );
  426. }
  427. }
  428. if (importOptions.webpackFetchPriority !== undefined) {
  429. if (
  430. typeof importOptions.webpackFetchPriority === "string" &&
  431. ["high", "low", "auto"].includes(importOptions.webpackFetchPriority)
  432. ) {
  433. groupOptions.fetchPriority =
  434. /** @type {"low" | "high" | "auto"} */
  435. (importOptions.webpackFetchPriority);
  436. } else {
  437. parser.state.module.addWarning(
  438. new (getUnsupportedFeatureWarning())(
  439. `\`webpackFetchPriority\` expected true or "low", "high" or "auto", but received: ${importOptions.webpackFetchPriority}.`,
  440. parser.getLocation(expr)
  441. )
  442. );
  443. }
  444. }
  445. if (importOptions.webpackInclude !== undefined) {
  446. if (
  447. !importOptions.webpackInclude ||
  448. !(importOptions.webpackInclude instanceof RegExp)
  449. ) {
  450. parser.state.module.addWarning(
  451. new (getUnsupportedFeatureWarning())(
  452. `\`webpackInclude\` expected a regular expression, but received: ${importOptions.webpackInclude}.`,
  453. parser.getLocation(expr)
  454. )
  455. );
  456. } else {
  457. include = importOptions.webpackInclude;
  458. }
  459. }
  460. if (importOptions.webpackExclude !== undefined) {
  461. if (
  462. !importOptions.webpackExclude ||
  463. !(importOptions.webpackExclude instanceof RegExp)
  464. ) {
  465. parser.state.module.addWarning(
  466. new (getUnsupportedFeatureWarning())(
  467. `\`webpackExclude\` expected a regular expression, but received: ${importOptions.webpackExclude}.`,
  468. parser.getLocation(expr)
  469. )
  470. );
  471. } else {
  472. exclude = importOptions.webpackExclude;
  473. }
  474. }
  475. if (importOptions.webpackExports !== undefined) {
  476. if (!(
  477. typeof importOptions.webpackExports === "string" ||
  478. (Array.isArray(importOptions.webpackExports) &&
  479. importOptions.webpackExports.every(
  480. (item) => typeof item === "string"
  481. ))
  482. )) {
  483. parser.state.module.addWarning(
  484. new (getUnsupportedFeatureWarning())(
  485. `\`webpackExports\` expected a string or an array of strings, but received: ${importOptions.webpackExports}.`,
  486. parser.getLocation(expr)
  487. )
  488. );
  489. } else if (typeof importOptions.webpackExports === "string") {
  490. exports = [[importOptions.webpackExports]];
  491. } else {
  492. exports = exportsFromEnumerable(importOptions.webpackExports);
  493. }
  494. }
  495. // `worker` is an internal entry option set only for workers
  496. if (
  497. importOptions.webpackEntryOptions !== undefined &&
  498. typeof importOptions.webpackEntryOptions === "object" &&
  499. importOptions.webpackEntryOptions !== null &&
  500. importOptions.webpackEntryOptions.worker !== undefined
  501. ) {
  502. parser.state.module.addWarning(
  503. new (getUnsupportedFeatureWarning())(
  504. "`worker` entry option is not supported in `import()`, it only applies to workers (e.g. `new Worker(new URL(...))`).",
  505. parser.getLocation(expr)
  506. )
  507. );
  508. }
  509. }
  510. if (
  511. mode !== "lazy" &&
  512. mode !== "lazy-once" &&
  513. mode !== "eager" &&
  514. mode !== "weak"
  515. ) {
  516. parser.state.module.addWarning(
  517. new (getUnsupportedFeatureWarning())(
  518. `\`webpackMode\` expected 'lazy', 'lazy-once', 'eager' or 'weak', but received: ${mode}.`,
  519. parser.getLocation(expr)
  520. )
  521. );
  522. mode = "lazy";
  523. }
  524. const referencedPropertiesInDestructuring =
  525. parser.destructuringAssignmentPropertiesFor(expr);
  526. const state = getState(parser);
  527. const referencedPropertiesInMember = state.get(expr);
  528. const fulfilledNamespaceObj =
  529. importThen && getFulfilledCallbackNamespaceObj(importThen);
  530. if (
  531. referencedPropertiesInDestructuring ||
  532. referencedPropertiesInMember ||
  533. fulfilledNamespaceObj
  534. ) {
  535. if (exports) {
  536. parser.state.module.addWarning(
  537. new (getUnsupportedFeatureWarning())(
  538. "You don't need `webpackExports` if the usage of dynamic import is statically analyse-able. You can safely remove the `webpackExports` magic comment.",
  539. parser.getLocation(expr)
  540. )
  541. );
  542. }
  543. if (referencedPropertiesInDestructuring) {
  544. /** @type {RawReferencedExports} */
  545. const refsInDestructuring = [];
  546. traverseDestructuringAssignmentProperties(
  547. referencedPropertiesInDestructuring,
  548. (stack) => refsInDestructuring.push(stack.map((p) => p.id))
  549. );
  550. exports = refsInDestructuring;
  551. } else if (referencedPropertiesInMember) {
  552. exports = referencedPropertiesInMember;
  553. } else {
  554. /** @type {RawReferencedExports} */
  555. const references = [];
  556. state.set(expr, references);
  557. exports = references;
  558. }
  559. }
  560. if (param.isString()) {
  561. const attributes = getImportAttributes(expr);
  562. if (mode === "eager") {
  563. const dep = new ImportEagerDependency(
  564. /** @type {string} */ (param.string),
  565. /** @type {Range} */ (expr.range),
  566. exports,
  567. phase,
  568. attributes
  569. );
  570. parser.state.current.addDependency(dep);
  571. } else if (mode === "weak") {
  572. const dep = new ImportWeakDependency(
  573. /** @type {string} */ (param.string),
  574. /** @type {Range} */ (expr.range),
  575. exports,
  576. phase,
  577. attributes
  578. );
  579. parser.state.current.addDependency(dep);
  580. } else {
  581. const depBlock = new AsyncDependenciesBlock(
  582. {
  583. ...groupOptions,
  584. name: chunkName
  585. },
  586. parser.getLocation(expr),
  587. param.string
  588. );
  589. // A second argument that isn't a statically extractable attributes
  590. // object still has to be evaluated and validated at runtime, so
  591. // drop the (unreliable) static attributes for it.
  592. const optionsNode = expr.options;
  593. const runtimeValidateOptions = Boolean(
  594. optionsNode && !isStaticStringAttributes(optionsNode)
  595. );
  596. const dep = new ImportDependency(
  597. /** @type {string} */ (param.string),
  598. /** @type {Range} */ (expr.range),
  599. exports,
  600. phase,
  601. runtimeValidateOptions ? undefined : attributes
  602. );
  603. if (runtimeValidateOptions && optionsNode && optionsNode.range) {
  604. dep.optionsRange = /** @type {Range} */ (optionsNode.range);
  605. // The options expression stays in the output, so walk it to
  606. // register its variable references and keep them from being
  607. // tree-shaken away.
  608. parser.walkExpression(optionsNode);
  609. }
  610. dep.loc = parser.getLocation(expr);
  611. dep.optional = Boolean(parser.scope.inTry);
  612. depBlock.addDependency(dep);
  613. parser.state.current.addBlock(depBlock);
  614. HarmonyImportGuard.attachDependencyGuards(parser, dep);
  615. }
  616. } else {
  617. if (mode === "weak") {
  618. mode = "async-weak";
  619. }
  620. const dep = ContextDependencyHelpers.create(
  621. ImportContextDependency,
  622. /** @type {Range} */ (expr.range),
  623. param,
  624. expr,
  625. this.options,
  626. {
  627. chunkName,
  628. groupOptions,
  629. include,
  630. exclude,
  631. mode,
  632. namespaceObject:
  633. /** @type {BuildMeta} */
  634. (parser.state.module.buildMeta).strictHarmonyModule
  635. ? "strict"
  636. : true,
  637. typePrefix: "import()",
  638. category: "esm",
  639. referencedExports: exports,
  640. attributes: getImportAttributes(expr),
  641. phase
  642. },
  643. parser
  644. );
  645. if (!dep) return;
  646. dep.loc = parser.getLocation(expr);
  647. dep.optional = Boolean(parser.scope.inTry);
  648. parser.state.current.addDependency(dep);
  649. }
  650. if (fulfilledNamespaceObj) {
  651. walkImportThenFulfilledCallback(
  652. parser,
  653. expr,
  654. /** @type {ArrowFunctionExpression | FunctionExpression} */
  655. (importThen.arguments[0]),
  656. fulfilledNamespaceObj
  657. );
  658. parser.walkExpressions(importThen.arguments.slice(1));
  659. } else if (importThen) {
  660. parser.walkExpressions(importThen.arguments);
  661. }
  662. return true;
  663. });
  664. }
  665. }
  666. module.exports = ImportParserPlugin;