@fro.bot/wiki-write-core 0.1.3 → 0.2.0

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.
@@ -2,38 +2,38 @@ import { Buffer } from 'node:buffer';
2
2
  import { basename } from 'node:path';
3
3
  import { parse } from 'yaml';
4
4
  import { findCodeRegions, findRegionAt } from "./code-regions.js";
5
+ import { splitFrontmatterBlock } from "./frontmatter-block.js";
5
6
  /** Canonical root directory for wiki page content. Shared by every wiki script. */
6
7
  export const WIKI_ROOT = 'knowledge/wiki';
7
8
  /**
8
9
  * Split raw wiki page content into frontmatter and body.
9
10
  *
10
- * Stricter than a naive split: malformed YAML frontmatter is surfaced via `error`
11
- * rather than silently discarded, so downstream safety/lint logic can observe it.
11
+ * Stricter than a naive split: malformed YAML frontmatter, and a block that is opened and never closed, are
12
+ * surfaced via `error` rather than silently discarded, so downstream safety/lint logic can observe them.
12
13
  */
13
14
  export function splitFrontmatter(content) {
14
- const match = /^---\n([\s\S]+?)\n---\n?/u.exec(content);
15
- if (match === null) {
15
+ const split = splitFrontmatterBlock(content);
16
+ if (split.kind === 'none') {
16
17
  return { frontmatter: {}, body: content.trim() };
17
18
  }
18
- const frontmatterText = match[1];
19
- if (frontmatterText === undefined) {
20
- return { frontmatter: {}, body: content.trim() };
19
+ if (split.kind === 'malformed') {
20
+ return { frontmatter: {}, body: content.trim(), error: 'Invalid frontmatter: missing closing --- delimiter' };
21
21
  }
22
22
  let parsed;
23
23
  try {
24
- parsed = parse(frontmatterText);
24
+ parsed = parse(split.text);
25
25
  }
26
26
  catch (error) {
27
27
  const message = error instanceof Error ? error.message : 'Unknown YAML parse error';
28
28
  return {
29
29
  frontmatter: {},
30
- body: content.slice(match[0].length).trim(),
30
+ body: split.body.trim(),
31
31
  error: `Invalid YAML frontmatter: ${message}`,
32
32
  };
33
33
  }
34
34
  return {
35
35
  frontmatter: isRecord(parsed) ? parsed : {},
36
- body: content.slice(match[0].length).trim(),
36
+ body: split.body.trim(),
37
37
  };
38
38
  }
39
39
  /**
@@ -200,9 +200,12 @@ export function truncateToBytes(value, maxBytes) {
200
200
  if (contentBudget <= 0) {
201
201
  return '';
202
202
  }
203
- const truncated = Buffer.from(value)
204
- .subarray(0, contentBudget)
205
- .toString('utf8')
206
- .replaceAll(/\uFFFD+$/gu, '');
203
+ const decoded = Buffer.from(value).subarray(0, contentBudget).toString('utf8');
204
+ // Drop the replacement characters a cut multi-byte sequence decodes to. A trailing-run regex rescans a long run
205
+ // from every position in it.
206
+ let keep = decoded.length;
207
+ while (keep > 0 && decoded.charCodeAt(keep - 1) === 0xff_fd)
208
+ keep -= 1;
209
+ const truncated = decoded.slice(0, keep);
207
210
  return truncated === '' ? '' : `${truncated}${ellipsis}`;
208
211
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fro.bot/wiki-write-core",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "Shared validation and commit primitives for Fro Bot wiki writes",
5
5
  "homepage": "https://github.com/fro-bot/.github/tree/main/packages/wiki-write-core#readme",
6
6
  "bugs": {