All files / src/polyfill index.ts

100% Statements 45/45
100% Branches 40/40
100% Functions 5/5
100% Lines 43/43

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124  1x 1x     1x     1x 1x                                 29x 29x 29x 29x                         29x 29x   29x             23x   22x 1x   22x 5x 5x 5x   17x 2x 2x 2x   15x 1x                 15x 2x   15x 1x     15x       11x         4x     11x 3x   8x 7x 7x       3x   2x                 7x     1x 1x   1x  
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
import inject from "@rollup/plugin-inject";
import { dirname, relative, join, resolve } from "path";
import type { FilterPattern } from "@rollup/pluginutils";
// @ts-ignore
import POLYFILLS from "rollup-plugin-polyfill-node/dist/es/polyfills";
import type { InputPluginOption } from "rollup";
// @ts-ignore
import { v4 as uuid } from "uuid";
import { getModules, Polyfill, PolyfillFilter } from "./modules";
 
export type PolyFillOptions = {
  exclude?: FilterPattern;
  sourceMap?: boolean;
  baseDir?: string;
  polyfillFilter?: Partial<PolyfillFilter>;
 
  // When rollup used to bundle a package named after a node builtin,
  // it shouldn't be treated as a polyfill.
  // resolveEntryPoints can be used to determine what goes in the bundle of such packages.
  // If resolveEntryPoints == true, invoking rollup on a package named 'buffer' will resolve
  // to the polyfill and not the package on disk.
  resolveEntryPoints?: boolean;
};
 
function polyfill(opts: PolyFillOptions = {}): InputPluginOption {
  const libs = getModules(opts.polyfillFilter);
  const PREFIX = `\0polyfill-node.`;
  const PREFIX_LENGTH = PREFIX.length;
  const injectPlugin = inject({
    include: "**/*.js",
    exclude: opts.exclude,
    sourceMap: opts.sourceMap,
    modules: {
      process: PREFIX + "process",
      console: PREFIX + "console",
      Buffer: [PREFIX + "buffer", "Buffer"],
      global: PREFIX + "global",
      __filename: FILENAME_PATH,
      __dirname: DIRNAME_PATH,
    },
  });
  const basedir = opts.baseDir || "/";
  const dirs = new Map();
 
  return {
    name: "node-polyfills",
    resolveId(
      importee: string,
      importer: string | undefined,
      options?: { isEntry?: boolean },
    ) {
      if (opts.resolveEntryPoints === false && options?.isEntry) return null;
      // Fixes commonjs compatability: https://github.com/FredKSchott/rollup-plugin-polyfill-node/pull/42
      if (importee[0] == "\0" && /\?commonjs-\w+$/.test(importee)) {
        importee = importee.slice(1).replace(/\?commonjs-\w+$/, "");
      }
      if (importee === DIRNAME_PATH && importer) {
        const id = getRandomId();
        dirs.set(id, dirname("/" + relative(basedir, importer)));
        return { id, moduleSideEffects: false };
      }
      if (importee === FILENAME_PATH && importer) {
        const id = getRandomId();
        dirs.set(id, dirname("/" + relative(basedir, importer)));
        return { id, moduleSideEffects: false };
      }
      if (importer && importer.startsWith(PREFIX) && importee.startsWith(".")) {
        importee =
          PREFIX +
          join(
            importer.substring(PREFIX_LENGTH).replace(".js", ""),
            "..",
            importee,
          ) +
          ".js";
      }
      if (importee.startsWith(PREFIX)) {
        importee = importee.substring(PREFIX_LENGTH);
      }
      if (importee.startsWith("node:")) {
        importee = importee.substring("node:".length);
      }
 
      if (
        libs.has(importee as Polyfill) ||
        POLYFILLS[importee.replace(".js", "") + ".js"]
      ) {
        return {
          id: PREFIX + importee.replace(".js", "") + ".js",
          moduleSideEffects: false,
        };
      }
      return null;
    },
    load(id: string) {
      if (dirs.has(id)) {
        return `export default '${dirs.get(id)}'`;
      }
      if (id.startsWith(PREFIX)) {
        const importee = id.substring(PREFIX_LENGTH).replace(".js", "");
        return libs.get(importee as Polyfill) || POLYFILLS[importee + ".js"];
      }
    },
    transform(code: string, id: string) {
      if (id === PREFIX + "global.js") return;
      // @ts-ignore
      return injectPlugin.transform.call(
        this,
        code,
        id.replace(PREFIX, resolve("node_modules", "polyfill-node")),
      );
    },
  };
}
function getRandomId() {
  return uuid().replaceAll("-", "");
}
 
const DIRNAME_PATH = "\0node-polyfills:dirname";
const FILENAME_PATH = "\0node-polyfills:filename";
 
export default polyfill;