fix(build): postinstall script patches flowbite-svelte TypeScript optional params

flowbite-svelte ships TypeScript optional-param syntax (x?: string, event?: MouseEvent,
date?: Date) in its dist .svelte files. Vite's esbuild dep pre-bundler processes these
files (via dist/*/index.js re-exports) and fails with "Unexpected '?'" parse errors
whenever the lockfile changes and the dep cache is rebuilt.

- Add scripts/postinstall.mjs: patches 4 specific TypeScript signatures in
  CommandPalette.svelte, ScrollSpy.svelte, and Datepicker.svelte after every npm install.
  Patches are idempotent and targeted — only the ?-in-param-position syntax is removed;
  optional-chaining (?.) in function bodies is untouched.
- Add "postinstall" script to package.json to run it automatically.
- Upgrade flowbite-svelte 1.31.0 → 1.33.1 (both have the same issue; 1.33.1 is current).
- npm update now works without breaking the dev server.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-06-22 18:33:53 -04:00
parent 99c4934045
commit 9c30d4618a
3 changed files with 436 additions and 315 deletions

674
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,8 @@
"build:docker:dev": "docker compose -f ../aether_container_env/docker-compose.yml build ae_app && docker compose -f ../aether_container_env/docker-compose.yml up -d ae_app", "build:docker:dev": "docker compose -f ../aether_container_env/docker-compose.yml build ae_app && docker compose -f ../aether_container_env/docker-compose.yml up -d ae_app",
"compose:down": "docker compose -f ../aether_container_env/docker-compose.yml --profile database down", "compose:down": "docker compose -f ../aether_container_env/docker-compose.yml --profile database down",
"deploy:remote:test": "ssh linode.oneskyit.com 'bash /srv/env/test_aether/deploy.sh test'", "deploy:remote:test": "ssh linode.oneskyit.com 'bash /srv/env/test_aether/deploy.sh test'",
"deploy:remote:prod": "ssh linode.oneskyit.com 'bash /srv/env/prod_aether/deploy.sh prod'" "deploy:remote:prod": "ssh linode.oneskyit.com 'bash /srv/env/prod_aether/deploy.sh prod'",
"postinstall": "node scripts/postinstall.mjs"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "9.39.4", "@eslint/js": "9.39.4",
@@ -108,7 +109,7 @@
"@tailwindcss/vite": "^4.3.0", "@tailwindcss/vite": "^4.3.0",
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"dexie": "^4.0.0", "dexie": "^4.0.0",
"flowbite-svelte": "1.31.0", "flowbite-svelte": "1.33.1",
"html5-qrcode": "^2.3.8", "html5-qrcode": "^2.3.8",
"marked": "17.0.6", "marked": "17.0.6",
"openai": "^6.10.0", "openai": "^6.10.0",

72
scripts/postinstall.mjs Normal file
View File

@@ -0,0 +1,72 @@
#!/usr/bin/env node
/**
* Postinstall: strip TypeScript optional-param syntax from flowbite-svelte dist files.
*
* flowbite-svelte ships raw .svelte files with `<script lang="ts">` in its dist.
* esbuild (used by Vite's dep pre-bundler) cannot parse TypeScript optional params
* like `(x?: string)` or `event?` in function signatures — it fails with
* "Unexpected '?'" or "Expected ')' but found '?'" errors.
*
* The patches below remove only the TypeScript syntax that causes esbuild to fail.
* The `?.` optional-chaining calls in function bodies are left untouched (those are
* valid JavaScript and handle undefined correctly at runtime).
*
* This runs automatically via `"postinstall": "node scripts/postinstall.mjs"` and
* is safe to re-run — the replacements are idempotent.
*/
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { resolve } from 'node:path';
const root = fileURLToPath(new URL('..', import.meta.url));
const dist = resolve(root, 'node_modules/flowbite-svelte/dist');
if (!existsSync(dist)) {
console.log('postinstall: flowbite-svelte dist not found, skipping.');
process.exit(0);
}
let patched = 0;
function patch(relPath, from, to) {
const file = resolve(dist, relPath);
if (!existsSync(file)) return;
const original = readFileSync(file, 'utf8');
const updated = original.replace(from, to);
if (updated !== original) {
writeFileSync(file, updated, 'utf8');
console.log(` patched: ${relPath}`);
patched++;
}
}
// CommandPalette.svelte: (x?: string) => x?.toLowerCase()...
// Remove optional type annotation from the `check` helper param.
patch(
'command-palette/CommandPalette.svelte',
/\(x\?:\s*string\)/g,
'(x)'
);
// ScrollSpy.svelte: function scrollToSection(itemId: string, event?: MouseEvent)
// Remove type annotations from both params.
patch(
'scroll-spy/ScrollSpy.svelte',
/scrollToSection\(itemId:\s*string,\s*event\?:\s*MouseEvent\)/g,
'scrollToSection(itemId, event)'
);
// Datepicker.svelte: two functions with optional typed params + return-type annotations.
patch(
'datepicker/Datepicker.svelte',
/\(date\?:\s*Date\):\s*string/g,
'(date)'
);
patch(
'datepicker/Datepicker.svelte',
/\(date1\?:\s*Date,\s*date2\?:\s*Date\):\s*boolean/g,
'(date1, date2)'
);
console.log(`postinstall: flowbite-svelte — ${patched} file(s) patched.`);