|
- #!/usr/bin/env node
- // One-shot migration: sanitize existing card.fullContent in data/cards.txt.
- // Backups the original to data/cards.txt.bak-<timestamp> before rewriting.
- // Run: `node scripts/sanitize-existing-cards.mjs`.
-
- import { readFile, writeFile, copyFile } from 'node:fs/promises';
- import { resolve, dirname } from 'node:path';
- import { fileURLToPath } from 'node:url';
- import sanitizeHtml from 'sanitize-html';
-
- const __dirname = dirname(fileURLToPath(import.meta.url));
- const CARDS_PATH = resolve(__dirname, '..', 'data', 'cards.txt');
-
- // Keep this config in sync with lib/sanitize.ts
- const CARD_HTML_CONFIG = {
- allowedTags: [
- 'p', 'br', 'strong', 'em', 'b', 'i', 'u',
- 'ul', 'ol', 'li',
- 'a',
- 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
- 'blockquote',
- 'span',
- ],
- allowedAttributes: {
- a: ['href', 'title', 'target', 'rel'],
- span: ['class'],
- '*': [],
- },
- allowedSchemes: ['http', 'https', 'mailto', 'tel'],
- allowedSchemesAppliedToAttributes: ['href'],
- transformTags: {
- a: sanitizeHtml.simpleTransform('a', { rel: 'noopener noreferrer', target: '_blank' }),
- },
- disallowedTagsMode: 'discard',
- };
-
- async function main() {
- let raw;
- try {
- raw = await readFile(CARDS_PATH, 'utf-8');
- } catch (err) {
- if (err.code === 'ENOENT') {
- console.log(`No cards file at ${CARDS_PATH}, nothing to do.`);
- return;
- }
- throw err;
- }
-
- let cards;
- try {
- cards = JSON.parse(raw);
- } catch (err) {
- console.error('Cards file is not valid JSON; refusing to migrate.', err.message);
- process.exit(1);
- }
-
- if (!Array.isArray(cards)) {
- console.error('Cards file is not an array; refusing to migrate.');
- process.exit(1);
- }
-
- const ts = new Date().toISOString().replace(/[:.]/g, '-');
- const backupPath = `${CARDS_PATH}.bak-${ts}`;
- await copyFile(CARDS_PATH, backupPath);
- console.log(`Backup written: ${backupPath}`);
-
- let changed = 0;
- for (const card of cards) {
- if (typeof card?.fullContent === 'string' && card.fullContent.length > 0) {
- const cleaned = sanitizeHtml(card.fullContent, CARD_HTML_CONFIG);
- if (cleaned !== card.fullContent) {
- card.fullContent = cleaned;
- changed++;
- }
- }
- }
-
- await writeFile(CARDS_PATH, JSON.stringify(cards, null, 2), 'utf-8');
- console.log(`Migration done. Cards changed: ${changed} / ${cards.length}.`);
- }
-
- main().catch(err => {
- console.error(err);
- process.exit(1);
- });
|