domma-cms 0.25.1 → 0.25.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "domma-cms",
3
- "version": "0.25.1",
3
+ "version": "0.25.2",
4
4
  "description": "File-based CMS powered by Domma and Fastify. Run npx domma-cms my-site to create a new project.",
5
5
  "type": "module",
6
6
  "main": "server/server.js",
@@ -23,7 +23,8 @@
23
23
  "scripts/",
24
24
  "docs/",
25
25
  "CHANGELOG.md",
26
- "CLAUDE.md"
26
+ "CLAUDE.md",
27
+ "FEATURES.md"
27
28
  ],
28
29
  "scripts": {
29
30
  "test": "node --test --test-concurrency=1 'tests/**/*.test.js'",
@@ -1177,12 +1177,26 @@ export function parseShortcodeAttrs(attrStr) {
1177
1177
  * @param {string} markdown
1178
1178
  * @returns {{ scrubbed: string, restore: (s: string) => string }}
1179
1179
  */
1180
+ /**
1181
+ * Monotonic id namespacing each scrubCodeRegions call. Scrub/restore pairs
1182
+ * NEST: a shortcode handler may run nested processors (processCardBlocks,
1183
+ * processGridBlocks, …) on an already-scrubbed body, and each of those scrubs
1184
+ * again. Without a per-call id, the inner restore's regex also matched the
1185
+ * OUTER call's placeholders and looked them up in the wrong store —
1186
+ * `store[idx]` → undefined, which surfaced as literal "undefined" strings
1187
+ * wherever inline code appeared inside [reveal]/effects bodies. With the id,
1188
+ * each restore only touches its own placeholders and the outer restore picks
1189
+ * up the rest on the way out.
1190
+ */
1191
+ let scrubCallId = 0;
1192
+
1180
1193
  export function scrubCodeRegions(markdown) {
1194
+ const callId = ++scrubCallId;
1181
1195
  const store = [];
1182
1196
  const placeholder = (s) => {
1183
1197
  const idx = store.length;
1184
1198
  store.push(s);
1185
- return `\x02SC${idx}\x03`;
1199
+ return `\x02SC${callId}:${idx}\x03`;
1186
1200
  };
1187
1201
 
1188
1202
  // HTML <pre><code>...</code></pre> blocks (rendered by earlier marked.parse calls inside accordion/carousel etc.)
@@ -1192,7 +1206,7 @@ export function scrubCodeRegions(markdown) {
1192
1206
  // Inline code spans (single or multiple backticks, non-greedy)
1193
1207
  scrubbed = scrubbed.replace(/`+[^`\n]+`+/g, placeholder);
1194
1208
 
1195
- const restore = (s) => s.replace(/\x02SC(\d+)\x03/g, (_, i) => store[parseInt(i, 10)]);
1209
+ const restore = (s) => s.replace(new RegExp(`\\x02SC${callId}:(\\d+)\\x03`, 'g'), (_, i) => store[parseInt(i, 10)]);
1196
1210
  return {scrubbed, restore};
1197
1211
  }
1198
1212
 
@@ -1306,7 +1320,9 @@ function processEffectsBlocks(markdown) {
1306
1320
  if (attrs.continuous === 'true') classes.push('firework-continuous');
1307
1321
  if (attrs.hover === 'true') classes.push('firework-on-hover');
1308
1322
  if (body === null) return `<div class="${classes.join(' ')}"></div>`;
1309
- const innerHtml = marked.parse(processCardBlocks(processGridBlocks(body.trim())));
1323
+ // Restore code placeholders before the nested parse (tabs-handler
1324
+ // pattern) so code spans/fences render as <code>, not raw backticks.
1325
+ const innerHtml = marked.parse(processCardBlocks(processGridBlocks(restore(body.trim()))));
1310
1326
  return `<div class="${classes.join(' ')}">${innerHtml}</div>\n`;
1311
1327
  });
1312
1328
 
@@ -1321,7 +1337,9 @@ function processEffectsBlocks(markdown) {
1321
1337
  const dataAttrs = Object.entries(attrs).map(([k, v]) => ` data-fx-${k}="${escapeAttr(v)}"`).join('');
1322
1338
  const hasActions = /\[\s*(render|wait|undo|redraw)\b/.test(body);
1323
1339
  if (!hasActions) {
1324
- const innerHtml = marked.parse(processCardBlocks(processGridBlocks(body.trim())));
1340
+ // Restore code placeholders before the nested parse (tabs-handler
1341
+ // pattern) so code spans/fences render as <code>, not raw backticks.
1342
+ const innerHtml = marked.parse(processCardBlocks(processGridBlocks(restore(body.trim()))));
1325
1343
  return `<div class="dm-fx-scribe"${dataAttrs}>${innerHtml}</div>\n`;
1326
1344
  }
1327
1345
  const actions = [];
@@ -1358,7 +1376,9 @@ function processEffectsBlocks(markdown) {
1358
1376
  if (body === null) return '';
1359
1377
  const attrs = parseShortcodeAttrs(attrStr);
1360
1378
  const dataAttrs = Object.entries(attrs).map(([k, v]) => ` data-fx-${k}="${v}"`).join('');
1361
- const innerHtml = marked.parse(processCardBlocks(processGridBlocks(body.trim())));
1379
+ // Restore code placeholders before the nested parse (tabs-handler
1380
+ // pattern) so code spans/fences render as <code>, not raw backticks.
1381
+ const innerHtml = marked.parse(processCardBlocks(processGridBlocks(restore(body.trim()))));
1362
1382
  return `<div class="dm-fx-${name}"${dataAttrs}>${innerHtml}</div>\n`;
1363
1383
  });
1364
1384
  }
@@ -1373,7 +1393,9 @@ function processEffectsBlocks(markdown) {
1373
1393
  if (body === null) {
1374
1394
  return `<div class="dm-fx-ticker-tape" data-fx-mode="page"${dataAttrs}></div>`;
1375
1395
  }
1376
- const innerHtml = marked.parse(processCardBlocks(processGridBlocks(body.trim())));
1396
+ // Restore code placeholders before the nested parse (tabs-handler
1397
+ // pattern) so code spans/fences render as <code>, not raw backticks.
1398
+ const innerHtml = marked.parse(processCardBlocks(processGridBlocks(restore(body.trim()))));
1377
1399
  return `<div class="dm-fx-ticker-tape" data-fx-mode="container"${dataAttrs}>${innerHtml}</div>\n`;
1378
1400
  });
1379
1401
 
@@ -1385,7 +1407,7 @@ function processEffectsBlocks(markdown) {
1385
1407
  if (attrs.duration) classes.push(`animate-duration-${attrs.duration}`);
1386
1408
  if (attrs.delay) classes.push(`animate-delay-${attrs.delay}`);
1387
1409
  if (attrs.repeat) classes.push(`animate-${attrs.repeat}`);
1388
- return `<div class="${classes.join(' ')}">${marked.parse(processCardBlocks(processGridBlocks(body.trim())))}</div>\n`;
1410
+ return `<div class="${classes.join(' ')}">${marked.parse(processCardBlocks(processGridBlocks(restore(body.trim()))))}</div>\n`;
1389
1411
  });
1390
1412
 
1391
1413
  apply('ambient', (attrStr, body) => {
@@ -1395,7 +1417,7 @@ function processEffectsBlocks(markdown) {
1395
1417
  if (attrs.type) classes.push(`bg-ambient-${attrs.type}`);
1396
1418
  if (attrs.speed) classes.push(`bg-ambient-${attrs.speed}`);
1397
1419
  if (attrs.intensity) classes.push(`bg-ambient-${attrs.intensity}`);
1398
- return `<div class="${classes.join(' ')}">${marked.parse(processCardBlocks(processGridBlocks(body.trim())))}</div>\n`;
1420
+ return `<div class="${classes.join(' ')}">${marked.parse(processCardBlocks(processGridBlocks(restore(body.trim()))))}</div>\n`;
1399
1421
  });
1400
1422
 
1401
1423
  return restore(result);