| |
| |
| |
| |
| |
| "use strict"; |
|
|
| const DescriptionFileUtils = require("./DescriptionFileUtils"); |
| const forEachBail = require("./forEachBail"); |
| const { processExportsField } = require("./util/entrypoints"); |
| const { parseIdentifier } = require("./util/identifier"); |
| const { |
| deprecatedInvalidSegmentRegEx, |
| invalidSegmentRegEx, |
| } = require("./util/path"); |
|
|
| |
| |
| |
| |
| |
| |
|
|
| module.exports = class ExportsFieldPlugin { |
| |
| |
| |
| |
| |
| |
| constructor(source, conditionNames, fieldNamePath, target) { |
| this.source = source; |
| this.target = target; |
| this.conditionNames = conditionNames; |
| this.fieldName = fieldNamePath; |
| |
| this.fieldProcessorCache = new WeakMap(); |
| } |
|
|
| |
| |
| |
| |
| apply(resolver) { |
| const target = resolver.ensureHook(this.target); |
| resolver |
| .getHook(this.source) |
| .tapAsync("ExportsFieldPlugin", (request, resolveContext, callback) => { |
| |
| if (!request.descriptionFilePath) return callback(); |
| if ( |
| |
| |
| request.relativePath !== "." || |
| request.request === undefined |
| ) { |
| return callback(); |
| } |
|
|
| const remainingRequest = |
| request.query || request.fragment |
| ? (request.request === "." ? "./" : request.request) + |
| request.query + |
| request.fragment |
| : request.request; |
| const exportsField = |
| |
| ( |
| DescriptionFileUtils.getField( |
| (request.descriptionFileData), |
| this.fieldName, |
| ) |
| ); |
| if (!exportsField) return callback(); |
|
|
| if (request.directory) { |
| return callback( |
| new Error( |
| `Resolving to directories is not possible with the exports field (request was ${remainingRequest}/)`, |
| ), |
| ); |
| } |
|
|
| |
| let paths; |
| |
| let usedField; |
|
|
| try { |
| |
| |
| |
| let fieldProcessor = this.fieldProcessorCache.get( |
| (request.descriptionFileData), |
| ); |
| if (fieldProcessor === undefined) { |
| fieldProcessor = processExportsField(exportsField); |
| this.fieldProcessorCache.set( |
| (request.descriptionFileData), |
| fieldProcessor, |
| ); |
| } |
| [paths, usedField] = fieldProcessor( |
| remainingRequest, |
| this.conditionNames, |
| ); |
| } catch ( err) { |
| if (resolveContext.log) { |
| resolveContext.log( |
| `Exports field in ${request.descriptionFilePath} can't be processed: ${err}`, |
| ); |
| } |
| return callback( (err)); |
| } |
|
|
| if (paths.length === 0) { |
| const conditions = [...this.conditionNames]; |
| const conditionsStr = |
| conditions.length === 1 |
| ? `the condition "${conditions[0]}"` |
| : `the conditions ${JSON.stringify(conditions)}`; |
| return callback( |
| new Error( |
| `"${remainingRequest}" is not exported under ${conditionsStr} from package ${request.descriptionFileRoot} (see exports field in ${request.descriptionFilePath})`, |
| ), |
| ); |
| } |
|
|
| forEachBail( |
| paths, |
| |
| |
| |
| |
| |
| |
| (path, callback, i) => { |
| const parsedIdentifier = parseIdentifier(path); |
|
|
| if (!parsedIdentifier) return callback(); |
|
|
| const [relativePath, query, fragment] = parsedIdentifier; |
|
|
| if (relativePath.length === 0 || !relativePath.startsWith("./")) { |
| if (paths.length === i) { |
| return callback( |
| new Error( |
| `Invalid "exports" target "${path}" defined for "${usedField}" in the package config ${request.descriptionFilePath}, targets must start with "./"`, |
| ), |
| ); |
| } |
|
|
| return callback(); |
| } |
|
|
| if ( |
| invalidSegmentRegEx.exec(relativePath.slice(2)) !== null && |
| deprecatedInvalidSegmentRegEx.test(relativePath.slice(2)) |
| ) { |
| if (paths.length === i) { |
| return callback( |
| new Error( |
| `Invalid "exports" target "${path}" defined for "${usedField}" in the package config ${request.descriptionFilePath}, targets must start with "./"`, |
| ), |
| ); |
| } |
|
|
| return callback(); |
| } |
|
|
| |
| const obj = { |
| ...request, |
| request: undefined, |
| path: resolver.join( |
| (request.descriptionFileRoot), |
| relativePath, |
| ), |
| relativePath, |
| query, |
| fragment, |
| }; |
|
|
| resolver.doResolve( |
| target, |
| obj, |
| `using exports field: ${path}`, |
| resolveContext, |
| (err, result) => { |
| if (err) return callback(err); |
| |
| if (result === undefined) return callback(null, null); |
| callback(null, result); |
| }, |
| ); |
| }, |
| |
| |
| |
| |
| |
| (err, result) => callback(err, result || null), |
| ); |
| }); |
| } |
| }; |
|
|