| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Ivan Kopeykin @vankop | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-28 23:51:48 +08:00
										 |  |  | const { pathToFileURL } = require("url"); | 
					
						
							| 
									
										
										
										
											2024-08-14 21:58:10 +08:00
										 |  |  | const CommentCompilationWarning = require("../CommentCompilationWarning"); | 
					
						
							| 
									
										
										
										
											2023-04-01 01:56:32 +08:00
										 |  |  | const { | 
					
						
							|  |  |  | 	JAVASCRIPT_MODULE_TYPE_AUTO, | 
					
						
							|  |  |  | 	JAVASCRIPT_MODULE_TYPE_ESM | 
					
						
							|  |  |  | } = require("../ModuleTypeConstants"); | 
					
						
							| 
									
										
										
										
											2024-08-14 21:58:10 +08:00
										 |  |  | const RuntimeGlobals = require("../RuntimeGlobals"); | 
					
						
							|  |  |  | const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning"); | 
					
						
							| 
									
										
										
										
											2022-03-28 23:51:48 +08:00
										 |  |  | const BasicEvaluatedExpression = require("../javascript/BasicEvaluatedExpression"); | 
					
						
							| 
									
										
										
										
											2020-08-29 05:20:22 +08:00
										 |  |  | const { approve } = require("../javascript/JavascriptParserHelpers"); | 
					
						
							| 
									
										
										
										
											2021-01-19 20:31:55 +08:00
										 |  |  | const InnerGraph = require("../optimize/InnerGraph"); | 
					
						
							| 
									
										
										
										
											2024-08-14 21:58:10 +08:00
										 |  |  | const ConstDependency = require("./ConstDependency"); | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | const URLDependency = require("./URLDependency"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-02 05:18:10 +08:00
										 |  |  | /** @typedef {import("estree").MemberExpression} MemberExpression */ | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | /** @typedef {import("estree").NewExpression} NewExpressionNode */ | 
					
						
							| 
									
										
										
										
											2023-05-22 08:03:05 +08:00
										 |  |  | /** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */ | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | /** @typedef {import("../Compiler")} Compiler */ | 
					
						
							| 
									
										
										
										
											2023-06-18 02:36:03 +08:00
										 |  |  | /** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */ | 
					
						
							| 
									
										
										
										
											2022-03-28 23:51:48 +08:00
										 |  |  | /** @typedef {import("../NormalModule")} NormalModule */ | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */ | 
					
						
							| 
									
										
										
										
											2023-05-22 08:03:05 +08:00
										 |  |  | /** @typedef {import("../javascript/JavascriptParser")} Parser */ | 
					
						
							| 
									
										
										
										
											2023-06-18 02:36:03 +08:00
										 |  |  | /** @typedef {import("../javascript/JavascriptParser").Range} Range */ | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-01 01:56:32 +08:00
										 |  |  | const PLUGIN_NAME = "URLPlugin"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | class URLPlugin { | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {Compiler} compiler compiler | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	apply(compiler) { | 
					
						
							|  |  |  | 		compiler.hooks.compilation.tap( | 
					
						
							| 
									
										
										
										
											2023-04-01 01:56:32 +08:00
										 |  |  | 			PLUGIN_NAME, | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | 			(compilation, { normalModuleFactory }) => { | 
					
						
							|  |  |  | 				compilation.dependencyFactories.set(URLDependency, normalModuleFactory); | 
					
						
							|  |  |  | 				compilation.dependencyTemplates.set( | 
					
						
							|  |  |  | 					URLDependency, | 
					
						
							|  |  |  | 					new URLDependency.Template() | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-28 23:51:48 +08:00
										 |  |  | 				/** | 
					
						
							|  |  |  | 				 * @param {NormalModule} module module | 
					
						
							|  |  |  | 				 * @returns {URL} file url | 
					
						
							|  |  |  | 				 */ | 
					
						
							| 
									
										
										
										
											2024-07-31 11:31:11 +08:00
										 |  |  | 				const getUrl = module => pathToFileURL(module.resource); | 
					
						
							| 
									
										
										
										
											2023-05-22 08:03:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-02 05:18:10 +08:00
										 |  |  | 				/** | 
					
						
							|  |  |  | 				 * @param {Parser} parser parser parser | 
					
						
							|  |  |  | 				 * @param {MemberExpression} arg arg | 
					
						
							|  |  |  | 				 * @returns {boolean} true when it is `meta.url`, otherwise false | 
					
						
							|  |  |  | 				 */ | 
					
						
							| 
									
										
										
										
											2024-08-14 21:58:10 +08:00
										 |  |  | 				const isMetaUrl = (parser, arg) => { | 
					
						
							|  |  |  | 					const chain = parser.extractMemberExpressionChain(arg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if ( | 
					
						
							|  |  |  | 						chain.members.length !== 1 || | 
					
						
							|  |  |  | 						chain.object.type !== "MetaProperty" || | 
					
						
							|  |  |  | 						chain.object.meta.name !== "import" || | 
					
						
							|  |  |  | 						chain.object.property.name !== "meta" || | 
					
						
							|  |  |  | 						chain.members[0] !== "url" | 
					
						
							|  |  |  | 					) | 
					
						
							|  |  |  | 						return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					return true; | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | 				/** | 
					
						
							| 
									
										
										
										
											2023-05-22 08:03:05 +08:00
										 |  |  | 				 * @param {Parser} parser parser parser | 
					
						
							|  |  |  | 				 * @param {JavascriptParserOptions} parserOptions parserOptions | 
					
						
							|  |  |  | 				 * @returns {void} | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | 				 */ | 
					
						
							| 
									
										
										
										
											2020-09-02 21:08:10 +08:00
										 |  |  | 				const parserCallback = (parser, parserOptions) => { | 
					
						
							|  |  |  | 					if (parserOptions.url === false) return; | 
					
						
							| 
									
										
										
										
											2021-02-16 23:05:47 +08:00
										 |  |  | 					const relative = parserOptions.url === "relative"; | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-19 20:31:55 +08:00
										 |  |  | 					/** | 
					
						
							|  |  |  | 					 * @param {NewExpressionNode} expr expression | 
					
						
							|  |  |  | 					 * @returns {undefined | string} request | 
					
						
							|  |  |  | 					 */ | 
					
						
							|  |  |  | 					const getUrlRequest = expr => { | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | 						if (expr.arguments.length !== 2) return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						const [arg1, arg2] = expr.arguments; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						if ( | 
					
						
							|  |  |  | 							arg2.type !== "MemberExpression" || | 
					
						
							|  |  |  | 							arg1.type === "SpreadElement" | 
					
						
							|  |  |  | 						) | 
					
						
							|  |  |  | 							return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-14 21:58:10 +08:00
										 |  |  | 						if (!isMetaUrl(parser, arg2)) return; | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-22 08:03:05 +08:00
										 |  |  | 						return parser.evaluateExpression(arg1).asString(); | 
					
						
							| 
									
										
										
										
											2021-01-19 20:31:55 +08:00
										 |  |  | 					}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-01 01:56:32 +08:00
										 |  |  | 					parser.hooks.canRename.for("URL").tap(PLUGIN_NAME, approve); | 
					
						
							| 
									
										
										
										
											2022-03-28 23:51:48 +08:00
										 |  |  | 					parser.hooks.evaluateNewExpression | 
					
						
							|  |  |  | 						.for("URL") | 
					
						
							| 
									
										
										
										
											2023-04-01 01:56:32 +08:00
										 |  |  | 						.tap(PLUGIN_NAME, expr => { | 
					
						
							| 
									
										
										
										
											2022-03-28 23:51:48 +08:00
										 |  |  | 							const request = getUrlRequest(expr); | 
					
						
							|  |  |  | 							if (!request) return; | 
					
						
							|  |  |  | 							const url = new URL(request, getUrl(parser.state.module)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 								.setString(url.toString()) | 
					
						
							| 
									
										
										
										
											2023-06-18 02:36:03 +08:00
										 |  |  | 								.setRange(/** @type {Range} */ (expr.range)); | 
					
						
							| 
									
										
										
										
											2022-03-28 23:51:48 +08:00
										 |  |  | 						}); | 
					
						
							| 
									
										
										
										
											2023-04-01 01:56:32 +08:00
										 |  |  | 					parser.hooks.new.for("URL").tap(PLUGIN_NAME, _expr => { | 
					
						
							| 
									
										
										
										
											2021-01-19 20:31:55 +08:00
										 |  |  | 						const expr = /** @type {NewExpressionNode} */ (_expr); | 
					
						
							| 
									
										
										
										
											2024-08-14 21:58:10 +08:00
										 |  |  | 						const { options: importOptions, errors: commentErrors } = | 
					
						
							|  |  |  | 							parser.parseCommentOptions(/** @type {Range} */ (expr.range)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						if (commentErrors) { | 
					
						
							|  |  |  | 							for (const e of commentErrors) { | 
					
						
							|  |  |  | 								const { comment } = e; | 
					
						
							|  |  |  | 								parser.state.module.addWarning( | 
					
						
							|  |  |  | 									new CommentCompilationWarning( | 
					
						
							|  |  |  | 										`Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`, | 
					
						
							| 
									
										
										
										
											2024-10-16 22:42:26 +08:00
										 |  |  | 										/** @type {DependencyLocation} */ (comment.loc) | 
					
						
							| 
									
										
										
										
											2024-08-14 21:58:10 +08:00
										 |  |  | 									) | 
					
						
							|  |  |  | 								); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						if (importOptions && importOptions.webpackIgnore !== undefined) { | 
					
						
							|  |  |  | 							if (typeof importOptions.webpackIgnore !== "boolean") { | 
					
						
							|  |  |  | 								parser.state.module.addWarning( | 
					
						
							|  |  |  | 									new UnsupportedFeatureWarning( | 
					
						
							|  |  |  | 										`\`webpackIgnore\` expected a boolean, but received: ${importOptions.webpackIgnore}.`, | 
					
						
							|  |  |  | 										/** @type {DependencyLocation} */ (expr.loc) | 
					
						
							|  |  |  | 									) | 
					
						
							|  |  |  | 								); | 
					
						
							|  |  |  | 								return; | 
					
						
							|  |  |  | 							} else if (importOptions.webpackIgnore) { | 
					
						
							|  |  |  | 								if (expr.arguments.length !== 2) return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 								const [, arg2] = expr.arguments; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 								if ( | 
					
						
							|  |  |  | 									arg2.type !== "MemberExpression" || | 
					
						
							|  |  |  | 									!isMetaUrl(parser, arg2) | 
					
						
							|  |  |  | 								) | 
					
						
							|  |  |  | 									return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 								const dep = new ConstDependency( | 
					
						
							|  |  |  | 									RuntimeGlobals.baseURI, | 
					
						
							|  |  |  | 									/** @type {Range} */ (arg2.range), | 
					
						
							|  |  |  | 									[RuntimeGlobals.baseURI] | 
					
						
							|  |  |  | 								); | 
					
						
							|  |  |  | 								dep.loc = /** @type {DependencyLocation} */ (expr.loc); | 
					
						
							|  |  |  | 								parser.state.module.addPresentationalDependency(dep); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 								return true; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2021-01-19 20:31:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 						const request = getUrlRequest(expr); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | 						if (!request) return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-19 20:31:55 +08:00
										 |  |  | 						const [arg1, arg2] = expr.arguments; | 
					
						
							|  |  |  | 						const dep = new URLDependency( | 
					
						
							|  |  |  | 							request, | 
					
						
							| 
									
										
										
										
											2023-06-18 02:36:03 +08:00
										 |  |  | 							[ | 
					
						
							|  |  |  | 								/** @type {Range} */ (arg1.range)[0], | 
					
						
							|  |  |  | 								/** @type {Range} */ (arg2.range)[1] | 
					
						
							|  |  |  | 							], | 
					
						
							|  |  |  | 							/** @type {Range} */ (expr.range), | 
					
						
							| 
									
										
										
										
											2021-02-16 23:05:47 +08:00
										 |  |  | 							relative | 
					
						
							| 
									
										
										
										
											2021-01-19 20:31:55 +08:00
										 |  |  | 						); | 
					
						
							| 
									
										
										
										
											2023-06-18 02:36:03 +08:00
										 |  |  | 						dep.loc = /** @type {DependencyLocation} */ (expr.loc); | 
					
						
							| 
									
										
										
										
											2021-11-14 01:27:23 +08:00
										 |  |  | 						parser.state.current.addDependency(dep); | 
					
						
							| 
									
										
										
										
											2021-01-19 20:31:55 +08:00
										 |  |  | 						InnerGraph.onUsage(parser.state, e => (dep.usedByExports = e)); | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | 						return true; | 
					
						
							|  |  |  | 					}); | 
					
						
							| 
									
										
										
										
											2023-04-01 01:56:32 +08:00
										 |  |  | 					parser.hooks.isPure.for("NewExpression").tap(PLUGIN_NAME, _expr => { | 
					
						
							| 
									
										
										
										
											2021-01-19 20:31:55 +08:00
										 |  |  | 						const expr = /** @type {NewExpressionNode} */ (_expr); | 
					
						
							|  |  |  | 						const { callee } = expr; | 
					
						
							|  |  |  | 						if (callee.type !== "Identifier") return; | 
					
						
							|  |  |  | 						const calleeInfo = parser.getFreeInfoFromVariable(callee.name); | 
					
						
							|  |  |  | 						if (!calleeInfo || calleeInfo.name !== "URL") return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						const request = getUrlRequest(expr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						if (request) return true; | 
					
						
							|  |  |  | 					}); | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | 				}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				normalModuleFactory.hooks.parser | 
					
						
							| 
									
										
										
										
											2023-04-01 01:56:32 +08:00
										 |  |  | 					.for(JAVASCRIPT_MODULE_TYPE_AUTO) | 
					
						
							|  |  |  | 					.tap(PLUGIN_NAME, parserCallback); | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				normalModuleFactory.hooks.parser | 
					
						
							| 
									
										
										
										
											2023-04-01 01:56:32 +08:00
										 |  |  | 					.for(JAVASCRIPT_MODULE_TYPE_ESM) | 
					
						
							|  |  |  | 					.tap(PLUGIN_NAME, parserCallback); | 
					
						
							| 
									
										
										
										
											2020-08-05 05:42:29 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = URLPlugin; |