fix(ci): keep postinstall script self-contained

This commit is contained in:
Peter Steinberger
2026-04-29 01:20:36 +01:00
parent 45f3074ee6
commit a820a307df

View File

@@ -21,9 +21,8 @@ import {
unlinkSync,
writeFileSync,
} from "node:fs";
import { basename, dirname, isAbsolute, join, relative } from "node:path";
import { basename, dirname, isAbsolute, join, posix, relative } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { expandPackageDistImportClosure } from "./lib/package-dist-imports.mjs";
import { resolveNpmRunner } from "./npm-runner.mjs";
export const BUNDLED_PLUGIN_INSTALL_TARGETS = [];
@@ -272,6 +271,137 @@ function pruneEmptyDistDirectories(params = {}) {
prune(distRoot.distDir);
}
const JS_DIST_FILE_RE = /^dist\/.*\.(?:cjs|js|mjs)$/u;
function stripSpecifierSuffix(value) {
return value.replace(/[?#].*$/u, "");
}
function resolveDistImportPath(importerPath, specifier) {
if (!specifier.startsWith(".")) {
return null;
}
const stripped = stripSpecifierSuffix(specifier);
if (!stripped) {
return null;
}
return posix.normalize(posix.join(posix.dirname(importerPath), stripped));
}
function findStatementStart(source, index) {
return (
Math.max(
source.lastIndexOf(";", index),
source.lastIndexOf("{", index),
source.lastIndexOf("}", index),
source.lastIndexOf("\n", index),
source.lastIndexOf("\r", index),
) + 1
);
}
function isImportSpecifierContext(source, index) {
const dynamicPrefix = source.slice(Math.max(0, index - 32), index);
if (/\bimport\s*\(\s*$/u.test(dynamicPrefix)) {
return true;
}
const statementPrefix = source.slice(findStatementStart(source, index), index).trimStart();
return (
/^(?:import|export)\b[\s\S]*\bfrom\s*$/u.test(statementPrefix) ||
/^import\s*$/u.test(statementPrefix)
);
}
function collectImportSpecifiers(source) {
const specifiers = [];
let inBlockComment = false;
let inLineComment = false;
for (let index = 0; index < source.length; index += 1) {
if (inBlockComment) {
if (source[index] === "*" && source[index + 1] === "/") {
inBlockComment = false;
index += 1;
}
continue;
}
if (inLineComment) {
if (source[index] === "\n" || source[index] === "\r") {
inLineComment = false;
}
continue;
}
if (source[index] === "/" && source[index + 1] === "*") {
inBlockComment = true;
index += 1;
continue;
}
if (source[index] === "/" && source[index + 1] === "/") {
inLineComment = true;
index += 1;
continue;
}
const quote = source[index];
if (quote !== '"' && quote !== "'") {
continue;
}
let cursor = index + 1;
let value = "";
while (cursor < source.length) {
const char = source[cursor];
if (char === "\\") {
value += source.slice(cursor, cursor + 2);
cursor += 2;
continue;
}
if (char === quote) {
break;
}
value += char;
cursor += 1;
}
if (cursor >= source.length) {
break;
}
if (value.startsWith(".") && isImportSpecifierContext(source, index)) {
specifiers.push(value);
}
index = cursor;
}
return specifiers;
}
function expandInstalledDistImportClosure(params) {
const files = [...new Set(params.files)];
const fileSet = new Set(files);
const expectedSet = new Set(params.seedFiles);
let changed = true;
while (changed) {
changed = false;
for (const importerPath of [...expectedSet]
.filter((file) => fileSet.has(file))
.toSorted((left, right) => left.localeCompare(right))) {
if (!JS_DIST_FILE_RE.test(importerPath) || importerPath.includes("/node_modules/")) {
continue;
}
const source = params.readText(importerPath);
for (const specifier of collectImportSpecifiers(source)) {
const importedPath = resolveDistImportPath(importerPath, specifier);
if (!importedPath || !fileSet.has(importedPath) || expectedSet.has(importedPath)) {
continue;
}
expectedSet.add(importedPath);
changed = true;
}
}
}
return [...expectedSet].toSorted((left, right) => left.localeCompare(right));
}
export function pruneInstalledPackageDist(params = {}) {
const packageRoot = params.packageRoot ?? DEFAULT_PACKAGE_ROOT;
const removeFile = params.unlinkSync ?? unlinkSync;
@@ -295,7 +425,7 @@ export function pruneInstalledPackageDist(params = {}) {
const installedFiles = listInstalledDistFiles(params);
const readFile = params.readFileSync ?? readFileSync;
expectedFiles = new Set(
expandPackageDistImportClosure({
expandInstalledDistImportClosure({
files: installedFiles,
seedFiles: [...expectedFiles],
readText(relativePath) {