@equationalapplications/core-okf 5.3.1 → 5.4.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.
package/dist/index.mjs CHANGED
@@ -24,6 +24,10 @@ function quoteString(value) {
24
24
  function serializeScalarString(value) {
25
25
  return needsQuoting(value) ? quoteString(value) : value;
26
26
  }
27
+ function serializeActorString(value) {
28
+ if (/[/:]/.test(value)) return quoteString(value);
29
+ return value;
30
+ }
27
31
  function serializeKey(key) {
28
32
  if (/\s/.test(key) || needsQuoting(key) || isIso8601Timestamp(key)) {
29
33
  return quoteString(key);
@@ -35,8 +39,52 @@ function serializeValue(value) {
35
39
  if (typeof value === "boolean") return String(value);
36
40
  if (typeof value === "number") return String(value);
37
41
  if (typeof value === "string") return serializeScalarString(value);
42
+ if (Array.isArray(value)) return serializeFlowSequenceValue(value);
43
+ if (typeof value === "object") return serializeFlowMappingValue(value);
38
44
  throw new Error(`Unsupported frontmatter value type: ${typeof value}`);
39
45
  }
46
+ function needsFlowQuoting(value) {
47
+ return needsQuoting(value) || /[,{}[\]/:]/.test(value);
48
+ }
49
+ function serializeFlowScalarString(value) {
50
+ return needsFlowQuoting(value) ? quoteString(value) : value;
51
+ }
52
+ function serializeFlowMappingValue(obj, depth = 0) {
53
+ const entries = Object.entries(obj).filter(([, v]) => v !== void 0);
54
+ if (entries.length === 0) return "{}";
55
+ const parts = entries.map(([k, v]) => {
56
+ let rendered;
57
+ if (typeof v === "string") rendered = serializeFlowScalarString(v);
58
+ else if (v === null || typeof v === "boolean" || typeof v === "number") rendered = serializeValue(v);
59
+ else if (Array.isArray(v)) {
60
+ if (depth >= 1) throw new Error(`serializeFlowMappingValue: nesting deeper than one level is not supported (key "${k}")`);
61
+ rendered = serializeFlowSequenceValue(v, depth + 1);
62
+ } else if (typeof v === "object") {
63
+ if (depth >= 1) throw new Error(`serializeFlowMappingValue: nesting deeper than one level is not supported (key "${k}")`);
64
+ rendered = serializeFlowMappingValue(v, depth + 1);
65
+ } else {
66
+ throw new Error(`serializeFlowMappingValue: unsupported value type for key "${k}"`);
67
+ }
68
+ return `${serializeKey(k)}: ${rendered}`;
69
+ });
70
+ return `{ ${parts.join(", ")} }`;
71
+ }
72
+ function serializeFlowSequenceValue(arr, depth = 0) {
73
+ if (arr.length === 0) return "[]";
74
+ const parts = arr.map((item) => {
75
+ if (typeof item === "string") return serializeFlowScalarString(item);
76
+ if (item === null || typeof item === "boolean" || typeof item === "number") return serializeValue(item);
77
+ if (item !== null && typeof item === "object" && !Array.isArray(item)) {
78
+ return serializeFlowMappingValue(item, depth);
79
+ }
80
+ if (Array.isArray(item)) {
81
+ if (depth >= 1) throw new Error(`serializeFlowSequenceValue: nested array deeper than one level is not supported`);
82
+ return serializeFlowSequenceValue(item, depth + 1);
83
+ }
84
+ throw new Error("serializeFlowSequenceValue: unsupported item type");
85
+ });
86
+ return `[ ${parts.join(", ")} ]`;
87
+ }
40
88
  function serializeFrontmatter(fm) {
41
89
  const lines = ["---"];
42
90
  for (const [key, value] of Object.entries(fm)) {
@@ -44,16 +92,16 @@ function serializeFrontmatter(fm) {
44
92
  if (Array.isArray(value)) {
45
93
  if (value.length === 0) {
46
94
  lines.push(`${serializeKey(key)}: []`);
95
+ } else if (value.some((item) => item !== null && typeof item === "object")) {
96
+ lines.push(`${serializeKey(key)}: ${serializeFlowSequenceValue(value)}`);
47
97
  } else {
48
98
  lines.push(`${serializeKey(key)}:`);
49
99
  for (const item of value) {
50
- if (typeof item === "string") {
51
- lines.push(` - ${serializeScalarString(item)}`);
52
- } else {
53
- lines.push(` - ${serializeValue(item)}`);
54
- }
100
+ lines.push(` - ${typeof item === "string" ? serializeScalarString(item) : serializeValue(item)}`);
55
101
  }
56
102
  }
103
+ } else if (value !== null && typeof value === "object") {
104
+ lines.push(`${serializeKey(key)}: ${serializeFlowMappingValue(value)}`);
57
105
  } else {
58
106
  lines.push(`${serializeKey(key)}: ${serializeValue(value)}`);
59
107
  }
@@ -132,6 +180,121 @@ function matchFrontmatterKeyValue(line) {
132
180
  const tail = line.slice(key.length + 1);
133
181
  return { key, value: tail.trimStart(), hasValue: tail.trim().length > 0 };
134
182
  }
183
+ function hasUnquotedAnchorOrAlias(text) {
184
+ let quote = null;
185
+ for (let i = 0; i < text.length; i++) {
186
+ const ch = text[i];
187
+ if (quote) {
188
+ if (ch === "\\" && i + 1 < text.length) {
189
+ i++;
190
+ continue;
191
+ }
192
+ if (ch === quote) quote = null;
193
+ continue;
194
+ }
195
+ if (ch === '"' || ch === "'") {
196
+ quote = ch;
197
+ continue;
198
+ }
199
+ if (ch === "&" || ch === "*") return true;
200
+ }
201
+ return false;
202
+ }
203
+ function splitFlowEntries(inner) {
204
+ const entries = [];
205
+ let buf = "";
206
+ let i = 0;
207
+ let quote = null;
208
+ let depthBrace = 0;
209
+ let depthBracket = 0;
210
+ while (i < inner.length) {
211
+ const ch = inner[i];
212
+ if (quote) {
213
+ buf += ch;
214
+ if (ch === "\\" && i + 1 < inner.length) {
215
+ buf += inner[i + 1];
216
+ i += 2;
217
+ continue;
218
+ }
219
+ if (ch === quote) quote = null;
220
+ i++;
221
+ continue;
222
+ }
223
+ if (ch === '"' || ch === "'") {
224
+ quote = ch;
225
+ buf += ch;
226
+ i++;
227
+ continue;
228
+ }
229
+ if (ch === "{") depthBrace++;
230
+ else if (ch === "}") depthBrace--;
231
+ else if (ch === "[") depthBracket++;
232
+ else if (ch === "]") depthBracket--;
233
+ if (ch === "," && depthBrace === 0 && depthBracket === 0) {
234
+ entries.push(buf.trim());
235
+ buf = "";
236
+ i++;
237
+ continue;
238
+ }
239
+ buf += ch;
240
+ i++;
241
+ }
242
+ if (buf.trim().length > 0) entries.push(buf.trim());
243
+ if (depthBrace !== 0 || depthBracket !== 0 || quote !== null) return null;
244
+ return entries;
245
+ }
246
+ function parseFlowMapping(text, depth = 0) {
247
+ const trimmed = text.trim();
248
+ if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return null;
249
+ if (hasUnquotedAnchorOrAlias(trimmed)) return null;
250
+ const inner = trimmed.slice(1, -1).trim();
251
+ if (inner.length === 0) return {};
252
+ const entries = splitFlowEntries(inner);
253
+ if (!entries) return null;
254
+ const out = {};
255
+ for (const entry of entries) {
256
+ const kv = matchFrontmatterKeyValue(entry);
257
+ if (!kv || !kv.hasValue) return null;
258
+ const v = kv.value.trim();
259
+ if (v.startsWith("{") || v.startsWith("[")) {
260
+ if (depth >= 1) return null;
261
+ const nested = v.startsWith("{") ? parseFlowMapping(v, depth + 1) : parseFlowSequence(v, depth + 1);
262
+ if (nested === null) return null;
263
+ out[parseKey(kv.key)] = nested;
264
+ continue;
265
+ }
266
+ out[parseKey(kv.key)] = parseScalarValue(v);
267
+ }
268
+ return out;
269
+ }
270
+ function parseFlowSequence(text, depth = 0) {
271
+ const trimmed = text.trim();
272
+ if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) return null;
273
+ if (hasUnquotedAnchorOrAlias(trimmed)) return null;
274
+ const inner = trimmed.slice(1, -1).trim();
275
+ if (inner.length === 0) return [];
276
+ const entries = splitFlowEntries(inner);
277
+ if (!entries) return null;
278
+ const out = [];
279
+ for (const entry of entries) {
280
+ const v = entry.trim();
281
+ if (v.startsWith("{")) {
282
+ const nested = parseFlowMapping(v, depth);
283
+ if (nested === null) return null;
284
+ out.push(nested);
285
+ continue;
286
+ }
287
+ if (v.startsWith("[")) {
288
+ if (depth >= 1) return null;
289
+ const nested = parseFlowSequence(v, depth + 1);
290
+ if (nested === null) return null;
291
+ out.push(nested);
292
+ continue;
293
+ }
294
+ out.push(parseScalarValue(v));
295
+ }
296
+ return out;
297
+ }
135
298
  function parseFrontmatter(content) {
136
299
  const lines = content.split(/\r?\n/);
137
300
  const fallback = { frontmatter: { type: "" }, rest: content };
@@ -169,6 +332,34 @@ function parseFrontmatter(content) {
169
332
  frontmatter[key] = items;
170
333
  continue;
171
334
  }
335
+ const valueRaw = kv.value.trim();
336
+ if (valueRaw.startsWith("{")) {
337
+ const flowObj = parseFlowMapping(valueRaw);
338
+ if (flowObj !== null) {
339
+ frontmatter[parseKey(kv.key)] = flowObj;
340
+ i++;
341
+ continue;
342
+ }
343
+ frontmatter[parseKey(kv.key)] = null;
344
+ i++;
345
+ continue;
346
+ }
347
+ if (valueRaw.startsWith("[")) {
348
+ if (valueRaw === "[]") {
349
+ frontmatter[parseKey(kv.key)] = [];
350
+ i++;
351
+ continue;
352
+ }
353
+ const flowSeq = parseFlowSequence(valueRaw);
354
+ if (flowSeq !== null) {
355
+ frontmatter[parseKey(kv.key)] = flowSeq;
356
+ i++;
357
+ continue;
358
+ }
359
+ frontmatter[parseKey(kv.key)] = null;
360
+ i++;
361
+ continue;
362
+ }
172
363
  frontmatter[parseKey(kv.key)] = parseScalarValue(kv.value);
173
364
  i++;
174
365
  }
@@ -425,6 +616,181 @@ function extractMarkdownLinks(body) {
425
616
  return links;
426
617
  }
427
618
 
428
- export { appendEventIdComment, appendRelatedSection, buildConceptDocument, buildEntityIndexMd, buildIndexMd, buildLogMd, buildRootIndexMd, extractMarkdownLinks, isAllowedOkfPath, parseConcept, parseEntityIndexMd, parseEventIdComment, parseFrontmatter, parseLogMd, parseRootIndexMd, serializeFrontmatter, splitRelatedSection };
619
+ // src/footnotes.ts
620
+ var FOOTNOTE_DEFINITION = /^\[\^([^\]]+)\]:\s?(.*)$/;
621
+ function extractFootnotes(body) {
622
+ const out = [];
623
+ const lines = body.split(/\r?\n/);
624
+ let i = 0;
625
+ while (i < lines.length) {
626
+ const m = FOOTNOTE_DEFINITION.exec(lines[i]);
627
+ if (!m) {
628
+ i++;
629
+ continue;
630
+ }
631
+ const id = m[1];
632
+ const firstLine = m[2] ?? "";
633
+ const collected = [firstLine];
634
+ i++;
635
+ while (i < lines.length) {
636
+ const next = lines[i];
637
+ if (FOOTNOTE_DEFINITION.test(next)) break;
638
+ if (/^\s{2,}\S/.test(next) || /^\s{2,}/.test(next)) {
639
+ collected.push(next.replace(/^\s{2}/, ""));
640
+ i++;
641
+ continue;
642
+ }
643
+ break;
644
+ }
645
+ out.push({ id, body: collected.join("\n").trimEnd() });
646
+ }
647
+ return out;
648
+ }
649
+ function serializeFootnotes(footnotes) {
650
+ return footnotes.map((f) => {
651
+ const lines = f.body.split("\n");
652
+ const [firstLine, ...continuation] = lines;
653
+ const tail = continuation.map((line) => `
654
+ ${line}`).join("");
655
+ return `[^${f.id}]: ${firstLine ?? ""}${tail}`;
656
+ }).join("\n");
657
+ }
658
+
659
+ // src/v02-helpers.ts
660
+ function deriveTrustTier(verified) {
661
+ if (!verified || verified.length === 0) return "unverified";
662
+ for (const v of verified) {
663
+ if (typeof v?.by === "string" && v.by.startsWith("human:")) return "human-reviewed";
664
+ }
665
+ return "machine-confirmed";
666
+ }
667
+ function parseStaleAfter(staleAfter) {
668
+ if (staleAfter == null) return null;
669
+ if (typeof staleAfter === "number") return Number.isFinite(staleAfter) ? staleAfter : null;
670
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(staleAfter);
671
+ if (!match) return null;
672
+ const year = Number(match[1]);
673
+ const month = Number(match[2]);
674
+ const day = Number(match[3]);
675
+ const ts = Date.UTC(year, month - 1, day);
676
+ if (!Number.isFinite(ts)) return null;
677
+ const d = new Date(ts);
678
+ if (d.getUTCFullYear() !== year || d.getUTCMonth() + 1 !== month || d.getUTCDate() !== day) {
679
+ return null;
680
+ }
681
+ return ts;
682
+ }
683
+ function isStaleAfter(staleAfter, now) {
684
+ const cutoff = parseStaleAfter(staleAfter);
685
+ if (cutoff == null) return false;
686
+ return now >= cutoff;
687
+ }
688
+ function parseVerifiedFlexible(value) {
689
+ if (value == null) return [];
690
+ if (Array.isArray(value)) {
691
+ return value.filter(
692
+ (v) => !!v && typeof v === "object" && typeof v.by === "string" && typeof v.at === "string"
693
+ );
694
+ }
695
+ if (typeof value === "object" && typeof value.by === "string" && typeof value.at === "string") {
696
+ return [value];
697
+ }
698
+ return [];
699
+ }
700
+ function formatVerifiedJson(entries) {
701
+ const sorted = [...entries].sort((a, b) => {
702
+ const ta = Date.parse(a.at);
703
+ const tb = Date.parse(b.at);
704
+ const fa = Number.isFinite(ta);
705
+ const fb = Number.isFinite(tb);
706
+ if (fa && fb) return ta - tb;
707
+ if (fa && !fb) return -1;
708
+ if (!fa && fb) return 1;
709
+ return a.at < b.at ? -1 : a.at > b.at ? 1 : 0;
710
+ });
711
+ return JSON.stringify(sorted);
712
+ }
713
+ function formatSourcesJson(sources, sharedWindow) {
714
+ const folded = sources.map(
715
+ (s) => s.usage_window ? s : sharedWindow ? { ...s, usage_window: sharedWindow } : s
716
+ );
717
+ return JSON.stringify(folded);
718
+ }
719
+ function latestVerified(entries, _now) {
720
+ if (!entries || entries.length === 0) return null;
721
+ let best = null;
722
+ let bestAt = -Infinity;
723
+ for (const e of entries) {
724
+ const ts = Date.parse(e.at);
725
+ if (Number.isFinite(ts) && ts > bestAt) {
726
+ best = e;
727
+ bestAt = ts;
728
+ }
729
+ }
730
+ if (!best) return null;
731
+ return { by: best.by, at: bestAt };
732
+ }
733
+ var URL_LINE = /^\s*-\s+(https?:\/\/\S+)\s*$/;
734
+ function parseCitationsList(body) {
735
+ const lines = body.split(/\r?\n/);
736
+ let inFence = false;
737
+ let fenceMarker = "";
738
+ let fenceLength = 0;
739
+ let startIdx = -1;
740
+ const isFenceClose = (marker, fullMatch, line) => {
741
+ if (marker[0] !== fenceMarker) return false;
742
+ if (marker.length < fenceLength) return false;
743
+ return /^\s*$/.test(line.slice(fullMatch.length));
744
+ };
745
+ for (let i = 0; i < lines.length; i++) {
746
+ const line = lines[i];
747
+ const fence = /^\s*(```+|~~~+)/.exec(line);
748
+ if (fence) {
749
+ const marker = fence[1];
750
+ if (!inFence) {
751
+ inFence = true;
752
+ fenceMarker = marker[0];
753
+ fenceLength = marker.length;
754
+ } else if (isFenceClose(marker, fence[0], line)) {
755
+ inFence = false;
756
+ fenceMarker = "";
757
+ fenceLength = 0;
758
+ }
759
+ continue;
760
+ }
761
+ if (!inFence && /^\s*#{1,2}\s*citations\s*$/i.test(line)) {
762
+ startIdx = i;
763
+ break;
764
+ }
765
+ }
766
+ if (startIdx === -1) return [];
767
+ const out = [];
768
+ for (let i = startIdx + 1; i < lines.length; i++) {
769
+ const line = lines[i];
770
+ const fence = /^\s*(```+|~~~+)/.exec(line);
771
+ if (fence) {
772
+ const marker = fence[1];
773
+ if (!inFence) {
774
+ inFence = true;
775
+ fenceMarker = marker[0];
776
+ fenceLength = marker.length;
777
+ continue;
778
+ }
779
+ if (isFenceClose(marker, fence[0], line)) {
780
+ inFence = false;
781
+ fenceMarker = "";
782
+ fenceLength = 0;
783
+ }
784
+ continue;
785
+ }
786
+ if (!inFence && /^\s*#{1,2}\s+/.test(line)) break;
787
+ if (inFence) continue;
788
+ const m = URL_LINE.exec(line);
789
+ if (m) out.push(m[1]);
790
+ }
791
+ return out;
792
+ }
793
+
794
+ export { appendEventIdComment, appendRelatedSection, buildConceptDocument, buildEntityIndexMd, buildIndexMd, buildLogMd, buildRootIndexMd, deriveTrustTier, extractFootnotes, extractMarkdownLinks, formatSourcesJson, formatVerifiedJson, isAllowedOkfPath, isStaleAfter, latestVerified, parseCitationsList, parseConcept, parseEntityIndexMd, parseEventIdComment, parseFlowMapping, parseFlowSequence, parseFrontmatter, parseLogMd, parseRootIndexMd, parseVerifiedFlexible, serializeActorString, serializeFootnotes, serializeFrontmatter, splitRelatedSection };
429
795
  //# sourceMappingURL=index.mjs.map
430
796
  //# sourceMappingURL=index.mjs.map