diff options
Diffstat (limited to 'node_modules/enhanced-resolve/lib/util/entrypoints.js')
| -rw-r--r-- | node_modules/enhanced-resolve/lib/util/entrypoints.js | 604 |
1 files changed, 0 insertions, 604 deletions
diff --git a/node_modules/enhanced-resolve/lib/util/entrypoints.js b/node_modules/enhanced-resolve/lib/util/entrypoints.js deleted file mode 100644 index 392898ce..00000000 --- a/node_modules/enhanced-resolve/lib/util/entrypoints.js +++ /dev/null @@ -1,604 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Ivan Kopeykin @vankop -*/ - -"use strict"; - -/** @typedef {string|(string|ConditionalMapping)[]} DirectMapping */ -/** @typedef {{[k: string]: MappingValue}} ConditionalMapping */ -/** @typedef {ConditionalMapping|DirectMapping|null} MappingValue */ -/** @typedef {Record<string, MappingValue>|ConditionalMapping|DirectMapping} ExportsField */ -/** @typedef {Record<string, MappingValue>} ImportsField */ - -/** - * Processing exports/imports field - * @callback FieldProcessor - * @param {string} request request - * @param {Set<string>} conditionNames condition names - * @returns {string[]} resolved paths - */ - -/* -Example exports field: -{ - ".": "./main.js", - "./feature": { - "browser": "./feature-browser.js", - "default": "./feature.js" - } -} -Terminology: - -Enhanced-resolve name keys ("." and "./feature") as exports field keys. - -If value is string or string[], mapping is called as a direct mapping -and value called as a direct export. - -If value is key-value object, mapping is called as a conditional mapping -and value called as a conditional export. - -Key in conditional mapping is called condition name. - -Conditional mapping nested in another conditional mapping is called nested mapping. - ----------- - -Example imports field: -{ - "#a": "./main.js", - "#moment": { - "browser": "./moment/index.js", - "default": "moment" - }, - "#moment/": { - "browser": "./moment/", - "default": "moment/" - } -} -Terminology: - -Enhanced-resolve name keys ("#a" and "#moment/", "#moment") as imports field keys. - -If value is string or string[], mapping is called as a direct mapping -and value called as a direct export. - -If value is key-value object, mapping is called as a conditional mapping -and value called as a conditional export. - -Key in conditional mapping is called condition name. - -Conditional mapping nested in another conditional mapping is called nested mapping. - -*/ - -const slashCode = "/".charCodeAt(0); -const dotCode = ".".charCodeAt(0); -const hashCode = "#".charCodeAt(0); -const patternRegEx = /\*/g; - -/** - * @param {ExportsField} exportsField the exports field - * @returns {FieldProcessor} process callback - */ -module.exports.processExportsField = function processExportsField( - exportsField -) { - return createFieldProcessor( - buildExportsField(exportsField), - request => (request.length === 0 ? "." : "./" + request), - assertExportsFieldRequest, - assertExportTarget - ); -}; - -/** - * @param {ImportsField} importsField the exports field - * @returns {FieldProcessor} process callback - */ -module.exports.processImportsField = function processImportsField( - importsField -) { - return createFieldProcessor( - buildImportsField(importsField), - request => "#" + request, - assertImportsFieldRequest, - assertImportTarget - ); -}; - -/** - * @param {ExportsField | ImportsField} field root - * @param {(s: string) => string} normalizeRequest Normalize request, for `imports` field it adds `#`, for `exports` field it adds `.` or `./` - * @param {(s: string) => string} assertRequest assertRequest - * @param {(s: string, f: boolean) => void} assertTarget assertTarget - * @returns {FieldProcessor} field processor - */ -function createFieldProcessor( - field, - normalizeRequest, - assertRequest, - assertTarget -) { - return function fieldProcessor(request, conditionNames) { - request = assertRequest(request); - - const match = findMatch(normalizeRequest(request), field); - - if (match === null) return []; - - const [mapping, remainingRequest, isSubpathMapping, isPattern] = match; - - /** @type {DirectMapping|null} */ - let direct = null; - - if (isConditionalMapping(mapping)) { - direct = conditionalMapping( - /** @type {ConditionalMapping} */ (mapping), - conditionNames - ); - - // matching not found - if (direct === null) return []; - } else { - direct = /** @type {DirectMapping} */ (mapping); - } - - return directMapping( - remainingRequest, - isPattern, - isSubpathMapping, - direct, - conditionNames, - assertTarget - ); - }; -} - -/** - * @param {string} request request - * @returns {string} updated request - */ -function assertExportsFieldRequest(request) { - if (request.charCodeAt(0) !== dotCode) { - throw new Error('Request should be relative path and start with "."'); - } - if (request.length === 1) return ""; - if (request.charCodeAt(1) !== slashCode) { - throw new Error('Request should be relative path and start with "./"'); - } - if (request.charCodeAt(request.length - 1) === slashCode) { - throw new Error("Only requesting file allowed"); - } - - return request.slice(2); -} - -/** - * @param {string} request request - * @returns {string} updated request - */ -function assertImportsFieldRequest(request) { - if (request.charCodeAt(0) !== hashCode) { - throw new Error('Request should start with "#"'); - } - if (request.length === 1) { - throw new Error("Request should have at least 2 characters"); - } - if (request.charCodeAt(1) === slashCode) { - throw new Error('Request should not start with "#/"'); - } - if (request.charCodeAt(request.length - 1) === slashCode) { - throw new Error("Only requesting file allowed"); - } - - return request.slice(1); -} - -/** - * @param {string} exp export target - * @param {boolean} expectFolder is folder expected - */ -function assertExportTarget(exp, expectFolder) { - if ( - exp.charCodeAt(0) === slashCode || - (exp.charCodeAt(0) === dotCode && exp.charCodeAt(1) !== slashCode) - ) { - throw new Error( - `Export should be relative path and start with "./", got ${JSON.stringify( - exp - )}.` - ); - } - - const isFolder = exp.charCodeAt(exp.length - 1) === slashCode; - - if (isFolder !== expectFolder) { - throw new Error( - expectFolder - ? `Expecting folder to folder mapping. ${JSON.stringify( - exp - )} should end with "/"` - : `Expecting file to file mapping. ${JSON.stringify( - exp - )} should not end with "/"` - ); - } -} - -/** - * @param {string} imp import target - * @param {boolean} expectFolder is folder expected - */ -function assertImportTarget(imp, expectFolder) { - const isFolder = imp.charCodeAt(imp.length - 1) === slashCode; - - if (isFolder !== expectFolder) { - throw new Error( - expectFolder - ? `Expecting folder to folder mapping. ${JSON.stringify( - imp - )} should end with "/"` - : `Expecting file to file mapping. ${JSON.stringify( - imp - )} should not end with "/"` - ); - } -} - -/** - * @param {string} a first string - * @param {string} b second string - * @returns {number} compare result - */ -function patternKeyCompare(a, b) { - const aPatternIndex = a.indexOf("*"); - const bPatternIndex = b.indexOf("*"); - const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1; - const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1; - - if (baseLenA > baseLenB) return -1; - if (baseLenB > baseLenA) return 1; - if (aPatternIndex === -1) return 1; - if (bPatternIndex === -1) return -1; - if (a.length > b.length) return -1; - if (b.length > a.length) return 1; - - return 0; -} - -/** - * Trying to match request to field - * @param {string} request request - * @param {ExportsField | ImportsField} field exports or import field - * @returns {[MappingValue, string, boolean, boolean]|null} match or null, number is negative and one less when it's a folder mapping, number is request.length + 1 for direct mappings - */ -function findMatch(request, field) { - if ( - Object.prototype.hasOwnProperty.call(field, request) && - !request.includes("*") && - !request.endsWith("/") - ) { - const target = /** @type {{[k: string]: MappingValue}} */ (field)[request]; - - return [target, "", false, false]; - } - - /** @type {string} */ - let bestMatch = ""; - /** @type {string|undefined} */ - let bestMatchSubpath; - - const keys = Object.getOwnPropertyNames(field); - - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - const patternIndex = key.indexOf("*"); - - if (patternIndex !== -1 && request.startsWith(key.slice(0, patternIndex))) { - const patternTrailer = key.slice(patternIndex + 1); - - if ( - request.length >= key.length && - request.endsWith(patternTrailer) && - patternKeyCompare(bestMatch, key) === 1 && - key.lastIndexOf("*") === patternIndex - ) { - bestMatch = key; - bestMatchSubpath = request.slice( - patternIndex, - request.length - patternTrailer.length - ); - } - } - // For legacy `./foo/` - else if ( - key[key.length - 1] === "/" && - request.startsWith(key) && - patternKeyCompare(bestMatch, key) === 1 - ) { - bestMatch = key; - bestMatchSubpath = request.slice(key.length); - } - } - - if (bestMatch === "") return null; - - const target = /** @type {{[k: string]: MappingValue}} */ (field)[bestMatch]; - const isSubpathMapping = bestMatch.endsWith("/"); - const isPattern = bestMatch.includes("*"); - - return [ - target, - /** @type {string} */ (bestMatchSubpath), - isSubpathMapping, - isPattern - ]; -} - -/** - * @param {ConditionalMapping|DirectMapping|null} mapping mapping - * @returns {boolean} is conditional mapping - */ -function isConditionalMapping(mapping) { - return ( - mapping !== null && typeof mapping === "object" && !Array.isArray(mapping) - ); -} - -/** - * @param {string|undefined} remainingRequest remaining request when folder mapping, undefined for file mappings - * @param {boolean} isPattern true, if mapping is a pattern (contains "*") - * @param {boolean} isSubpathMapping true, for subpath mappings - * @param {DirectMapping|null} mappingTarget direct export - * @param {Set<string>} conditionNames condition names - * @param {(d: string, f: boolean) => void} assert asserting direct value - * @returns {string[]} mapping result - */ -function directMapping( - remainingRequest, - isPattern, - isSubpathMapping, - mappingTarget, - conditionNames, - assert -) { - if (mappingTarget === null) return []; - - if (typeof mappingTarget === "string") { - return [ - targetMapping( - remainingRequest, - isPattern, - isSubpathMapping, - mappingTarget, - assert - ) - ]; - } - - /** @type {string[]} */ - const targets = []; - - for (const exp of mappingTarget) { - if (typeof exp === "string") { - targets.push( - targetMapping( - remainingRequest, - isPattern, - isSubpathMapping, - exp, - assert - ) - ); - continue; - } - - const mapping = conditionalMapping(exp, conditionNames); - if (!mapping) continue; - const innerExports = directMapping( - remainingRequest, - isPattern, - isSubpathMapping, - mapping, - conditionNames, - assert - ); - for (const innerExport of innerExports) { - targets.push(innerExport); - } - } - - return targets; -} - -/** - * @param {string|undefined} remainingRequest remaining request when folder mapping, undefined for file mappings - * @param {boolean} isPattern true, if mapping is a pattern (contains "*") - * @param {boolean} isSubpathMapping true, for subpath mappings - * @param {string} mappingTarget direct export - * @param {(d: string, f: boolean) => void} assert asserting direct value - * @returns {string} mapping result - */ -function targetMapping( - remainingRequest, - isPattern, - isSubpathMapping, - mappingTarget, - assert -) { - if (remainingRequest === undefined) { - assert(mappingTarget, false); - - return mappingTarget; - } - - if (isSubpathMapping) { - assert(mappingTarget, true); - - return mappingTarget + remainingRequest; - } - - assert(mappingTarget, false); - - let result = mappingTarget; - - if (isPattern) { - result = result.replace( - patternRegEx, - remainingRequest.replace(/\$/g, "$$") - ); - } - - return result; -} - -/** - * @param {ConditionalMapping} conditionalMapping_ conditional mapping - * @param {Set<string>} conditionNames condition names - * @returns {DirectMapping|null} direct mapping if found - */ -function conditionalMapping(conditionalMapping_, conditionNames) { - /** @type {[ConditionalMapping, string[], number][]} */ - let lookup = [[conditionalMapping_, Object.keys(conditionalMapping_), 0]]; - - loop: while (lookup.length > 0) { - const [mapping, conditions, j] = lookup[lookup.length - 1]; - const last = conditions.length - 1; - - for (let i = j; i < conditions.length; i++) { - const condition = conditions[i]; - - // assert default. Could be last only - if (i !== last) { - if (condition === "default") { - throw new Error("Default condition should be last one"); - } - } else if (condition === "default") { - const innerMapping = mapping[condition]; - // is nested - if (isConditionalMapping(innerMapping)) { - const conditionalMapping = /** @type {ConditionalMapping} */ ( - innerMapping - ); - lookup[lookup.length - 1][2] = i + 1; - lookup.push([conditionalMapping, Object.keys(conditionalMapping), 0]); - continue loop; - } - - return /** @type {DirectMapping} */ (innerMapping); - } - - if (conditionNames.has(condition)) { - const innerMapping = mapping[condition]; - // is nested - if (isConditionalMapping(innerMapping)) { - const conditionalMapping = /** @type {ConditionalMapping} */ ( - innerMapping - ); - lookup[lookup.length - 1][2] = i + 1; - lookup.push([conditionalMapping, Object.keys(conditionalMapping), 0]); - continue loop; - } - - return /** @type {DirectMapping} */ (innerMapping); - } - } - - lookup.pop(); - } - - return null; -} - -/** - * @param {ExportsField} field exports field - * @returns {ExportsField} normalized exports field - */ -function buildExportsField(field) { - // handle syntax sugar, if exports field is direct mapping for "." - if (typeof field === "string" || Array.isArray(field)) { - return { ".": field }; - } - - const keys = Object.keys(field); - - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - - if (key.charCodeAt(0) !== dotCode) { - // handle syntax sugar, if exports field is conditional mapping for "." - if (i === 0) { - while (i < keys.length) { - const charCode = keys[i].charCodeAt(0); - if (charCode === dotCode || charCode === slashCode) { - throw new Error( - `Exports field key should be relative path and start with "." (key: ${JSON.stringify( - key - )})` - ); - } - i++; - } - - return { ".": field }; - } - - throw new Error( - `Exports field key should be relative path and start with "." (key: ${JSON.stringify( - key - )})` - ); - } - - if (key.length === 1) { - continue; - } - - if (key.charCodeAt(1) !== slashCode) { - throw new Error( - `Exports field key should be relative path and start with "./" (key: ${JSON.stringify( - key - )})` - ); - } - } - - return field; -} - -/** - * @param {ImportsField} field imports field - * @returns {ImportsField} normalized imports field - */ -function buildImportsField(field) { - const keys = Object.keys(field); - - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - - if (key.charCodeAt(0) !== hashCode) { - throw new Error( - `Imports field key should start with "#" (key: ${JSON.stringify(key)})` - ); - } - - if (key.length === 1) { - throw new Error( - `Imports field key should have at least 2 characters (key: ${JSON.stringify( - key - )})` - ); - } - - if (key.charCodeAt(1) === slashCode) { - throw new Error( - `Imports field key should not start with "#/" (key: ${JSON.stringify( - key - )})` - ); - } - } - - return field; -} |
