| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-05 21:38:15 +08:00
										 |  |  | "use strict"; | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-05 21:38:15 +08:00
										 |  |  | const path = require("path"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-11 22:25:03 +08:00
										 |  |  | const WINDOWS_ABS_PATH_REGEXP = /^[a-zA-Z]:[\\/]/; | 
					
						
							| 
									
										
										
										
											2018-12-26 17:40:42 +08:00
										 |  |  | const SEGEMENTS_SPLIT_REGEXP = /([|!])/; | 
					
						
							|  |  |  | const WINDOWS_PATH_SEPARATOR_REGEXP = /\\/g; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-21 05:37:42 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} MakeRelativePathsCache | 
					
						
							|  |  |  |  * @property {Map<string, Map<string, string>>=} relativePaths | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-04-15 05:31:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-12-08 01:12:04 +08:00
										 |  |  |  * @param {string} context context for relative path | 
					
						
							|  |  |  |  * @param {string} maybeAbsolutePath path to make relative | 
					
						
							|  |  |  |  * @returns {string} relative path in request style | 
					
						
							| 
									
										
										
										
											2018-04-15 05:31:11 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-12-08 01:12:04 +08:00
										 |  |  | const absoluteToRequest = (context, maybeAbsolutePath) => { | 
					
						
							| 
									
										
										
										
											2018-12-23 20:22:07 +08:00
										 |  |  | 	if (maybeAbsolutePath[0] === "/") { | 
					
						
							|  |  |  | 		if ( | 
					
						
							|  |  |  | 			maybeAbsolutePath.length > 1 && | 
					
						
							|  |  |  | 			maybeAbsolutePath[maybeAbsolutePath.length - 1] === "/" | 
					
						
							|  |  |  | 		) { | 
					
						
							|  |  |  | 			// this 'path' is actually a regexp generated by dynamic requires.
 | 
					
						
							|  |  |  | 			// Don't treat it as an absolute path.
 | 
					
						
							|  |  |  | 			return maybeAbsolutePath; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-26 17:40:42 +08:00
										 |  |  | 		const querySplitPos = maybeAbsolutePath.indexOf("?"); | 
					
						
							|  |  |  | 		let resource = | 
					
						
							|  |  |  | 			querySplitPos === -1 | 
					
						
							|  |  |  | 				? maybeAbsolutePath | 
					
						
							|  |  |  | 				: maybeAbsolutePath.slice(0, querySplitPos); | 
					
						
							|  |  |  | 		resource = path.posix.relative(context, resource); | 
					
						
							|  |  |  | 		if (!resource.startsWith("../")) { | 
					
						
							|  |  |  | 			resource = "./" + resource; | 
					
						
							| 
									
										
										
										
											2018-12-23 20:22:07 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-12-26 17:40:42 +08:00
										 |  |  | 		return querySplitPos === -1 | 
					
						
							|  |  |  | 			? resource | 
					
						
							|  |  |  | 			: resource + maybeAbsolutePath.slice(querySplitPos); | 
					
						
							| 
									
										
										
										
											2018-12-08 01:12:04 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-12-23 20:22:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-26 17:40:42 +08:00
										 |  |  | 	if (WINDOWS_ABS_PATH_REGEXP.test(maybeAbsolutePath)) { | 
					
						
							|  |  |  | 		const querySplitPos = maybeAbsolutePath.indexOf("?"); | 
					
						
							|  |  |  | 		let resource = | 
					
						
							|  |  |  | 			querySplitPos === -1 | 
					
						
							|  |  |  | 				? maybeAbsolutePath | 
					
						
							|  |  |  | 				: maybeAbsolutePath.slice(0, querySplitPos); | 
					
						
							|  |  |  | 		resource = path.win32.relative(context, resource); | 
					
						
							|  |  |  | 		if (!WINDOWS_ABS_PATH_REGEXP.test(resource)) { | 
					
						
							|  |  |  | 			resource = resource.replace(WINDOWS_PATH_SEPARATOR_REGEXP, "/"); | 
					
						
							|  |  |  | 			if (!resource.startsWith("../")) { | 
					
						
							|  |  |  | 				resource = "./" + resource; | 
					
						
							| 
									
										
										
										
											2018-12-08 01:12:04 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-12-26 17:40:42 +08:00
										 |  |  | 		return querySplitPos === -1 | 
					
						
							|  |  |  | 			? resource | 
					
						
							|  |  |  | 			: resource + maybeAbsolutePath.slice(querySplitPos); | 
					
						
							| 
									
										
										
										
											2018-05-21 16:46:09 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-12-23 20:22:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// not an absolute path
 | 
					
						
							|  |  |  | 	return maybeAbsolutePath; | 
					
						
							| 
									
										
										
										
											2017-04-05 21:38:15 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-11 22:25:03 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {string} context context for relative path | 
					
						
							|  |  |  |  * @param {string} relativePath path | 
					
						
							|  |  |  |  * @returns {string} absolute path | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const requestToAbsolute = (context, relativePath) => { | 
					
						
							|  |  |  | 	if (relativePath.startsWith("./") || relativePath.startsWith("../")) | 
					
						
							|  |  |  | 		return path.join(context, relativePath); | 
					
						
							|  |  |  | 	return relativePath; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-19 19:40:00 +08:00
										 |  |  | const makeCacheable = fn => { | 
					
						
							|  |  |  | 	/** @type {WeakMap<Object, Map<string, Map<string, string>>>} */ | 
					
						
							|  |  |  | 	const cache = new WeakMap(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {string} context context used to create relative path | 
					
						
							|  |  |  | 	 * @param {string} identifier identifier used to create relative path | 
					
						
							|  |  |  | 	 * @param {Object=} associatedObjectForCache an object to which the cache will be attached | 
					
						
							|  |  |  | 	 * @returns {string} the returned relative path | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	const cachedFn = (context, identifier, associatedObjectForCache) => { | 
					
						
							|  |  |  | 		if (!associatedObjectForCache) return fn(context, identifier); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		let innerCache = cache.get(associatedObjectForCache); | 
					
						
							|  |  |  | 		if (innerCache === undefined) { | 
					
						
							|  |  |  | 			innerCache = new Map(); | 
					
						
							|  |  |  | 			cache.set(associatedObjectForCache, innerCache); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		let cachedResult; | 
					
						
							|  |  |  | 		let innerSubCache = innerCache.get(context); | 
					
						
							|  |  |  | 		if (innerSubCache === undefined) { | 
					
						
							|  |  |  | 			innerCache.set(context, (innerSubCache = new Map())); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			cachedResult = innerSubCache.get(identifier); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (cachedResult !== undefined) { | 
					
						
							|  |  |  | 			return cachedResult; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			const result = fn(context, identifier); | 
					
						
							|  |  |  | 			innerSubCache.set(identifier, result); | 
					
						
							|  |  |  | 			return result; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return cachedFn; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-15 05:31:11 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param {string} context context for relative path | 
					
						
							|  |  |  |  * @param {string} identifier identifier for path | 
					
						
							| 
									
										
										
										
											2018-05-08 20:31:51 +08:00
										 |  |  |  * @returns {string} a converted relative path | 
					
						
							| 
									
										
										
										
											2018-04-15 05:31:11 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-07-18 04:30:29 +08:00
										 |  |  | const _makePathsRelative = (context, identifier) => { | 
					
						
							|  |  |  | 	return identifier | 
					
						
							| 
									
										
										
										
											2018-12-26 17:40:42 +08:00
										 |  |  | 		.split(SEGEMENTS_SPLIT_REGEXP) | 
					
						
							| 
									
										
										
										
											2018-12-08 01:12:04 +08:00
										 |  |  | 		.map(str => absoluteToRequest(context, str)) | 
					
						
							| 
									
										
										
										
											2017-07-18 04:30:29 +08:00
										 |  |  | 		.join(""); | 
					
						
							| 
									
										
										
										
											2017-07-18 04:47:18 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-07-12 07:19:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-19 19:40:00 +08:00
										 |  |  | exports.makePathsRelative = makeCacheable(_makePathsRelative); | 
					
						
							| 
									
										
										
										
											2018-07-04 15:59:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {string} context absolute context path | 
					
						
							|  |  |  |  * @param {string} request any request string may containing absolute paths, query string, etc. | 
					
						
							|  |  |  |  * @returns {string} a new request string avoiding absolute paths when possible | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-01-19 19:40:00 +08:00
										 |  |  | const _contextify = (context, request) => { | 
					
						
							| 
									
										
										
										
											2018-07-04 15:59:22 +08:00
										 |  |  | 	return request | 
					
						
							|  |  |  | 		.split("!") | 
					
						
							| 
									
										
										
										
											2018-12-08 01:12:04 +08:00
										 |  |  | 		.map(r => absoluteToRequest(context, r)) | 
					
						
							| 
									
										
										
										
											2018-07-04 15:59:22 +08:00
										 |  |  | 		.join("!"); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2019-01-19 19:40:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-11 22:25:03 +08:00
										 |  |  | const contextify = makeCacheable(_contextify); | 
					
						
							|  |  |  | exports.contextify = contextify; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {string} context absolute context path | 
					
						
							|  |  |  |  * @param {string} request any request string | 
					
						
							|  |  |  |  * @returns {string} a new request string using absolute paths when possible | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const _absolutify = (context, request) => { | 
					
						
							|  |  |  | 	return request | 
					
						
							|  |  |  | 		.split("!") | 
					
						
							|  |  |  | 		.map(r => requestToAbsolute(context, r)) | 
					
						
							|  |  |  | 		.join("!"); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const absolutify = makeCacheable(_absolutify); | 
					
						
							|  |  |  | exports.absolutify = absolutify; |