You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			230 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
		
		
			
		
	
	
			230 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
| 
											9 months ago
										 | /* | ||
|  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | ||
|  | 	Author Tobias Koppers @sokra | ||
|  | */ | ||
|  | 
 | ||
|  | "use strict"; | ||
|  | 
 | ||
|  | const path = require("path"); | ||
|  | 
 | ||
|  | const CHAR_HASH = "#".charCodeAt(0); | ||
|  | const CHAR_SLASH = "/".charCodeAt(0); | ||
|  | const CHAR_BACKSLASH = "\\".charCodeAt(0); | ||
|  | const CHAR_A = "A".charCodeAt(0); | ||
|  | const CHAR_Z = "Z".charCodeAt(0); | ||
|  | const CHAR_LOWER_A = "a".charCodeAt(0); | ||
|  | const CHAR_LOWER_Z = "z".charCodeAt(0); | ||
|  | const CHAR_DOT = ".".charCodeAt(0); | ||
|  | const CHAR_COLON = ":".charCodeAt(0); | ||
|  | 
 | ||
|  | const posixNormalize = path.posix.normalize; | ||
|  | const winNormalize = path.win32.normalize; | ||
|  | 
 | ||
|  | /** | ||
|  |  * @enum {number} | ||
|  |  */ | ||
|  | const PathType = Object.freeze({ | ||
|  | 	Empty: 0, | ||
|  | 	Normal: 1, | ||
|  | 	Relative: 2, | ||
|  | 	AbsoluteWin: 3, | ||
|  | 	AbsolutePosix: 4, | ||
|  | 	Internal: 5 | ||
|  | }); | ||
|  | exports.PathType = PathType; | ||
|  | 
 | ||
|  | /** | ||
|  |  * @param {string} p a path | ||
|  |  * @returns {PathType} type of path | ||
|  |  */ | ||
|  | const getType = p => { | ||
|  | 	switch (p.length) { | ||
|  | 		case 0: | ||
|  | 			return PathType.Empty; | ||
|  | 		case 1: { | ||
|  | 			const c0 = p.charCodeAt(0); | ||
|  | 			switch (c0) { | ||
|  | 				case CHAR_DOT: | ||
|  | 					return PathType.Relative; | ||
|  | 				case CHAR_SLASH: | ||
|  | 					return PathType.AbsolutePosix; | ||
|  | 				case CHAR_HASH: | ||
|  | 					return PathType.Internal; | ||
|  | 			} | ||
|  | 			return PathType.Normal; | ||
|  | 		} | ||
|  | 		case 2: { | ||
|  | 			const c0 = p.charCodeAt(0); | ||
|  | 			switch (c0) { | ||
|  | 				case CHAR_DOT: { | ||
|  | 					const c1 = p.charCodeAt(1); | ||
|  | 					switch (c1) { | ||
|  | 						case CHAR_DOT: | ||
|  | 						case CHAR_SLASH: | ||
|  | 							return PathType.Relative; | ||
|  | 					} | ||
|  | 					return PathType.Normal; | ||
|  | 				} | ||
|  | 				case CHAR_SLASH: | ||
|  | 					return PathType.AbsolutePosix; | ||
|  | 				case CHAR_HASH: | ||
|  | 					return PathType.Internal; | ||
|  | 			} | ||
|  | 			const c1 = p.charCodeAt(1); | ||
|  | 			if (c1 === CHAR_COLON) { | ||
|  | 				if ( | ||
|  | 					(c0 >= CHAR_A && c0 <= CHAR_Z) || | ||
|  | 					(c0 >= CHAR_LOWER_A && c0 <= CHAR_LOWER_Z) | ||
|  | 				) { | ||
|  | 					return PathType.AbsoluteWin; | ||
|  | 				} | ||
|  | 			} | ||
|  | 			return PathType.Normal; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	const c0 = p.charCodeAt(0); | ||
|  | 	switch (c0) { | ||
|  | 		case CHAR_DOT: { | ||
|  | 			const c1 = p.charCodeAt(1); | ||
|  | 			switch (c1) { | ||
|  | 				case CHAR_SLASH: | ||
|  | 					return PathType.Relative; | ||
|  | 				case CHAR_DOT: { | ||
|  | 					const c2 = p.charCodeAt(2); | ||
|  | 					if (c2 === CHAR_SLASH) return PathType.Relative; | ||
|  | 					return PathType.Normal; | ||
|  | 				} | ||
|  | 			} | ||
|  | 			return PathType.Normal; | ||
|  | 		} | ||
|  | 		case CHAR_SLASH: | ||
|  | 			return PathType.AbsolutePosix; | ||
|  | 		case CHAR_HASH: | ||
|  | 			return PathType.Internal; | ||
|  | 	} | ||
|  | 	const c1 = p.charCodeAt(1); | ||
|  | 	if (c1 === CHAR_COLON) { | ||
|  | 		const c2 = p.charCodeAt(2); | ||
|  | 		if ( | ||
|  | 			(c2 === CHAR_BACKSLASH || c2 === CHAR_SLASH) && | ||
|  | 			((c0 >= CHAR_A && c0 <= CHAR_Z) || | ||
|  | 				(c0 >= CHAR_LOWER_A && c0 <= CHAR_LOWER_Z)) | ||
|  | 		) { | ||
|  | 			return PathType.AbsoluteWin; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	return PathType.Normal; | ||
|  | }; | ||
|  | exports.getType = getType; | ||
|  | 
 | ||
|  | /** | ||
|  |  * @param {string} p a path | ||
|  |  * @returns {string} the normalized path | ||
|  |  */ | ||
|  | const normalize = p => { | ||
|  | 	switch (getType(p)) { | ||
|  | 		case PathType.Empty: | ||
|  | 			return p; | ||
|  | 		case PathType.AbsoluteWin: | ||
|  | 			return winNormalize(p); | ||
|  | 		case PathType.Relative: { | ||
|  | 			const r = posixNormalize(p); | ||
|  | 			return getType(r) === PathType.Relative ? r : `./${r}`; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	return posixNormalize(p); | ||
|  | }; | ||
|  | exports.normalize = normalize; | ||
|  | 
 | ||
|  | /** | ||
|  |  * @param {string} rootPath the root path | ||
|  |  * @param {string | undefined} request the request path | ||
|  |  * @returns {string} the joined path | ||
|  |  */ | ||
|  | const join = (rootPath, request) => { | ||
|  | 	if (!request) return normalize(rootPath); | ||
|  | 	const requestType = getType(request); | ||
|  | 	switch (requestType) { | ||
|  | 		case PathType.AbsolutePosix: | ||
|  | 			return posixNormalize(request); | ||
|  | 		case PathType.AbsoluteWin: | ||
|  | 			return winNormalize(request); | ||
|  | 	} | ||
|  | 	switch (getType(rootPath)) { | ||
|  | 		case PathType.Normal: | ||
|  | 		case PathType.Relative: | ||
|  | 		case PathType.AbsolutePosix: | ||
|  | 			return posixNormalize(`${rootPath}/${request}`); | ||
|  | 		case PathType.AbsoluteWin: | ||
|  | 			return winNormalize(`${rootPath}\\${request}`); | ||
|  | 	} | ||
|  | 	switch (requestType) { | ||
|  | 		case PathType.Empty: | ||
|  | 			return rootPath; | ||
|  | 		case PathType.Relative: { | ||
|  | 			const r = posixNormalize(rootPath); | ||
|  | 			return getType(r) === PathType.Relative ? r : `./${r}`; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	return posixNormalize(rootPath); | ||
|  | }; | ||
|  | exports.join = join; | ||
|  | 
 | ||
|  | /** @type {Map<string, Map<string, string | undefined>>} */ | ||
|  | const joinCache = new Map(); | ||
|  | 
 | ||
|  | /** | ||
|  |  * @param {string} rootPath the root path | ||
|  |  * @param {string} request the request path | ||
|  |  * @returns {string} the joined path | ||
|  |  */ | ||
|  | const cachedJoin = (rootPath, request) => { | ||
|  | 	/** @type {string | undefined} */ | ||
|  | 	let cacheEntry; | ||
|  | 	let cache = joinCache.get(rootPath); | ||
|  | 	if (cache === undefined) { | ||
|  | 		joinCache.set(rootPath, (cache = new Map())); | ||
|  | 	} else { | ||
|  | 		cacheEntry = cache.get(request); | ||
|  | 		if (cacheEntry !== undefined) return cacheEntry; | ||
|  | 	} | ||
|  | 	cacheEntry = join(rootPath, request); | ||
|  | 	cache.set(request, cacheEntry); | ||
|  | 	return cacheEntry; | ||
|  | }; | ||
|  | exports.cachedJoin = cachedJoin; | ||
|  | 
 | ||
|  | /** | ||
|  |  * @param {string} relativePath relative path | ||
|  |  * @returns {undefined|Error} nothing or an error | ||
|  |  */ | ||
|  | const checkImportsExportsFieldTarget = relativePath => { | ||
|  | 	let lastNonSlashIndex = 0; | ||
|  | 	let slashIndex = relativePath.indexOf("/", 1); | ||
|  | 	let cd = 0; | ||
|  | 
 | ||
|  | 	while (slashIndex !== -1) { | ||
|  | 		const folder = relativePath.slice(lastNonSlashIndex, slashIndex); | ||
|  | 
 | ||
|  | 		switch (folder) { | ||
|  | 			case "..": { | ||
|  | 				cd--; | ||
|  | 				if (cd < 0) | ||
|  | 					return new Error( | ||
|  | 						`Trying to access out of package scope. Requesting ${relativePath}` | ||
|  | 					); | ||
|  | 				break; | ||
|  | 			} | ||
|  | 			case ".": | ||
|  | 				break; | ||
|  | 			default: | ||
|  | 				cd++; | ||
|  | 				break; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		lastNonSlashIndex = slashIndex + 1; | ||
|  | 		slashIndex = relativePath.indexOf("/", lastNonSlashIndex); | ||
|  | 	} | ||
|  | }; | ||
|  | exports.checkImportsExportsFieldTarget = checkImportsExportsFieldTarget; |