Files
cinny/scripts/patch-folds.mjs
T
jaredandClaude Opus 5 c5082a78ef
CI / Build & Quality Checks (push) Successful in 1m28s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 6s
CI / Trigger Desktop Build (push) Successful in 6s
CI / Playwright smoke (e2e) (push) Successful in 2m7s
docs: move the LOTUS_TODO / LOTUS_TESTING backlogs into Gitea issues; keep a reference-only LOTUS_REFERENCE.md
LOTUS_TODO.md → LOTUS_REFERENCE.md (design laws, decided deferrals,
server-blocked features, operational reference only). Every open task was
filed: cinny #195–#210, cinny-desktop #15–#18, matrix #8–#10.

LOTUS_TESTING.md keeps the automated-coverage map, the Playwright notes and
the deploy tip; every manual checklist is now a `qa` issue under the
'Manual QA backlog' (cinny #170–#194, #198) and 'Desktop QA backlog'
(cinny-desktop #11–#14, #18) milestones.

Repointed the README, LOTUS_FEATURES, CI and source comments that
referenced LOTUS_TODO.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
2026-09-17 23:26:21 -04:00

64 lines
2.5 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 cinny #210 (build hygiene notes) 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 cinny #210 ' +
'-> patch-folds.mjs entry) before building.',
);
process.exit(1);
}
} catch (e) {
console.error('ERROR: Could not patch folds:', e.message);
process.exit(1);
}