- syncDecorations.mjs tracks which slugs its regex actually removed and exits 1 without writing if that set doesn't match the missing assets, instead of silently no-op'ing on a reformatted catalog. - patch-folds.mjs matches a 4-line context block, reports the installed folds version and expected snippet when the target is missing, and distinguishes "already patched" (exit 0) from "pattern not found" (exit 1). Verified against all three states. Fixes #88 Fixes #55 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
64 lines
2.6 KiB
JavaScript
64 lines
2.6 KiB
JavaScript
import { readFileSync, writeFileSync } from 'fs';
|
|
import { fileURLToPath } from 'url';
|
|
import { join, dirname } from 'path';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const foldsPath = join(__dirname, '../node_modules/folds/dist/index.js');
|
|
const foldsPkgPath = join(__dirname, '../node_modules/folds/package.json');
|
|
|
|
// Context lines around the target, not just the single `children: src(filled)`
|
|
// expression, so a coincidental match elsewhere in the bundle (e.g. some other
|
|
// `src(filled)` call) can't be mistaken for the Icon component we're patching.
|
|
// This is still string matching, not an AST edit, but the extra context makes
|
|
// an accidental match far less likely (Gitea #55).
|
|
const original = [' ...props,', ' ref,', ' children: src(filled)', ' }'].join(
|
|
'\n',
|
|
);
|
|
const patched = [
|
|
' ...props,',
|
|
' ref,',
|
|
' children: typeof src === "function" ? src(filled) : null',
|
|
' }',
|
|
].join('\n');
|
|
|
|
function foldsVersion() {
|
|
try {
|
|
return JSON.parse(readFileSync(foldsPkgPath, 'utf8')).version ?? 'unknown';
|
|
} catch {
|
|
return 'unknown';
|
|
}
|
|
}
|
|
|
|
try {
|
|
const content = readFileSync(foldsPath, 'utf8');
|
|
|
|
if (content.includes(patched)) {
|
|
// Already patched (e.g. re-running postinstall, or a fresh checkout that
|
|
// already has a patched node_modules cache) — no-op, exit 0.
|
|
console.log('folds patch already applied.');
|
|
} else if (content.includes(original)) {
|
|
writeFileSync(foldsPath, content.replace(original, patched), 'utf8');
|
|
console.log('Applied defensive Icon src guard to folds.');
|
|
} else {
|
|
// Genuine "patch could not be applied" case: neither the original nor the
|
|
// patched form was found, meaning folds changed the Icon implementation.
|
|
// Fail loudly so the postinstall hook / CI breaks instead of silently
|
|
// shipping an unpatched folds (which crashes at render with "src is not a
|
|
// function"). See LOTUS_TODO.md "Dependencies / Build / Hygiene" for
|
|
// context on why this is a direct node_modules patch rather than
|
|
// patch-package.
|
|
console.error('ERROR: folds Icon patch target not found.');
|
|
console.error(` folds version installed: ${foldsVersion()}`);
|
|
console.error(` Expected to find (surrounding context):\n${original}`);
|
|
console.error(
|
|
' folds likely changed its Icon implementation. Update the patch target ' +
|
|
'in scripts/patch-folds.mjs (see LOTUS_TODO -> "Dependencies / Build / Hygiene" ' +
|
|
'-> patch-folds.mjs entry) before building.',
|
|
);
|
|
process.exit(1);
|
|
}
|
|
} catch (e) {
|
|
console.error('ERROR: Could not patch folds:', e.message);
|
|
process.exit(1);
|
|
}
|