| |
| |
| |
| |
| |
| "use strict"; |
|
|
| const DescriptionFileUtils = require("./DescriptionFileUtils"); |
| const forEachBail = require("./forEachBail"); |
| const { processImportsField } = require("./util/entrypoints"); |
| const { parseIdentifier } = require("./util/identifier"); |
| const { |
| deprecatedInvalidSegmentRegEx, |
| invalidSegmentRegEx, |
| } = require("./util/path"); |
|
|
| |
| |
| |
| |
| |
| |
|
|
| const dotCode = ".".charCodeAt(0); |
|
|
| module.exports = class ImportsFieldPlugin { |
| |
| |
| |
| |
| |
| |
| |
| constructor( |
| source, |
| conditionNames, |
| fieldNamePath, |
| targetFile, |
| targetPackage, |
| ) { |
| this.source = source; |
| this.targetFile = targetFile; |
| this.targetPackage = targetPackage; |
| this.conditionNames = conditionNames; |
| this.fieldName = fieldNamePath; |
| |
| this.fieldProcessorCache = new WeakMap(); |
| } |
|
|
| |
| |
| |
| |
| apply(resolver) { |
| const targetFile = resolver.ensureHook(this.targetFile); |
| const targetPackage = resolver.ensureHook(this.targetPackage); |
|
|
| resolver |
| .getHook(this.source) |
| .tapAsync("ImportsFieldPlugin", (request, resolveContext, callback) => { |
| |
| if (!request.descriptionFilePath || request.request === undefined) { |
| return callback(); |
| } |
|
|
| const remainingRequest = |
| request.request + request.query + request.fragment; |
| const importsField = |
| |
| ( |
| DescriptionFileUtils.getField( |
| (request.descriptionFileData), |
| this.fieldName, |
| ) |
| ); |
| if (!importsField) return callback(); |
|
|
| if (request.directory) { |
| return callback( |
| new Error( |
| `Resolving to directories is not possible with the imports field (request was ${remainingRequest}/)`, |
| ), |
| ); |
| } |
|
|
| |
| let paths; |
| |
| let usedField; |
|
|
| try { |
| |
| |
| |
| let fieldProcessor = this.fieldProcessorCache.get( |
| (request.descriptionFileData), |
| ); |
| if (fieldProcessor === undefined) { |
| fieldProcessor = processImportsField(importsField); |
| this.fieldProcessorCache.set( |
| (request.descriptionFileData), |
| fieldProcessor, |
| ); |
| } |
| [paths, usedField] = fieldProcessor( |
| remainingRequest, |
| this.conditionNames, |
| ); |
| } catch ( err) { |
| if (resolveContext.log) { |
| resolveContext.log( |
| `Imports field in ${request.descriptionFilePath} can't be processed: ${err}`, |
| ); |
| } |
| return callback( (err)); |
| } |
|
|
| if (paths.length === 0) { |
| return callback( |
| new Error( |
| `Package import ${remainingRequest} is not imported from package ${request.descriptionFileRoot} (see imports field in ${request.descriptionFilePath})`, |
| ), |
| ); |
| } |
|
|
| forEachBail( |
| paths, |
| |
| |
| |
| |
| |
| |
| (path, callback, i) => { |
| const parsedIdentifier = parseIdentifier(path); |
|
|
| if (!parsedIdentifier) return callback(); |
|
|
| const [path_, query, fragment] = parsedIdentifier; |
|
|
| switch (path_.charCodeAt(0)) { |
| |
| case dotCode: { |
| if ( |
| invalidSegmentRegEx.exec(path_.slice(2)) !== null && |
| deprecatedInvalidSegmentRegEx.test(path_.slice(2)) !== null |
| ) { |
| if (paths.length === i) { |
| return callback( |
| new Error( |
| `Invalid "imports" 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), |
| path_, |
| ), |
| relativePath: path_, |
| query, |
| fragment, |
| }; |
|
|
| resolver.doResolve( |
| targetFile, |
| obj, |
| `using imports field: ${path}`, |
| resolveContext, |
| (err, result) => { |
| if (err) return callback(err); |
| |
| if (result === undefined) return callback(null, null); |
| callback(null, result); |
| }, |
| ); |
| break; |
| } |
|
|
| |
| default: { |
| |
| const obj = { |
| ...request, |
| request: path_, |
| relativePath: path_, |
| fullySpecified: true, |
| query, |
| fragment, |
| }; |
|
|
| resolver.doResolve( |
| targetPackage, |
| obj, |
| `using imports 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), |
| ); |
| }); |
| } |
| }; |
|
|