CommonJsImportsParserPlugin.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const CommentCompilationWarning = require("../CommentCompilationWarning");
  7. const RuntimeGlobals = require("../RuntimeGlobals");
  8. const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");
  9. const {
  10. evaluateToIdentifier,
  11. evaluateToString,
  12. expressionIsUnsupported,
  13. toConstantDependency
  14. } = require("../javascript/JavascriptParserHelpers");
  15. const traverseDestructuringAssignmentProperties = require("../util/traverseDestructuringAssignmentProperties");
  16. const CommonJsFullRequireDependency = require("./CommonJsFullRequireDependency");
  17. const CommonJsRequireContextDependency = require("./CommonJsRequireContextDependency");
  18. const CommonJsRequireDependency = require("./CommonJsRequireDependency");
  19. const ConstDependency = require("./ConstDependency");
  20. const ContextDependencyHelpers = require("./ContextDependencyHelpers");
  21. const LocalModuleDependency = require("./LocalModuleDependency");
  22. const { getLocalModule } = require("./LocalModulesHelpers");
  23. const RequireHeaderDependency = require("./RequireHeaderDependency");
  24. const RequireResolveContextDependency = require("./RequireResolveContextDependency");
  25. const RequireResolveDependency = require("./RequireResolveDependency");
  26. const RequireResolveHeaderDependency = require("./RequireResolveHeaderDependency");
  27. /** @typedef {import("estree").CallExpression} CallExpression */
  28. /** @typedef {import("estree").Expression} Expression */
  29. /** @typedef {import("estree").NewExpression} NewExpression */
  30. /** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
  31. /** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
  32. /** @typedef {import("../Dependency").RawReferencedExports} RawReferencedExports */
  33. /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
  34. /** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
  35. /** @typedef {import("../javascript/JavascriptParser").ImportSource} ImportSource */
  36. /** @typedef {import("../javascript/JavascriptParser").Range} Range */
  37. /** @typedef {import("../javascript/JavascriptParser").Members} Members */
  38. /** @typedef {import("../javascript/JavascriptParser").CalleeMembers} CalleeMembers */
  39. /** @typedef {import("./LocalModule")} LocalModule */
  40. /**
  41. * Defines the common js import settings type used by this module.
  42. * @typedef {object} CommonJsImportSettings
  43. * @property {string=} name
  44. * @property {string} context
  45. */
  46. const PLUGIN_NAME = "CommonJsImportsParserPlugin";
  47. /**
  48. * Checks whether this object is require call expression.
  49. * @param {Expression} expression expression
  50. * @returns {boolean} true, when expression is `require(...)` or `module.require(...)`
  51. */
  52. const isRequireCallExpression = (expression) => {
  53. if (expression.type !== "CallExpression") return false;
  54. const { callee } = expression;
  55. if (callee.type === "Identifier") {
  56. return callee.name === "require";
  57. }
  58. if (callee.type === "MemberExpression" && !callee.computed) {
  59. const object = callee.object;
  60. const property = callee.property;
  61. return (
  62. object.type === "Identifier" &&
  63. object.name === "module" &&
  64. property.type === "Identifier" &&
  65. property.name === "require"
  66. );
  67. }
  68. return false;
  69. };
  70. /**
  71. * Gets require referenced exports from destructuring.
  72. * @param {JavascriptParser} parser parser
  73. * @param {CallExpression | NewExpression} expr expression
  74. * @returns {RawReferencedExports | null} referenced exports from destructuring
  75. */
  76. const getRequireReferencedExportsFromDestructuring = (parser, expr) => {
  77. const referencedPropertiesInDestructuring =
  78. parser.destructuringAssignmentPropertiesFor(expr);
  79. if (!referencedPropertiesInDestructuring) return null;
  80. /** @type {RawReferencedExports} */
  81. const referencedExports = [];
  82. traverseDestructuringAssignmentProperties(
  83. referencedPropertiesInDestructuring,
  84. (stack) => referencedExports.push(stack.map((p) => p.id))
  85. );
  86. return referencedExports;
  87. };
  88. /**
  89. * Creates a require cache dependency.
  90. * @param {JavascriptParser} parser parser
  91. * @returns {(expr: Expression) => boolean} handler
  92. */
  93. const createRequireCacheDependency = (parser) =>
  94. toConstantDependency(parser, RuntimeGlobals.moduleCache, [
  95. RuntimeGlobals.moduleCache,
  96. RuntimeGlobals.moduleId,
  97. RuntimeGlobals.moduleLoaded
  98. ]);
  99. /**
  100. * Creates a require as expression handler.
  101. * @param {JavascriptParser} parser parser
  102. * @param {JavascriptParserOptions} options options
  103. * @param {() => undefined | string} getContext context accessor
  104. * @returns {(expr: Expression) => boolean} handler
  105. */
  106. const createRequireAsExpressionHandler =
  107. (parser, options, getContext) => (expr) => {
  108. const dep = new CommonJsRequireContextDependency(
  109. {
  110. request: /** @type {string} */ (options.unknownContextRequest),
  111. recursive: /** @type {boolean} */ (options.unknownContextRecursive),
  112. regExp: /** @type {RegExp} */ (options.unknownContextRegExp),
  113. mode: "sync"
  114. },
  115. /** @type {Range} */ (expr.range),
  116. undefined,
  117. parser.scope.inShorthand,
  118. getContext()
  119. );
  120. dep.critical =
  121. options.unknownContextCritical &&
  122. "require function is used in a way in which dependencies cannot be statically extracted";
  123. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  124. dep.optional = Boolean(parser.scope.inTry);
  125. parser.state.current.addDependency(dep);
  126. return true;
  127. };
  128. /**
  129. * Creates a require call handler.
  130. * @param {JavascriptParser} parser parser
  131. * @param {JavascriptParserOptions} options options
  132. * @param {() => undefined | string} getContext context accessor
  133. * @returns {(callNew: boolean) => (expr: CallExpression | NewExpression) => (boolean | void)} handler factory
  134. */
  135. const createRequireCallHandler = (parser, options, getContext) => {
  136. /**
  137. * Process require item.
  138. * @param {CallExpression | NewExpression} expr expression
  139. * @param {BasicEvaluatedExpression} param param
  140. * @returns {boolean | void} true when handled
  141. */
  142. const processRequireItem = (expr, param) => {
  143. if (param.isString()) {
  144. const referencedExports = getRequireReferencedExportsFromDestructuring(
  145. parser,
  146. expr
  147. );
  148. const dep = new CommonJsRequireDependency(
  149. /** @type {string} */ (param.string),
  150. /** @type {Range} */ (param.range),
  151. getContext(),
  152. referencedExports
  153. );
  154. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  155. dep.optional = Boolean(parser.scope.inTry);
  156. parser.state.current.addDependency(dep);
  157. return true;
  158. }
  159. };
  160. /**
  161. * Process require context.
  162. * @param {CallExpression | NewExpression} expr expression
  163. * @param {BasicEvaluatedExpression} param param
  164. * @returns {boolean | void} true when handled
  165. */
  166. const processRequireContext = (expr, param) => {
  167. const referencedExports = getRequireReferencedExportsFromDestructuring(
  168. parser,
  169. expr
  170. );
  171. const dep = ContextDependencyHelpers.create(
  172. CommonJsRequireContextDependency,
  173. /** @type {Range} */ (expr.range),
  174. param,
  175. expr,
  176. options,
  177. {
  178. category: "commonjs",
  179. referencedExports
  180. },
  181. parser,
  182. undefined,
  183. getContext()
  184. );
  185. if (!dep) return;
  186. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  187. dep.optional = Boolean(parser.scope.inTry);
  188. parser.state.current.addDependency(dep);
  189. return true;
  190. };
  191. return (callNew) => (expr) => {
  192. if (options.commonjsMagicComments) {
  193. const { options: requireOptions, errors: commentErrors } =
  194. parser.parseCommentOptions(/** @type {Range} */ (expr.range));
  195. if (commentErrors) {
  196. for (const e of commentErrors) {
  197. const { comment } = e;
  198. parser.state.module.addWarning(
  199. new CommentCompilationWarning(
  200. `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,
  201. /** @type {DependencyLocation} */ (comment.loc)
  202. )
  203. );
  204. }
  205. }
  206. if (requireOptions && requireOptions.webpackIgnore !== undefined) {
  207. if (typeof requireOptions.webpackIgnore !== "boolean") {
  208. parser.state.module.addWarning(
  209. new UnsupportedFeatureWarning(
  210. `\`webpackIgnore\` expected a boolean, but received: ${requireOptions.webpackIgnore}.`,
  211. /** @type {DependencyLocation} */ (expr.loc)
  212. )
  213. );
  214. } else if (requireOptions.webpackIgnore) {
  215. // Do not instrument `require()` if `webpackIgnore` is `true`
  216. return true;
  217. }
  218. }
  219. }
  220. if (expr.arguments.length !== 1) return;
  221. /** @type {null | LocalModule} */
  222. let localModule;
  223. const param = parser.evaluateExpression(expr.arguments[0]);
  224. if (param.isConditional()) {
  225. let isExpression = false;
  226. for (const p of /** @type {BasicEvaluatedExpression[]} */ (
  227. param.options
  228. )) {
  229. const result = processRequireItem(expr, p);
  230. if (result === undefined) {
  231. isExpression = true;
  232. }
  233. }
  234. if (!isExpression) {
  235. const dep = new RequireHeaderDependency(
  236. /** @type {Range} */ (expr.callee.range)
  237. );
  238. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  239. parser.state.module.addPresentationalDependency(dep);
  240. return true;
  241. }
  242. }
  243. if (
  244. param.isString() &&
  245. (localModule = getLocalModule(
  246. parser.state,
  247. /** @type {string} */ (param.string)
  248. ))
  249. ) {
  250. localModule.flagUsed();
  251. const dep = new LocalModuleDependency(
  252. localModule,
  253. /** @type {Range} */ (expr.range),
  254. callNew
  255. );
  256. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  257. parser.state.module.addPresentationalDependency(dep);
  258. } else {
  259. const result = processRequireItem(expr, param);
  260. if (result === undefined) {
  261. processRequireContext(expr, param);
  262. } else {
  263. const dep = new RequireHeaderDependency(
  264. /** @type {Range} */ (expr.callee.range)
  265. );
  266. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  267. parser.state.module.addPresentationalDependency(dep);
  268. }
  269. }
  270. return true;
  271. };
  272. };
  273. /**
  274. * Creates a process resolve handler.
  275. * @param {JavascriptParser} parser parser
  276. * @param {JavascriptParserOptions} options options
  277. * @param {() => undefined | string} getContext context accessor
  278. * @returns {(expr: CallExpression, weak: boolean) => (boolean | void)} resolver
  279. */
  280. const createProcessResolveHandler = (parser, options, getContext) => {
  281. /**
  282. * Process resolve item.
  283. * @param {CallExpression} expr call expression
  284. * @param {BasicEvaluatedExpression} param param
  285. * @param {boolean} weak weak
  286. * @returns {boolean | void} true when handled
  287. */
  288. const processResolveItem = (expr, param, weak) => {
  289. if (param.isString()) {
  290. const dep = new RequireResolveDependency(
  291. /** @type {string} */ (param.string),
  292. /** @type {Range} */ (param.range),
  293. getContext()
  294. );
  295. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  296. dep.optional = Boolean(parser.scope.inTry);
  297. dep.weak = weak;
  298. parser.state.current.addDependency(dep);
  299. return true;
  300. }
  301. };
  302. /**
  303. * Process resolve context.
  304. * @param {CallExpression} expr call expression
  305. * @param {BasicEvaluatedExpression} param param
  306. * @param {boolean} weak weak
  307. * @returns {boolean | void} true when handled
  308. */
  309. const processResolveContext = (expr, param, weak) => {
  310. const dep = ContextDependencyHelpers.create(
  311. RequireResolveContextDependency,
  312. /** @type {Range} */ (param.range),
  313. param,
  314. expr,
  315. options,
  316. {
  317. category: "commonjs",
  318. mode: weak ? "weak" : "sync"
  319. },
  320. parser,
  321. getContext()
  322. );
  323. if (!dep) return;
  324. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  325. dep.optional = Boolean(parser.scope.inTry);
  326. parser.state.current.addDependency(dep);
  327. return true;
  328. };
  329. return (expr, weak) => {
  330. if (!weak && options.commonjsMagicComments) {
  331. const { options: requireOptions, errors: commentErrors } =
  332. parser.parseCommentOptions(/** @type {Range} */ (expr.range));
  333. if (commentErrors) {
  334. for (const e of commentErrors) {
  335. const { comment } = e;
  336. parser.state.module.addWarning(
  337. new CommentCompilationWarning(
  338. `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,
  339. /** @type {DependencyLocation} */ (comment.loc)
  340. )
  341. );
  342. }
  343. }
  344. if (requireOptions && requireOptions.webpackIgnore !== undefined) {
  345. if (typeof requireOptions.webpackIgnore !== "boolean") {
  346. parser.state.module.addWarning(
  347. new UnsupportedFeatureWarning(
  348. `\`webpackIgnore\` expected a boolean, but received: ${requireOptions.webpackIgnore}.`,
  349. /** @type {DependencyLocation} */ (expr.loc)
  350. )
  351. );
  352. } else if (requireOptions.webpackIgnore) {
  353. // Do not instrument `require()` if `webpackIgnore` is `true`
  354. return true;
  355. }
  356. }
  357. }
  358. if (expr.arguments.length !== 1) return;
  359. const param = parser.evaluateExpression(expr.arguments[0]);
  360. if (param.isConditional()) {
  361. for (const option of /** @type {BasicEvaluatedExpression[]} */ (
  362. param.options
  363. )) {
  364. const result = processResolveItem(expr, option, weak);
  365. if (result === undefined) {
  366. processResolveContext(expr, option, weak);
  367. }
  368. }
  369. const dep = new RequireResolveHeaderDependency(
  370. /** @type {Range} */ (expr.callee.range)
  371. );
  372. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  373. parser.state.module.addPresentationalDependency(dep);
  374. return true;
  375. }
  376. const result = processResolveItem(expr, param, weak);
  377. if (result === undefined) {
  378. processResolveContext(expr, param, weak);
  379. }
  380. const dep = new RequireResolveHeaderDependency(
  381. /** @type {Range} */ (expr.callee.range)
  382. );
  383. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  384. parser.state.module.addPresentationalDependency(dep);
  385. return true;
  386. };
  387. };
  388. class CommonJsImportsParserPlugin {
  389. /**
  390. * Creates an instance of CommonJsImportsParserPlugin.
  391. * @param {JavascriptParserOptions} options parser options
  392. */
  393. constructor(options) {
  394. this.options = options;
  395. }
  396. /**
  397. * Applies the plugin by registering its hooks on the compiler.
  398. * @param {JavascriptParser} parser the parser
  399. * @returns {void}
  400. */
  401. apply(parser) {
  402. const options = this.options;
  403. parser.hooks.collectDestructuringAssignmentProperties.tap(
  404. PLUGIN_NAME,
  405. (expr) => {
  406. if (isRequireCallExpression(expr)) return true;
  407. }
  408. );
  409. const getContext = () => {
  410. if (parser.currentTagData) {
  411. const { context } =
  412. /** @type {CommonJsImportSettings} */
  413. (parser.currentTagData);
  414. return context;
  415. }
  416. };
  417. // #region metadata
  418. /**
  419. * Tap require expression.
  420. * @param {string} expression expression
  421. * @param {() => Members} getMembers get members
  422. */
  423. const tapRequireExpression = (expression, getMembers) => {
  424. parser.hooks.typeof
  425. .for(expression)
  426. .tap(
  427. PLUGIN_NAME,
  428. toConstantDependency(parser, JSON.stringify("function"))
  429. );
  430. parser.hooks.evaluateTypeof
  431. .for(expression)
  432. .tap(PLUGIN_NAME, evaluateToString("function"));
  433. parser.hooks.evaluateIdentifier
  434. .for(expression)
  435. .tap(
  436. PLUGIN_NAME,
  437. evaluateToIdentifier(expression, "require", getMembers, true)
  438. );
  439. };
  440. tapRequireExpression("require", () => []);
  441. tapRequireExpression("require.resolve", () => ["resolve"]);
  442. tapRequireExpression("require.resolveWeak", () => ["resolveWeak"]);
  443. // #endregion
  444. // Weird stuff //
  445. parser.hooks.assign.for("require").tap(PLUGIN_NAME, (expr) => {
  446. // to not leak to global "require", we need to define a local require here.
  447. const dep = new ConstDependency("var require;", 0);
  448. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  449. parser.state.module.addPresentationalDependency(dep);
  450. return true;
  451. });
  452. // #region Unsupported
  453. parser.hooks.call
  454. .for("require.main.require")
  455. .tap(
  456. PLUGIN_NAME,
  457. expressionIsUnsupported(
  458. parser,
  459. "require.main.require is not supported by webpack."
  460. )
  461. );
  462. parser.hooks.expression
  463. .for("module.parent.require")
  464. .tap(
  465. PLUGIN_NAME,
  466. expressionIsUnsupported(
  467. parser,
  468. "module.parent.require is not supported by webpack."
  469. )
  470. );
  471. parser.hooks.call
  472. .for("module.parent.require")
  473. .tap(
  474. PLUGIN_NAME,
  475. expressionIsUnsupported(
  476. parser,
  477. "module.parent.require is not supported by webpack."
  478. )
  479. );
  480. // #endregion
  481. // #region Renaming
  482. /**
  483. * Returns true when set undefined.
  484. * @param {Expression} expr expression
  485. * @returns {boolean} true when set undefined
  486. */
  487. const defineUndefined = (expr) => {
  488. // To avoid "not defined" error, replace the value with undefined
  489. const dep = new ConstDependency(
  490. "undefined",
  491. /** @type {Range} */ (expr.range)
  492. );
  493. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  494. parser.state.module.addPresentationalDependency(dep);
  495. return false;
  496. };
  497. parser.hooks.canRename.for("require").tap(PLUGIN_NAME, () => true);
  498. parser.hooks.rename.for("require").tap(PLUGIN_NAME, defineUndefined);
  499. // #endregion
  500. // #region Inspection
  501. const requireCache = createRequireCacheDependency(parser);
  502. parser.hooks.expression.for("require.cache").tap(PLUGIN_NAME, requireCache);
  503. // #endregion
  504. // #region Require as expression
  505. /**
  506. * Require as expression handler.
  507. * @param {Expression} expr expression
  508. * @returns {boolean} true when handled
  509. */
  510. const requireAsExpressionHandler = createRequireAsExpressionHandler(
  511. parser,
  512. options,
  513. getContext
  514. );
  515. parser.hooks.expression
  516. .for("require")
  517. .tap(PLUGIN_NAME, requireAsExpressionHandler);
  518. // #endregion
  519. // #region Require
  520. /**
  521. * Creates a require handler.
  522. * @param {boolean} callNew true, when require is called with new
  523. * @returns {(expr: CallExpression | NewExpression) => (boolean | void)} handler
  524. */
  525. const createRequireHandler = createRequireCallHandler(
  526. parser,
  527. options,
  528. getContext
  529. );
  530. parser.hooks.call
  531. .for("require")
  532. .tap(PLUGIN_NAME, createRequireHandler(false));
  533. parser.hooks.new
  534. .for("require")
  535. .tap(PLUGIN_NAME, createRequireHandler(true));
  536. parser.hooks.call
  537. .for("module.require")
  538. .tap(PLUGIN_NAME, createRequireHandler(false));
  539. parser.hooks.new
  540. .for("module.require")
  541. .tap(PLUGIN_NAME, createRequireHandler(true));
  542. // #endregion
  543. // #region Require with property access
  544. /**
  545. * Returns true when handled.
  546. * @param {Expression} expr expression
  547. * @param {CalleeMembers} calleeMembers callee members
  548. * @param {CallExpression} callExpr call expression
  549. * @param {Members} members members
  550. * @param {Range[]} memberRanges member ranges
  551. * @returns {boolean | void} true when handled
  552. */
  553. const chainHandler = (
  554. expr,
  555. calleeMembers,
  556. callExpr,
  557. members,
  558. memberRanges
  559. ) => {
  560. if (callExpr.arguments.length !== 1) return;
  561. const param = parser.evaluateExpression(callExpr.arguments[0]);
  562. if (
  563. param.isString() &&
  564. !getLocalModule(parser.state, /** @type {string} */ (param.string))
  565. ) {
  566. const dep = new CommonJsFullRequireDependency(
  567. /** @type {string} */ (param.string),
  568. /** @type {Range} */ (expr.range),
  569. members,
  570. /** @type {Range[]} */ memberRanges
  571. );
  572. dep.asiSafe = !parser.isAsiPosition(
  573. /** @type {Range} */ (expr.range)[0]
  574. );
  575. dep.optional = Boolean(parser.scope.inTry);
  576. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  577. parser.state.current.addDependency(dep);
  578. return true;
  579. }
  580. };
  581. /**
  582. * Call chain handler.
  583. * @param {CallExpression} expr expression
  584. * @param {CalleeMembers} calleeMembers callee members
  585. * @param {CallExpression} callExpr call expression
  586. * @param {Members} members members
  587. * @param {Range[]} memberRanges member ranges
  588. * @returns {boolean | void} true when handled
  589. */
  590. const callChainHandler = (
  591. expr,
  592. calleeMembers,
  593. callExpr,
  594. members,
  595. memberRanges
  596. ) => {
  597. if (callExpr.arguments.length !== 1) return;
  598. const param = parser.evaluateExpression(callExpr.arguments[0]);
  599. if (
  600. param.isString() &&
  601. !getLocalModule(parser.state, /** @type {string} */ (param.string))
  602. ) {
  603. const dep = new CommonJsFullRequireDependency(
  604. /** @type {string} */ (param.string),
  605. /** @type {Range} */ (expr.callee.range),
  606. members,
  607. /** @type {Range[]} */ memberRanges
  608. );
  609. dep.call = true;
  610. dep.asiSafe = !parser.isAsiPosition(
  611. /** @type {Range} */ (expr.range)[0]
  612. );
  613. dep.optional = Boolean(parser.scope.inTry);
  614. dep.loc = /** @type {DependencyLocation} */ (expr.callee.loc);
  615. parser.state.current.addDependency(dep);
  616. parser.walkExpressions(expr.arguments);
  617. return true;
  618. }
  619. };
  620. parser.hooks.memberChainOfCallMemberChain
  621. .for("require")
  622. .tap(PLUGIN_NAME, chainHandler);
  623. parser.hooks.memberChainOfCallMemberChain
  624. .for("module.require")
  625. .tap(PLUGIN_NAME, chainHandler);
  626. parser.hooks.callMemberChainOfCallMemberChain
  627. .for("require")
  628. .tap(PLUGIN_NAME, callChainHandler);
  629. parser.hooks.callMemberChainOfCallMemberChain
  630. .for("module.require")
  631. .tap(PLUGIN_NAME, callChainHandler);
  632. // #endregion
  633. // #region Require.resolve
  634. /**
  635. * Processes the provided expr.
  636. * @param {CallExpression} expr call expression
  637. * @param {boolean} weak weak
  638. * @returns {boolean | void} true when handled
  639. */
  640. const processResolve = createProcessResolveHandler(
  641. parser,
  642. options,
  643. getContext
  644. );
  645. parser.hooks.call
  646. .for("require.resolve")
  647. .tap(PLUGIN_NAME, (expr) => processResolve(expr, false));
  648. parser.hooks.call
  649. .for("require.resolveWeak")
  650. .tap(PLUGIN_NAME, (expr) => processResolve(expr, true));
  651. // #endregion
  652. }
  653. }
  654. module.exports = CommonJsImportsParserPlugin;
  655. module.exports.createProcessResolveHandler = createProcessResolveHandler;
  656. module.exports.createRequireAsExpressionHandler =
  657. createRequireAsExpressionHandler;
  658. module.exports.createRequireCacheDependency = createRequireCacheDependency;
  659. module.exports.createRequireHandler = createRequireCallHandler;