123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.pnpPlugin = void 0;
- const tslib_1 = require("tslib");
- const fs = tslib_1.__importStar(require("fs"));
- const path_1 = tslib_1.__importDefault(require("path"));
- const matchAll = /()/;
- const defaultExtensions = [`.tsx`, `.ts`, `.jsx`, `.mjs`, `.cjs`, `.js`, `.css`, `.json`];
- // Reference: https://github.com/evanw/esbuild/blob/537195ae84bee1510fac14235906d588084c39cd/pkg/api/api_impl.go#L366-L388
- function parseExternals(externals) {
- return externals.map(external => {
- // ESBuild's validation pass runs before this function is called so there's no need to assert that there's a single wildcard
- const wildcardIdx = external.indexOf(`*`);
- if (wildcardIdx !== -1)
- return { prefix: external.slice(0, wildcardIdx), suffix: external.slice(wildcardIdx + 1) };
- return external;
- });
- }
- function isExternal(path, externals) {
- for (const external of externals) {
- if (typeof external === `object`) {
- // Reference: https://github.com/evanw/esbuild/blob/537195ae84bee1510fac14235906d588084c39cd/internal/resolver/resolver.go#L372-L381
- if (path.length >= external.prefix.length + external.suffix.length
- && path.startsWith(external.prefix)
- && path.endsWith(external.suffix)) {
- return true;
- }
- }
- else {
- if (path === external)
- return true;
- // If the module "foo" has been marked as external, we also want to treat
- // paths into that module such as "foo/bar" as external too.
- // References:
- // - https://github.com/evanw/esbuild/blob/537195ae84bee1510fac14235906d588084c39cd/internal/resolver/resolver.go#L651-L652
- // - https://github.com/evanw/esbuild/blob/537195ae84bee1510fac14235906d588084c39cd/internal/resolver/resolver.go#L1688-L1691
- if (!external.startsWith(`/`) && !external.startsWith(`./`) && !external.startsWith(`../`) && external !== `.` && external !== `..`) {
- if (path.startsWith(`${external}/`)) {
- return true;
- }
- }
- }
- }
- return false;
- }
- async function defaultOnLoad(args) {
- return {
- contents: await fs.promises.readFile(args.path),
- loader: `default`,
- // For regular imports in the `file` namespace, resolveDir is the directory the
- // file being resolved lives in. For all other virtual modules, this defaults to
- // empty string: ""
- // A sensible value for pnp imports is the same as the `file` namespace, as pnp
- // still resolves to files on disk (in the cache).
- resolveDir: path_1.default.dirname(args.path),
- };
- }
- async function defaultOnResolve(args, { resolvedPath, error, watchFiles }) {
- const problems = error ? [{ text: error.message }] : [];
- // Sometimes dynamic resolve calls might be wrapped in a try / catch,
- // but ESBuild neither skips them nor does it provide a way for us to tell.
- // Because of that, we downgrade all errors to warnings in these situations.
- // Issue: https://github.com/evanw/esbuild/issues/1127
- let mergeWith;
- switch (args.kind) {
- case `require-call`:
- case `require-resolve`:
- case `dynamic-import`:
- {
- mergeWith = { warnings: problems };
- }
- break;
- default:
- {
- mergeWith = { errors: problems };
- }
- break;
- }
- if (resolvedPath !== null) {
- return { namespace: `pnp`, path: resolvedPath, watchFiles };
- }
- else {
- return { external: true, ...mergeWith, watchFiles };
- }
- }
- function pnpPlugin({ baseDir = process.cwd(), extensions = defaultExtensions, filter = matchAll, onResolve = defaultOnResolve, onLoad = defaultOnLoad, } = {}) {
- return {
- name: `@yarnpkg/esbuild-plugin-pnp`,
- setup(build) {
- var _a, _b;
- const { findPnpApi } = require(`module`);
- if (typeof findPnpApi === `undefined`)
- return;
- const externals = parseExternals((_a = build.initialOptions.external) !== null && _a !== void 0 ? _a : []);
- const platform = (_b = build.initialOptions.platform) !== null && _b !== void 0 ? _b : `browser`;
- const isPlatformNode = platform === `node`;
- // Reference: https://github.com/evanw/esbuild/blob/537195ae84bee1510fac14235906d588084c39cd/internal/resolver/resolver.go#L238-L253
- const conditionsDefault = new Set(build.initialOptions.conditions);
- conditionsDefault.add(`default`);
- if (platform === `browser` || platform === `node`)
- conditionsDefault.add(platform);
- const conditionsImport = new Set(conditionsDefault);
- conditionsImport.add(`import`);
- const conditionsRequire = new Set(conditionsDefault);
- conditionsRequire.add(`require`);
- build.onResolve({ filter }, args => {
- var _a, _b;
- if (isExternal(args.path, externals))
- return { external: true };
- // Reference: https://github.com/evanw/esbuild/blob/537195ae84bee1510fac14235906d588084c39cd/internal/resolver/resolver.go#L1495-L1502
- let conditions = conditionsDefault;
- if (args.kind === `dynamic-import` || args.kind === `import-statement`)
- conditions = conditionsImport;
- else if (args.kind === `require-call` || args.kind === `require-resolve`)
- conditions = conditionsRequire;
- // The entry point resolution uses an empty string
- const effectiveImporter = args.resolveDir
- ? `${args.resolveDir}/`
- : args.importer
- ? args.importer
- : `${baseDir}/`;
- const pnpApi = findPnpApi(effectiveImporter);
- if (!pnpApi)
- // Path isn't controlled by PnP so delegate to the next resolver in the chain
- return undefined;
- let path = null;
- let error;
- try {
- path = pnpApi.resolveRequest(args.path, effectiveImporter, {
- conditions,
- considerBuiltins: isPlatformNode,
- extensions,
- });
- }
- catch (e) {
- error = e;
- }
- const watchFiles = [pnpApi.resolveRequest(`pnpapi`, null)];
- if (path) {
- const locator = pnpApi.findPackageLocator(path);
- if (locator) {
- const info = pnpApi.getPackageInformation(locator);
- if ((info === null || info === void 0 ? void 0 : info.linkType) === `SOFT`) {
- watchFiles.push((_b = (_a = pnpApi.resolveVirtual) === null || _a === void 0 ? void 0 : _a.call(pnpApi, path)) !== null && _b !== void 0 ? _b : path);
- }
- }
- }
- return onResolve(args, { resolvedPath: path, error, watchFiles });
- });
- // We register on the build to prevent ESBuild from reading the files
- // itself, since it wouldn't know how to access the files from within
- // the zip archives.
- if (build.onLoad !== null) {
- build.onLoad({ filter }, onLoad);
- }
- },
- };
- }
- exports.pnpPlugin = pnpPlugin;
|