@bitcobblers/wod-wiki-core 0.10.42 → 0.35.2115
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.cjs +690 -150
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +479 -160
- package/dist/index.d.ts +479 -160
- package/dist/index.mjs +667 -149
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -26,6 +26,88 @@ function getMetricOwnershipLayer(origin) {
|
|
|
26
26
|
return LEGACY_ORIGIN_TO_OWNERSHIP_LAYER[origin ?? "parser"] ?? "parser";
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
// src/models/Metric.ts
|
|
30
|
+
var MetricType = /* @__PURE__ */ ((MetricType2) => {
|
|
31
|
+
MetricType2["Duration"] = "duration";
|
|
32
|
+
MetricType2["Spans"] = "spans";
|
|
33
|
+
MetricType2["SystemTime"] = "system-time";
|
|
34
|
+
MetricType2["Time"] = "time";
|
|
35
|
+
MetricType2["Elapsed"] = "elapsed";
|
|
36
|
+
MetricType2["Total"] = "total";
|
|
37
|
+
MetricType2["Rep"] = "rep";
|
|
38
|
+
MetricType2["Effort"] = "effort";
|
|
39
|
+
MetricType2["Distance"] = "distance";
|
|
40
|
+
MetricType2["Rounds"] = "rounds";
|
|
41
|
+
MetricType2["CurrentRound"] = "current-round";
|
|
42
|
+
MetricType2["Action"] = "action";
|
|
43
|
+
MetricType2["Increment"] = "increment";
|
|
44
|
+
MetricType2["Group"] = "group";
|
|
45
|
+
MetricType2["Text"] = "text";
|
|
46
|
+
MetricType2["Resistance"] = "resistance";
|
|
47
|
+
MetricType2["Sound"] = "sound";
|
|
48
|
+
MetricType2["System"] = "system";
|
|
49
|
+
MetricType2["Label"] = "label";
|
|
50
|
+
MetricType2["Lap"] = "lap";
|
|
51
|
+
MetricType2["Metric"] = "metric";
|
|
52
|
+
MetricType2["Hint"] = "hint";
|
|
53
|
+
MetricType2["Custom"] = "custom";
|
|
54
|
+
MetricType2["Volume"] = "volume";
|
|
55
|
+
MetricType2["Intensity"] = "intensity";
|
|
56
|
+
MetricType2["Grade"] = "grade";
|
|
57
|
+
MetricType2["Load"] = "load";
|
|
58
|
+
MetricType2["Work"] = "work";
|
|
59
|
+
MetricType2["RIR"] = "rir";
|
|
60
|
+
MetricType2["SessionRPE"] = "session-rpe";
|
|
61
|
+
MetricType2["SessionLoad"] = "session-load";
|
|
62
|
+
MetricType2["METScore"] = "met-score";
|
|
63
|
+
MetricType2["TIS"] = "tis";
|
|
64
|
+
MetricType2["Calculated"] = "calculated";
|
|
65
|
+
MetricType2["Choice"] = "choice";
|
|
66
|
+
return MetricType2;
|
|
67
|
+
})(MetricType || {});
|
|
68
|
+
var Metric = class {
|
|
69
|
+
type;
|
|
70
|
+
metricType;
|
|
71
|
+
value;
|
|
72
|
+
origin;
|
|
73
|
+
unit;
|
|
74
|
+
action;
|
|
75
|
+
image;
|
|
76
|
+
sourceBlockKey;
|
|
77
|
+
timestamp;
|
|
78
|
+
metadata;
|
|
79
|
+
name;
|
|
80
|
+
ownershipLayer;
|
|
81
|
+
constructor(typeOrName, valueOrType, originOrValue, unit, origin, action, image) {
|
|
82
|
+
if (typeof valueOrType === "string" && (typeof originOrValue === "number" || typeof originOrValue === "string" || typeof originOrValue === "boolean" || originOrValue === null || originOrValue === void 0)) {
|
|
83
|
+
this.name = String(typeOrName);
|
|
84
|
+
this.type = valueOrType;
|
|
85
|
+
this.metricType = valueOrType;
|
|
86
|
+
this.value = originOrValue;
|
|
87
|
+
this.unit = unit;
|
|
88
|
+
this.origin = origin || "parser";
|
|
89
|
+
this.action = action === "suppress" ? "suppress" : void 0;
|
|
90
|
+
this.image = image ?? String(originOrValue ?? valueOrType);
|
|
91
|
+
} else {
|
|
92
|
+
this.type = typeOrName;
|
|
93
|
+
this.metricType = typeOrName;
|
|
94
|
+
this.value = valueOrType;
|
|
95
|
+
this.origin = originOrValue || "parser";
|
|
96
|
+
this.unit = unit;
|
|
97
|
+
this.action = typeof origin === "string" && origin === "suppress" ? "suppress" : action === "suppress" ? "suppress" : void 0;
|
|
98
|
+
this.image = image ?? String(valueOrType ?? typeOrName);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
toNumber() {
|
|
102
|
+
if (typeof this.value === "number") return this.value;
|
|
103
|
+
if (typeof this.value === "string") {
|
|
104
|
+
const parsed = parseFloat(this.value);
|
|
105
|
+
return isNaN(parsed) ? 0 : parsed;
|
|
106
|
+
}
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
29
111
|
// src/ownership/ledger.ts
|
|
30
112
|
var LAYER_RANK = {
|
|
31
113
|
parser: 0,
|
|
@@ -41,6 +123,10 @@ function resolveLayer(metric) {
|
|
|
41
123
|
}
|
|
42
124
|
return getMetricOwnershipLayer(metric.origin);
|
|
43
125
|
}
|
|
126
|
+
function ownershipRank(metric) {
|
|
127
|
+
const layer = resolveLayer(metric);
|
|
128
|
+
return LAYER_RANK[layer] ?? 0;
|
|
129
|
+
}
|
|
44
130
|
function normalize(metrics) {
|
|
45
131
|
return metrics.map((metric, index) => {
|
|
46
132
|
const layer = resolveLayer(metric);
|
|
@@ -234,98 +320,6 @@ function createMetricOwnershipLedger(metrics) {
|
|
|
234
320
|
}
|
|
235
321
|
};
|
|
236
322
|
}
|
|
237
|
-
|
|
238
|
-
// src/models/Metric.ts
|
|
239
|
-
var MetricType = /* @__PURE__ */ ((MetricType2) => {
|
|
240
|
-
MetricType2["Duration"] = "duration";
|
|
241
|
-
MetricType2["Spans"] = "spans";
|
|
242
|
-
MetricType2["SystemTime"] = "system-time";
|
|
243
|
-
MetricType2["Time"] = "time";
|
|
244
|
-
MetricType2["Elapsed"] = "elapsed";
|
|
245
|
-
MetricType2["Total"] = "total";
|
|
246
|
-
MetricType2["Rep"] = "rep";
|
|
247
|
-
MetricType2["Effort"] = "effort";
|
|
248
|
-
MetricType2["Distance"] = "distance";
|
|
249
|
-
MetricType2["Rounds"] = "rounds";
|
|
250
|
-
MetricType2["CurrentRound"] = "current-round";
|
|
251
|
-
MetricType2["Action"] = "action";
|
|
252
|
-
MetricType2["Increment"] = "increment";
|
|
253
|
-
MetricType2["Group"] = "group";
|
|
254
|
-
MetricType2["Text"] = "text";
|
|
255
|
-
MetricType2["Resistance"] = "resistance";
|
|
256
|
-
MetricType2["Sound"] = "sound";
|
|
257
|
-
MetricType2["System"] = "system";
|
|
258
|
-
MetricType2["Label"] = "label";
|
|
259
|
-
MetricType2["Lap"] = "lap";
|
|
260
|
-
MetricType2["Metric"] = "metric";
|
|
261
|
-
MetricType2["Hint"] = "hint";
|
|
262
|
-
MetricType2["Custom"] = "custom";
|
|
263
|
-
MetricType2["Volume"] = "volume";
|
|
264
|
-
MetricType2["Intensity"] = "intensity";
|
|
265
|
-
MetricType2["Load"] = "load";
|
|
266
|
-
MetricType2["Work"] = "work";
|
|
267
|
-
MetricType2["RIR"] = "rir";
|
|
268
|
-
MetricType2["SessionRPE"] = "session-rpe";
|
|
269
|
-
MetricType2["SessionLoad"] = "session-load";
|
|
270
|
-
MetricType2["METScore"] = "met-score";
|
|
271
|
-
MetricType2["TIS"] = "tis";
|
|
272
|
-
MetricType2["Calculated"] = "calculated";
|
|
273
|
-
MetricType2["Choice"] = "choice";
|
|
274
|
-
return MetricType2;
|
|
275
|
-
})(MetricType || {});
|
|
276
|
-
var Metric = class {
|
|
277
|
-
type;
|
|
278
|
-
metricType;
|
|
279
|
-
value;
|
|
280
|
-
origin;
|
|
281
|
-
unit;
|
|
282
|
-
action;
|
|
283
|
-
image;
|
|
284
|
-
sourceBlockKey;
|
|
285
|
-
timestamp;
|
|
286
|
-
metadata;
|
|
287
|
-
name;
|
|
288
|
-
ownershipLayer;
|
|
289
|
-
constructor(typeOrName, valueOrType, originOrValue, unit, origin, action, image) {
|
|
290
|
-
if (typeof valueOrType === "string" && (typeof originOrValue === "number" || typeof originOrValue === "string" || typeof originOrValue === "boolean" || originOrValue === null || originOrValue === void 0)) {
|
|
291
|
-
this.name = String(typeOrName);
|
|
292
|
-
this.type = valueOrType;
|
|
293
|
-
this.metricType = valueOrType;
|
|
294
|
-
this.value = originOrValue;
|
|
295
|
-
this.unit = unit;
|
|
296
|
-
this.origin = origin || "parser";
|
|
297
|
-
this.action = action === "suppress" ? "suppress" : void 0;
|
|
298
|
-
this.image = image ?? String(originOrValue ?? valueOrType);
|
|
299
|
-
} else {
|
|
300
|
-
this.type = typeOrName;
|
|
301
|
-
this.metricType = typeOrName;
|
|
302
|
-
this.value = valueOrType;
|
|
303
|
-
this.origin = originOrValue || "parser";
|
|
304
|
-
this.unit = unit;
|
|
305
|
-
this.action = typeof origin === "string" && origin === "suppress" ? "suppress" : action === "suppress" ? "suppress" : void 0;
|
|
306
|
-
this.image = image ?? String(valueOrType ?? typeOrName);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
toNumber() {
|
|
310
|
-
if (typeof this.value === "number") return this.value;
|
|
311
|
-
if (typeof this.value === "string") {
|
|
312
|
-
const parsed = parseFloat(this.value);
|
|
313
|
-
return isNaN(parsed) ? 0 : parsed;
|
|
314
|
-
}
|
|
315
|
-
return 0;
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
|
|
319
|
-
// src/ownership/OwnershipResolver.ts
|
|
320
|
-
function resolveLayer2(metric) {
|
|
321
|
-
const maybeLayer = metric.ownershipLayer;
|
|
322
|
-
if (maybeLayer != null) return maybeLayer;
|
|
323
|
-
return getMetricOwnershipLayer(metric.origin ?? "parser");
|
|
324
|
-
}
|
|
325
|
-
function ownershipRank(metric) {
|
|
326
|
-
const layer = resolveLayer2(metric);
|
|
327
|
-
return METRIC_OWNERSHIP_LAYER_CHAIN.indexOf(layer);
|
|
328
|
-
}
|
|
329
323
|
function applyFilter(metrics, filter) {
|
|
330
324
|
let filtered = [...metrics];
|
|
331
325
|
const wantsHints = filter?.types?.includes("hint" /* Hint */) ?? false;
|
|
@@ -360,6 +354,181 @@ var OwnershipResolver = class {
|
|
|
360
354
|
}
|
|
361
355
|
};
|
|
362
356
|
|
|
357
|
+
// src/fields/fieldIdentity.ts
|
|
358
|
+
function splitWords(component) {
|
|
359
|
+
const onSeparators = component.split(/[\s_\-\u2010-\u2015]+/).filter(Boolean);
|
|
360
|
+
const words = [];
|
|
361
|
+
for (const chunk of onSeparators) {
|
|
362
|
+
const cased = chunk.replace(/([\p{Ll}\p{Nd}])(\p{Lu})/gu, "$1\0$2").replace(/(\p{Lu})(\p{Lu}\p{Ll})/gu, "$1\0$2");
|
|
363
|
+
for (const word of cased.split("\0")) {
|
|
364
|
+
if (word) words.push(word);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return words;
|
|
368
|
+
}
|
|
369
|
+
function normalizeFieldComponent(component) {
|
|
370
|
+
const words = splitWords(component);
|
|
371
|
+
if (words.length === 0) return "";
|
|
372
|
+
return words.map((word, index) => {
|
|
373
|
+
const lower = word.toLowerCase();
|
|
374
|
+
return index === 0 ? lower : lower.charAt(0).toUpperCase() + lower.slice(1);
|
|
375
|
+
}).join("");
|
|
376
|
+
}
|
|
377
|
+
function normalizeFieldPath(path) {
|
|
378
|
+
return path.split(".").map(normalizeFieldComponent).filter((component) => component.length > 0).join(".");
|
|
379
|
+
}
|
|
380
|
+
function valueKindOf(value) {
|
|
381
|
+
if (value === null) return "null";
|
|
382
|
+
if (value === void 0) return "undefined";
|
|
383
|
+
if (Array.isArray(value)) return "array";
|
|
384
|
+
switch (typeof value) {
|
|
385
|
+
case "number":
|
|
386
|
+
return "number";
|
|
387
|
+
case "string":
|
|
388
|
+
return "string";
|
|
389
|
+
case "boolean":
|
|
390
|
+
return "boolean";
|
|
391
|
+
case "object":
|
|
392
|
+
return "object";
|
|
393
|
+
default:
|
|
394
|
+
return "undefined";
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function flattenFieldLeaves(input, prefix = "") {
|
|
398
|
+
const leaves = [];
|
|
399
|
+
for (const [rawKey, value] of Object.entries(input)) {
|
|
400
|
+
const path = prefix ? `${prefix}.${normalizeFieldPath(rawKey)}` : normalizeFieldPath(rawKey);
|
|
401
|
+
if (!path) continue;
|
|
402
|
+
const kind = valueKindOf(value);
|
|
403
|
+
if (kind === "object") {
|
|
404
|
+
leaves.push(...flattenFieldLeaves(value, path));
|
|
405
|
+
} else if (kind !== "undefined") {
|
|
406
|
+
leaves.push({ path, kind, value, originalPath: prefix ? `${prefix}.${rawKey}` : rawKey });
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return leaves;
|
|
410
|
+
}
|
|
411
|
+
function fieldRefKey(ref) {
|
|
412
|
+
return JSON.stringify([ref.path, ref.kind, ref.dimension ?? null]);
|
|
413
|
+
}
|
|
414
|
+
function fieldRefFromKey(key) {
|
|
415
|
+
const [path, kind, dimension] = JSON.parse(key);
|
|
416
|
+
return { path, kind, ...dimension ? { dimension } : {} };
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// src/units/catalog.ts
|
|
420
|
+
var UnitConversionError = class extends Error {
|
|
421
|
+
code;
|
|
422
|
+
constructor(code, message) {
|
|
423
|
+
super(message);
|
|
424
|
+
this.name = "UnitConversionError";
|
|
425
|
+
this.code = code;
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
var UNIT_CATALOG = [
|
|
429
|
+
// Distance — base m
|
|
430
|
+
{ canonical: "m", dimension: "distance", factor: 1, aliases: ["meter", "meters", "metre", "metres"] },
|
|
431
|
+
{ canonical: "km", dimension: "distance", factor: 1e3, aliases: ["kilometer", "kilometers", "kilometre", "kilometres"] },
|
|
432
|
+
{ canonical: "cm", dimension: "distance", factor: 0.01, aliases: ["centimeter", "centimeters"] },
|
|
433
|
+
{ canonical: "mm", dimension: "distance", factor: 1e-3, aliases: ["millimeter", "millimeters"] },
|
|
434
|
+
{ canonical: "ft", dimension: "distance", factor: 0.3048, aliases: ["foot", "feet"] },
|
|
435
|
+
{ canonical: "in", dimension: "distance", factor: 0.0254, aliases: ["inch", "inches"] },
|
|
436
|
+
{ canonical: "yd", dimension: "distance", factor: 0.9144, aliases: ["yard", "yards"] },
|
|
437
|
+
{ canonical: "mi", dimension: "distance", factor: 1609.344, aliases: ["mile", "miles"] },
|
|
438
|
+
// Mass — base kg
|
|
439
|
+
{ canonical: "kg", dimension: "mass", factor: 1, aliases: ["kilogram", "kilograms", "kilo", "kilos"] },
|
|
440
|
+
{ canonical: "g", dimension: "mass", factor: 1e-3, aliases: ["gram", "grams"] },
|
|
441
|
+
{ canonical: "lb", dimension: "mass", factor: 0.45359237, aliases: ["lbs", "pound", "pounds"] },
|
|
442
|
+
// Duration — base s
|
|
443
|
+
{ canonical: "ms", dimension: "duration", factor: 1e-3, aliases: ["millisecond", "milliseconds"] },
|
|
444
|
+
{ canonical: "s", dimension: "duration", factor: 1, aliases: ["sec", "secs", "second", "seconds"] },
|
|
445
|
+
{ canonical: "min", dimension: "duration", factor: 60, aliases: ["mins", "minute", "minutes"] },
|
|
446
|
+
{ canonical: "h", dimension: "duration", factor: 3600, aliases: ["hr", "hrs", "hour", "hours"] },
|
|
447
|
+
// Count — base count. Test-result scales ("pull-up", "thruster",
|
|
448
|
+
// "problem") are count-dimension scales: one of their units is one rep.
|
|
449
|
+
{ canonical: "count", dimension: "count", factor: 1 },
|
|
450
|
+
{ canonical: "rep", dimension: "count", factor: 1, aliases: ["reps"] },
|
|
451
|
+
{ canonical: "pull-up", dimension: "count", factor: 1 },
|
|
452
|
+
{ canonical: "thruster", dimension: "count", factor: 1 },
|
|
453
|
+
{ canonical: "problem", dimension: "count", factor: 1 },
|
|
454
|
+
// Count-rate — base count/s; bpm (beats per minute) is its registered scale
|
|
455
|
+
{ canonical: "count/s", dimension: "count-rate", factor: 1 },
|
|
456
|
+
{ canonical: "bpm", dimension: "count-rate", factor: 1 / 60 },
|
|
457
|
+
// Energy — base cal
|
|
458
|
+
{ canonical: "cal", dimension: "energy", factor: 1, aliases: ["calorie", "calories"] },
|
|
459
|
+
{ canonical: "kcal", dimension: "energy", factor: 1e3, aliases: ["kilocalorie", "kilocalories"] },
|
|
460
|
+
// Speed — base m/s
|
|
461
|
+
{ canonical: "m/s", dimension: "speed", factor: 1 },
|
|
462
|
+
{ canonical: "km/h", dimension: "speed", factor: 1e3 / 3600, aliases: ["kmh", "kph"] },
|
|
463
|
+
{ canonical: "mph", dimension: "speed", factor: 1609.344 / 3600 },
|
|
464
|
+
// Pace — base min/km
|
|
465
|
+
{ canonical: "min/km", dimension: "pace", factor: 1 },
|
|
466
|
+
{ canonical: "min/mi", dimension: "pace", factor: 1e3 / 1609.344 },
|
|
467
|
+
{ canonical: "s/m", dimension: "pace", factor: 1 / 60 },
|
|
468
|
+
// Ratio — unitless base (factor 1); percent via 100% = 1.
|
|
469
|
+
// Dimensionless named scales (arbitrary units, points) share the ratio
|
|
470
|
+
// dimension but are convertible only to the base — never to each other.
|
|
471
|
+
{ canonical: "ratio", dimension: "ratio", factor: 1, aliases: ["x"] },
|
|
472
|
+
{ canonical: "%", dimension: "ratio", factor: 0.01, aliases: ["pct", "percent"] },
|
|
473
|
+
{ canonical: "au", dimension: "ratio", factor: 1, aliases: ["AU"] },
|
|
474
|
+
{ canonical: "pts", dimension: "ratio", factor: 1, aliases: ["point", "points"] },
|
|
475
|
+
{ canonical: "rating", dimension: "ratio", factor: 1, aliases: ["ratings"] }
|
|
476
|
+
];
|
|
477
|
+
var bySpelling = (() => {
|
|
478
|
+
const map = /* @__PURE__ */ new Map();
|
|
479
|
+
for (const def of UNIT_CATALOG) {
|
|
480
|
+
map.set(def.canonical.toLowerCase(), def);
|
|
481
|
+
for (const alias of def.aliases ?? []) {
|
|
482
|
+
if (!map.has(alias.toLowerCase())) map.set(alias.toLowerCase(), def);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return map;
|
|
486
|
+
})();
|
|
487
|
+
function lookupUnit(spelling) {
|
|
488
|
+
return bySpelling.get(spelling.trim().toLowerCase());
|
|
489
|
+
}
|
|
490
|
+
function dimensionKeyOf(spelling) {
|
|
491
|
+
return lookupUnit(spelling)?.dimension;
|
|
492
|
+
}
|
|
493
|
+
var SYSTEM_DEFAULT_OUTPUT_UNIT = Object.freeze({
|
|
494
|
+
mass: "kg",
|
|
495
|
+
distance: "m",
|
|
496
|
+
duration: "s",
|
|
497
|
+
count: "count",
|
|
498
|
+
"count-rate": "count/s",
|
|
499
|
+
energy: "cal",
|
|
500
|
+
speed: "m/s",
|
|
501
|
+
pace: "min/km",
|
|
502
|
+
ratio: void 0
|
|
503
|
+
});
|
|
504
|
+
function systemDefaultUnit(dimension) {
|
|
505
|
+
return SYSTEM_DEFAULT_OUTPUT_UNIT[dimension];
|
|
506
|
+
}
|
|
507
|
+
function convertViaCatalog(value, from, to) {
|
|
508
|
+
const fromDef = lookupUnit(from);
|
|
509
|
+
if (!fromDef) throw new UnitConversionError("unknown-unit", `Unknown unit "${from}"`);
|
|
510
|
+
const toDef = lookupUnit(to);
|
|
511
|
+
if (!toDef) throw new UnitConversionError("unknown-unit", `Unknown unit "${to}"`);
|
|
512
|
+
if (fromDef.dimension !== toDef.dimension) {
|
|
513
|
+
throw new UnitConversionError(
|
|
514
|
+
"dimension-mismatch",
|
|
515
|
+
`Cannot convert ${from} (${fromDef.dimension}) to ${to} (${toDef.dimension})`
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
if (fromDef.dimension === "ratio" && fromDef.canonical !== toDef.canonical) {
|
|
519
|
+
if (fromDef.canonical !== "ratio" && toDef.canonical !== "ratio") {
|
|
520
|
+
throw new UnitConversionError(
|
|
521
|
+
"scale-mismatch",
|
|
522
|
+
`Named scales ${from} and ${to} are not interchangeable`
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
if (!Number.isFinite(value)) {
|
|
527
|
+
throw new UnitConversionError("non-finite", `Non-finite value cannot be converted`);
|
|
528
|
+
}
|
|
529
|
+
return value * fromDef.factor / toDef.factor;
|
|
530
|
+
}
|
|
531
|
+
|
|
363
532
|
// src/models/CodeMetadata.ts
|
|
364
533
|
var CodeMetadata = class {
|
|
365
534
|
constructor(line, startOffset, endOffset, length, columnStart = 0, columnEnd = 0, raw = "") {
|
|
@@ -686,7 +855,7 @@ var ParsedCodeStatement = class extends CodeStatement {
|
|
|
686
855
|
};
|
|
687
856
|
|
|
688
857
|
// src/models/OutputStatement.ts
|
|
689
|
-
var OutputStatement = class _OutputStatement {
|
|
858
|
+
var OutputStatement = class _OutputStatement extends CodeStatement {
|
|
690
859
|
static nextId = 1e6;
|
|
691
860
|
id;
|
|
692
861
|
outputType;
|
|
@@ -704,6 +873,7 @@ var OutputStatement = class _OutputStatement {
|
|
|
704
873
|
statement;
|
|
705
874
|
timestamp;
|
|
706
875
|
constructor(optionsOrStatement, metricsArg, timestamp) {
|
|
876
|
+
super();
|
|
707
877
|
if (optionsOrStatement && "outputType" in optionsOrStatement && "timeSpan" in optionsOrStatement) {
|
|
708
878
|
const options = optionsOrStatement;
|
|
709
879
|
this.id = _OutputStatement.nextId++;
|
|
@@ -711,6 +881,9 @@ var OutputStatement = class _OutputStatement {
|
|
|
711
881
|
this.timeSpan = options.timeSpan;
|
|
712
882
|
this.sourceBlockKey = options.sourceBlockKey ?? "";
|
|
713
883
|
this.sourceStatementId = options.sourceStatementId;
|
|
884
|
+
this.line = options.line;
|
|
885
|
+
this.text = options.text;
|
|
886
|
+
this.dialect = options.dialect;
|
|
714
887
|
this.stackLevel = options.stackLevel ?? 0;
|
|
715
888
|
this.metrics = MetricContainer.from(options.metrics, this.id);
|
|
716
889
|
this.metricMeta = options.metricMeta ?? /* @__PURE__ */ new Map();
|
|
@@ -733,27 +906,13 @@ var OutputStatement = class _OutputStatement {
|
|
|
733
906
|
this.children = [];
|
|
734
907
|
this.isLeaf = true;
|
|
735
908
|
this.meta = stmt?.meta ?? new CodeMetadata(0, 0, 0, 0);
|
|
909
|
+
this.line = stmt?.line;
|
|
910
|
+
this.text = stmt?.text;
|
|
911
|
+
this.dialect = stmt?.dialect;
|
|
736
912
|
this.timestamp = timestamp ?? Date.now();
|
|
737
913
|
}
|
|
738
914
|
}
|
|
739
|
-
//
|
|
740
|
-
// IMetricSource implementation
|
|
741
|
-
// ═══════════════════════════════════════════════════════════════
|
|
742
|
-
getDisplayMetrics(filter) {
|
|
743
|
-
return this.metrics.getDisplayMetrics(filter);
|
|
744
|
-
}
|
|
745
|
-
getMetric(type) {
|
|
746
|
-
return this.metrics.getMetric(type);
|
|
747
|
-
}
|
|
748
|
-
getAllMetricsByType(type) {
|
|
749
|
-
return this.metrics.getAllMetricsByType(type);
|
|
750
|
-
}
|
|
751
|
-
hasMetric(type) {
|
|
752
|
-
return this.metrics.hasMetric(type);
|
|
753
|
-
}
|
|
754
|
-
get rawMetrics() {
|
|
755
|
-
return this.metrics.rawMetrics;
|
|
756
|
-
}
|
|
915
|
+
// IMetricSource implementation is inherited from CodeStatement
|
|
757
916
|
/**
|
|
758
917
|
* Reset the ID counter (useful for testing)
|
|
759
918
|
*/
|
|
@@ -762,37 +921,6 @@ var OutputStatement = class _OutputStatement {
|
|
|
762
921
|
}
|
|
763
922
|
};
|
|
764
923
|
|
|
765
|
-
// src/models/Duration.ts
|
|
766
|
-
var Duration = class {
|
|
767
|
-
constructor(original) {
|
|
768
|
-
this.original = original;
|
|
769
|
-
let remaining = original ?? 0;
|
|
770
|
-
this.days = Math.floor(remaining / 864e5);
|
|
771
|
-
remaining %= 864e5;
|
|
772
|
-
this.hours = Math.floor(remaining / 36e5);
|
|
773
|
-
remaining %= 36e5;
|
|
774
|
-
this.minutes = Math.floor(remaining / 6e4);
|
|
775
|
-
remaining %= 6e4;
|
|
776
|
-
this.seconds = Math.floor(remaining / 1e3);
|
|
777
|
-
this.milliseconds = Math.round(remaining - this.seconds * 1e3);
|
|
778
|
-
}
|
|
779
|
-
original;
|
|
780
|
-
days;
|
|
781
|
-
hours;
|
|
782
|
-
minutes;
|
|
783
|
-
seconds;
|
|
784
|
-
milliseconds;
|
|
785
|
-
};
|
|
786
|
-
var SpanDuration = class extends Duration {
|
|
787
|
-
constructor(spans) {
|
|
788
|
-
const total = spans.reduce((sum, span) => {
|
|
789
|
-
const end = span.ended ?? Date.now();
|
|
790
|
-
return sum + Math.max(0, end - span.started);
|
|
791
|
-
}, 0);
|
|
792
|
-
super(total);
|
|
793
|
-
}
|
|
794
|
-
};
|
|
795
|
-
|
|
796
924
|
// src/models/BlockKey.ts
|
|
797
925
|
var BlockKey = class {
|
|
798
926
|
value;
|
|
@@ -810,6 +938,17 @@ var BlockKey = class {
|
|
|
810
938
|
}
|
|
811
939
|
};
|
|
812
940
|
|
|
941
|
+
// src/models/blockContentId.ts
|
|
942
|
+
function blockContentId(content) {
|
|
943
|
+
const normalized = content.trim();
|
|
944
|
+
let hash = 2166136261;
|
|
945
|
+
for (let i = 0; i < normalized.length; i++) {
|
|
946
|
+
hash ^= normalized.charCodeAt(i);
|
|
947
|
+
hash = Math.imul(hash, 16777619);
|
|
948
|
+
}
|
|
949
|
+
return `bc-${(hash >>> 0).toString(16).padStart(8, "0")}`;
|
|
950
|
+
}
|
|
951
|
+
|
|
813
952
|
// src/types/storage.ts
|
|
814
953
|
var KNOWN_OUTPUT_TYPES = [
|
|
815
954
|
"segment",
|
|
@@ -839,21 +978,399 @@ var toNotebookTag = (notebookId) => `${NOTEBOOK_TAG_PREFIX}${notebookId}`;
|
|
|
839
978
|
var fromNotebookTag = (tag) => tag.startsWith(NOTEBOOK_TAG_PREFIX) ? tag.slice(NOTEBOOK_TAG_PREFIX.length) : null;
|
|
840
979
|
var isNotebookTag = (tag) => tag.startsWith(NOTEBOOK_TAG_PREFIX);
|
|
841
980
|
|
|
981
|
+
// src/sections/blockDetection.ts
|
|
982
|
+
function matchDialectFence(trimmedLine) {
|
|
983
|
+
if (!trimmedLine.startsWith("```")) return null;
|
|
984
|
+
const tag = trimmedLine.slice(3).split(/[\s\t]/)[0].toLowerCase();
|
|
985
|
+
const [base, sport] = tag.split(":", 2);
|
|
986
|
+
if (VALID_FENCE_DIALECTS.includes(base)) {
|
|
987
|
+
return { dialect: base, sport: sport || void 0 };
|
|
988
|
+
}
|
|
989
|
+
return null;
|
|
990
|
+
}
|
|
991
|
+
function detectScriptBlocks(content) {
|
|
992
|
+
const lines = content.split("\n");
|
|
993
|
+
const blocks = [];
|
|
994
|
+
let inBlock = false;
|
|
995
|
+
let currentBlock = {};
|
|
996
|
+
let blockContent = [];
|
|
997
|
+
lines.forEach((line, index) => {
|
|
998
|
+
const trimmedLine = line.trim();
|
|
999
|
+
if (!inBlock) {
|
|
1000
|
+
const fence = matchDialectFence(trimmedLine);
|
|
1001
|
+
if (fence) {
|
|
1002
|
+
inBlock = true;
|
|
1003
|
+
const now = Date.now();
|
|
1004
|
+
currentBlock = {
|
|
1005
|
+
id: `${fence.dialect}-block-${now}-${Math.random().toString(36).slice(2, 9)}`,
|
|
1006
|
+
dialect: fence.dialect,
|
|
1007
|
+
sport: fence.sport,
|
|
1008
|
+
startLine: index,
|
|
1009
|
+
state: "idle",
|
|
1010
|
+
version: 1,
|
|
1011
|
+
createdAt: now
|
|
1012
|
+
};
|
|
1013
|
+
blockContent = [];
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
if (inBlock && trimmedLine.startsWith("```")) {
|
|
1018
|
+
inBlock = false;
|
|
1019
|
+
currentBlock.endLine = index;
|
|
1020
|
+
currentBlock.content = blockContent.join("\n");
|
|
1021
|
+
blocks.push(currentBlock);
|
|
1022
|
+
currentBlock = {};
|
|
1023
|
+
blockContent = [];
|
|
1024
|
+
} else if (inBlock) {
|
|
1025
|
+
blockContent.push(line);
|
|
1026
|
+
}
|
|
1027
|
+
});
|
|
1028
|
+
if (inBlock && currentBlock.startLine !== void 0) {
|
|
1029
|
+
currentBlock.endLine = lines.length - 1;
|
|
1030
|
+
currentBlock.content = blockContent.join("\n");
|
|
1031
|
+
blocks.push(currentBlock);
|
|
1032
|
+
}
|
|
1033
|
+
return blocks;
|
|
1034
|
+
}
|
|
1035
|
+
function findBlockAtLine(blocks, lineNumber) {
|
|
1036
|
+
return blocks.find(
|
|
1037
|
+
(block) => lineNumber >= block.startLine && lineNumber <= block.endLine
|
|
1038
|
+
) ?? null;
|
|
1039
|
+
}
|
|
1040
|
+
function extractBlockContent(content, startLine, endLine) {
|
|
1041
|
+
const lines = content.split("\n");
|
|
1042
|
+
return lines.slice(startLine + 1, endLine).join("\n");
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// src/sections/sectionParser.ts
|
|
1046
|
+
var METADATA_REGEX = /<!--\s*section-metadata\s+id:(\S+)\s+version:(\d+)\s+created:(\d+)\s*-->/i;
|
|
1047
|
+
function extractMetadata(text) {
|
|
1048
|
+
const match = text.match(METADATA_REGEX);
|
|
1049
|
+
if (!match) return { metadata: null, cleanText: text };
|
|
1050
|
+
return {
|
|
1051
|
+
metadata: {
|
|
1052
|
+
id: match[1],
|
|
1053
|
+
version: parseInt(match[2], 10),
|
|
1054
|
+
createdAt: parseInt(match[3], 10)
|
|
1055
|
+
},
|
|
1056
|
+
cleanText: text.replace(METADATA_REGEX, "").trim()
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
1059
|
+
function generateSectionId(type, startLine, content) {
|
|
1060
|
+
let hash = 0;
|
|
1061
|
+
for (let i = 0; i < content.length && i < 64; i++) {
|
|
1062
|
+
hash = (hash << 5) - hash + content.charCodeAt(i) | 0;
|
|
1063
|
+
}
|
|
1064
|
+
const hashHex = (hash >>> 0).toString(16).padStart(8, "0");
|
|
1065
|
+
return `${type}-${startLine}-${hashHex}`;
|
|
1066
|
+
}
|
|
1067
|
+
function detectUrlSubtype(url) {
|
|
1068
|
+
if (!url) return null;
|
|
1069
|
+
const withoutScheme = url.trim().replace(/^[a-z][a-z0-9+.-]*:\/\//i, "");
|
|
1070
|
+
const host = withoutScheme.split(/[/?#:]/, 1)[0].toLowerCase();
|
|
1071
|
+
if (host === "youtube.com" || host.endsWith(".youtube.com") || host === "youtu.be") return "youtube";
|
|
1072
|
+
if (host === "strava.com" || host.endsWith(".strava.com")) return "strava";
|
|
1073
|
+
if (host === "amazon.com" || host.endsWith(".amazon.com") || host === "amzn.to") return "amazon";
|
|
1074
|
+
return null;
|
|
1075
|
+
}
|
|
1076
|
+
function resolveFrontMatterSubtype(props) {
|
|
1077
|
+
const typeValue = (props["type"] || "").toLowerCase();
|
|
1078
|
+
if (typeValue === "youtube") return "youtube";
|
|
1079
|
+
if (typeValue === "strava") return "strava";
|
|
1080
|
+
if (typeValue === "amazon") return "amazon";
|
|
1081
|
+
if (typeValue === "file") return "file";
|
|
1082
|
+
if (typeValue === "effort") return "effort";
|
|
1083
|
+
const url = props["url"] || props["link"] || "";
|
|
1084
|
+
if (url) {
|
|
1085
|
+
const detected = detectUrlSubtype(url);
|
|
1086
|
+
if (detected) return detected;
|
|
1087
|
+
}
|
|
1088
|
+
if (props["baseAttributes"] !== void 0 || props["discipline"] !== void 0 || props["effortType"] !== void 0 || props["targetRPE"] !== void 0 || props["equipment"] !== void 0 || props["aliases"] !== void 0 || props["derivation"] !== void 0) {
|
|
1089
|
+
return "effort";
|
|
1090
|
+
}
|
|
1091
|
+
return "default";
|
|
1092
|
+
}
|
|
1093
|
+
function parseFrontMatterProperties(innerLines) {
|
|
1094
|
+
const props = {};
|
|
1095
|
+
for (const line of innerLines) {
|
|
1096
|
+
const match = line.match(/^([^:]+):\s*(.*)$/);
|
|
1097
|
+
if (match) {
|
|
1098
|
+
props[match[1].trim()] = match[2].trim();
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
return props;
|
|
1102
|
+
}
|
|
1103
|
+
function matchMarkdownEmbed(trimmed) {
|
|
1104
|
+
const match = trimmed.match(/^(!)?\[([^\]]*)\]\(([^)]+)\)$/);
|
|
1105
|
+
if (!match) return null;
|
|
1106
|
+
const isImage = !!match[1];
|
|
1107
|
+
const label = match[2];
|
|
1108
|
+
const url = match[3];
|
|
1109
|
+
let type = isImage ? "image" : "link";
|
|
1110
|
+
if (/youtube\.com|youtu\.be/i.test(url)) {
|
|
1111
|
+
type = "youtube";
|
|
1112
|
+
}
|
|
1113
|
+
return { type, label, url, isImage };
|
|
1114
|
+
}
|
|
1115
|
+
function detectFrontMatterBlocks(lines, scriptBlocks) {
|
|
1116
|
+
const ranges = [];
|
|
1117
|
+
let i = 0;
|
|
1118
|
+
while (i < lines.length) {
|
|
1119
|
+
const inScript = scriptBlocks.some((b) => i >= b.startLine && i <= b.endLine);
|
|
1120
|
+
if (inScript) {
|
|
1121
|
+
i++;
|
|
1122
|
+
continue;
|
|
1123
|
+
}
|
|
1124
|
+
if (lines[i].trim() === "---") {
|
|
1125
|
+
const openLine = i;
|
|
1126
|
+
let j = i + 1;
|
|
1127
|
+
while (j < lines.length) {
|
|
1128
|
+
const inScriptInner = scriptBlocks.some((b) => j >= b.startLine && j <= b.endLine);
|
|
1129
|
+
if (inScriptInner) {
|
|
1130
|
+
j++;
|
|
1131
|
+
continue;
|
|
1132
|
+
}
|
|
1133
|
+
if (lines[j].trim() === "---") {
|
|
1134
|
+
ranges.push({ startLine: openLine, endLine: j });
|
|
1135
|
+
i = j + 1;
|
|
1136
|
+
break;
|
|
1137
|
+
}
|
|
1138
|
+
j++;
|
|
1139
|
+
}
|
|
1140
|
+
if (j >= lines.length) {
|
|
1141
|
+
i++;
|
|
1142
|
+
}
|
|
1143
|
+
} else {
|
|
1144
|
+
i++;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
return ranges;
|
|
1148
|
+
}
|
|
1149
|
+
function parseDocumentSections(content, scriptBlocks) {
|
|
1150
|
+
if (!content) return [];
|
|
1151
|
+
const blocks = scriptBlocks ?? detectScriptBlocks(content);
|
|
1152
|
+
const lines = content.split("\n");
|
|
1153
|
+
const sections = [];
|
|
1154
|
+
const fmRanges = detectFrontMatterBlocks(lines, blocks);
|
|
1155
|
+
const now = Date.now();
|
|
1156
|
+
let currentLine = 0;
|
|
1157
|
+
let isFirstTextBlock = true;
|
|
1158
|
+
function flushMarkdownLines(mdLines, startLine) {
|
|
1159
|
+
if (mdLines.length === 0) return;
|
|
1160
|
+
let currentGroup = [];
|
|
1161
|
+
let groupStartLine = startLine;
|
|
1162
|
+
const flushGroup = () => {
|
|
1163
|
+
if (currentGroup.length > 0) {
|
|
1164
|
+
const raw = currentGroup.join("\n");
|
|
1165
|
+
const { metadata, cleanText } = extractMetadata(raw);
|
|
1166
|
+
const trimmed = cleanText.trim();
|
|
1167
|
+
const embed = currentGroup.length === 1 ? matchMarkdownEmbed(trimmed) : null;
|
|
1168
|
+
if (embed) {
|
|
1169
|
+
sections.push({
|
|
1170
|
+
id: metadata?.id || generateSectionId("embed", groupStartLine, trimmed),
|
|
1171
|
+
type: "embed",
|
|
1172
|
+
rawContent: cleanText,
|
|
1173
|
+
displayContent: cleanText,
|
|
1174
|
+
startLine: groupStartLine,
|
|
1175
|
+
endLine: groupStartLine,
|
|
1176
|
+
lineCount: 1,
|
|
1177
|
+
embed,
|
|
1178
|
+
version: metadata?.version || 1,
|
|
1179
|
+
createdAt: metadata?.createdAt || now
|
|
1180
|
+
});
|
|
1181
|
+
} else if (isFirstTextBlock) {
|
|
1182
|
+
isFirstTextBlock = false;
|
|
1183
|
+
sections.push({
|
|
1184
|
+
id: metadata?.id || generateSectionId("title", groupStartLine, cleanText),
|
|
1185
|
+
type: "title",
|
|
1186
|
+
rawContent: cleanText,
|
|
1187
|
+
displayContent: cleanText,
|
|
1188
|
+
startLine: groupStartLine,
|
|
1189
|
+
endLine: groupStartLine + currentGroup.length - 1,
|
|
1190
|
+
lineCount: currentGroup.length,
|
|
1191
|
+
version: metadata?.version || 1,
|
|
1192
|
+
createdAt: metadata?.createdAt || now
|
|
1193
|
+
});
|
|
1194
|
+
} else {
|
|
1195
|
+
sections.push({
|
|
1196
|
+
id: metadata?.id || generateSectionId("markdown", groupStartLine, cleanText),
|
|
1197
|
+
type: "markdown",
|
|
1198
|
+
rawContent: cleanText,
|
|
1199
|
+
displayContent: cleanText,
|
|
1200
|
+
startLine: groupStartLine,
|
|
1201
|
+
endLine: groupStartLine + currentGroup.length - 1,
|
|
1202
|
+
lineCount: currentGroup.length,
|
|
1203
|
+
version: metadata?.version || 1,
|
|
1204
|
+
createdAt: metadata?.createdAt || now
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
currentGroup = [];
|
|
1209
|
+
};
|
|
1210
|
+
for (let i = 0; i < mdLines.length; i++) {
|
|
1211
|
+
const line = mdLines[i];
|
|
1212
|
+
if (line.trim().length === 0) {
|
|
1213
|
+
flushGroup();
|
|
1214
|
+
sections.push({
|
|
1215
|
+
id: generateSectionId("markdown", startLine + i, ""),
|
|
1216
|
+
type: "markdown",
|
|
1217
|
+
rawContent: "",
|
|
1218
|
+
displayContent: "",
|
|
1219
|
+
startLine: startLine + i,
|
|
1220
|
+
endLine: startLine + i,
|
|
1221
|
+
lineCount: 1,
|
|
1222
|
+
version: 1,
|
|
1223
|
+
createdAt: now
|
|
1224
|
+
});
|
|
1225
|
+
groupStartLine = startLine + i + 1;
|
|
1226
|
+
} else {
|
|
1227
|
+
currentGroup.push(line);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
flushGroup();
|
|
1231
|
+
}
|
|
1232
|
+
let mdBuffer = [];
|
|
1233
|
+
let mdBufferStart = 0;
|
|
1234
|
+
while (currentLine < lines.length) {
|
|
1235
|
+
const scriptBlock = blocks.find((b) => b.startLine === currentLine);
|
|
1236
|
+
if (scriptBlock) {
|
|
1237
|
+
flushMarkdownLines(mdBuffer, mdBufferStart);
|
|
1238
|
+
mdBuffer = [];
|
|
1239
|
+
const dialect = scriptBlock.dialect ?? "time";
|
|
1240
|
+
const { metadata, cleanText } = extractMetadata(scriptBlock.content);
|
|
1241
|
+
const fenceTag = scriptBlock.sport ? `${dialect}:${scriptBlock.sport}` : dialect;
|
|
1242
|
+
const cleanRawContent = `\`\`\`${fenceTag}
|
|
1243
|
+
${cleanText}
|
|
1244
|
+
\`\`\``;
|
|
1245
|
+
const cleanLineCount = cleanRawContent.split("\n").length;
|
|
1246
|
+
const sectionId = metadata?.id || generateSectionId(dialect, scriptBlock.startLine, cleanText);
|
|
1247
|
+
const contentId = blockContentId(cleanText);
|
|
1248
|
+
sections.push({
|
|
1249
|
+
id: sectionId,
|
|
1250
|
+
contentId,
|
|
1251
|
+
type: dialect,
|
|
1252
|
+
sport: scriptBlock.sport,
|
|
1253
|
+
rawContent: cleanRawContent,
|
|
1254
|
+
displayContent: cleanText,
|
|
1255
|
+
startLine: scriptBlock.startLine,
|
|
1256
|
+
endLine: scriptBlock.startLine + cleanLineCount - 1,
|
|
1257
|
+
lineCount: cleanLineCount,
|
|
1258
|
+
scriptBlock: {
|
|
1259
|
+
...scriptBlock,
|
|
1260
|
+
id: sectionId,
|
|
1261
|
+
contentId,
|
|
1262
|
+
content: cleanText,
|
|
1263
|
+
dialect,
|
|
1264
|
+
version: metadata?.version || 1,
|
|
1265
|
+
createdAt: metadata?.createdAt || now
|
|
1266
|
+
},
|
|
1267
|
+
version: metadata?.version || 1,
|
|
1268
|
+
createdAt: metadata?.createdAt || now
|
|
1269
|
+
});
|
|
1270
|
+
currentLine = scriptBlock.endLine + 1;
|
|
1271
|
+
mdBufferStart = currentLine;
|
|
1272
|
+
continue;
|
|
1273
|
+
}
|
|
1274
|
+
const fmRange = fmRanges.find((r) => r.startLine === currentLine);
|
|
1275
|
+
if (fmRange) {
|
|
1276
|
+
flushMarkdownLines(mdBuffer, mdBufferStart);
|
|
1277
|
+
mdBuffer = [];
|
|
1278
|
+
const rawLines = lines.slice(fmRange.startLine, fmRange.endLine + 1);
|
|
1279
|
+
const raw = rawLines.join("\n");
|
|
1280
|
+
const innerLines = lines.slice(fmRange.startLine + 1, fmRange.endLine);
|
|
1281
|
+
const { metadata, cleanText } = extractMetadata(innerLines.join("\n"));
|
|
1282
|
+
const properties = parseFrontMatterProperties(cleanText.split("\n"));
|
|
1283
|
+
const subtype = resolveFrontMatterSubtype(properties);
|
|
1284
|
+
const lineCount = fmRange.endLine - fmRange.startLine + 1;
|
|
1285
|
+
sections.push({
|
|
1286
|
+
id: metadata?.id || generateSectionId("frontmatter", fmRange.startLine, raw),
|
|
1287
|
+
type: "frontmatter",
|
|
1288
|
+
rawContent: raw,
|
|
1289
|
+
displayContent: cleanText,
|
|
1290
|
+
startLine: fmRange.startLine,
|
|
1291
|
+
endLine: fmRange.endLine,
|
|
1292
|
+
lineCount,
|
|
1293
|
+
properties,
|
|
1294
|
+
frontmatterType: subtype,
|
|
1295
|
+
version: metadata?.version || 1,
|
|
1296
|
+
createdAt: metadata?.createdAt || now
|
|
1297
|
+
});
|
|
1298
|
+
currentLine = fmRange.endLine + 1;
|
|
1299
|
+
mdBufferStart = currentLine;
|
|
1300
|
+
continue;
|
|
1301
|
+
}
|
|
1302
|
+
if (mdBuffer.length === 0) {
|
|
1303
|
+
mdBufferStart = currentLine;
|
|
1304
|
+
}
|
|
1305
|
+
mdBuffer.push(lines[currentLine]);
|
|
1306
|
+
currentLine++;
|
|
1307
|
+
}
|
|
1308
|
+
flushMarkdownLines(mdBuffer, mdBufferStart);
|
|
1309
|
+
return sections;
|
|
1310
|
+
}
|
|
1311
|
+
function buildRawContent(sections) {
|
|
1312
|
+
return sections.filter((s) => !s.deleted).map((s) => s.rawContent).join("\n");
|
|
1313
|
+
}
|
|
1314
|
+
function calculateTotalLines(sections) {
|
|
1315
|
+
const visible = sections.filter((s) => !s.deleted);
|
|
1316
|
+
if (visible.length === 0) return 0;
|
|
1317
|
+
const last = visible[visible.length - 1];
|
|
1318
|
+
return last.endLine + 1;
|
|
1319
|
+
}
|
|
1320
|
+
function matchSectionIds(oldSections, newSections) {
|
|
1321
|
+
return newSections.map((newSec) => {
|
|
1322
|
+
const { metadata } = extractMetadata(newSec.rawContent);
|
|
1323
|
+
if (metadata) {
|
|
1324
|
+
const updated = { ...newSec, id: metadata.id, version: metadata.version, createdAt: metadata.createdAt };
|
|
1325
|
+
if (updated.scriptBlock) {
|
|
1326
|
+
updated.scriptBlock = { ...updated.scriptBlock, id: metadata.id };
|
|
1327
|
+
}
|
|
1328
|
+
return updated;
|
|
1329
|
+
}
|
|
1330
|
+
const exactMatch = oldSections.find(
|
|
1331
|
+
(old) => old.type === newSec.type && old.startLine === newSec.startLine && old.displayContent === newSec.displayContent
|
|
1332
|
+
);
|
|
1333
|
+
if (exactMatch) {
|
|
1334
|
+
const updated = { ...newSec, id: exactMatch.id, version: exactMatch.version, createdAt: exactMatch.createdAt };
|
|
1335
|
+
if (updated.scriptBlock) {
|
|
1336
|
+
updated.scriptBlock = { ...updated.scriptBlock, id: exactMatch.id };
|
|
1337
|
+
}
|
|
1338
|
+
return updated;
|
|
1339
|
+
}
|
|
1340
|
+
const positionMatch = oldSections.find(
|
|
1341
|
+
(old) => old.type === newSec.type && old.startLine === newSec.startLine
|
|
1342
|
+
);
|
|
1343
|
+
if (positionMatch) {
|
|
1344
|
+
const newVersion = (positionMatch.version || 1) + 1;
|
|
1345
|
+
const updated = {
|
|
1346
|
+
...newSec,
|
|
1347
|
+
id: positionMatch.id,
|
|
1348
|
+
version: newVersion,
|
|
1349
|
+
createdAt: positionMatch.createdAt
|
|
1350
|
+
};
|
|
1351
|
+
if (updated.scriptBlock) {
|
|
1352
|
+
updated.scriptBlock = { ...updated.scriptBlock, id: positionMatch.id, version: newVersion };
|
|
1353
|
+
}
|
|
1354
|
+
return updated;
|
|
1355
|
+
}
|
|
1356
|
+
return newSec;
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
|
|
842
1360
|
// src/version.ts
|
|
843
|
-
var VERSION = "0.
|
|
844
|
-
var GIT_SHA = "
|
|
845
|
-
var BUILD_TIME = "2026-
|
|
1361
|
+
var VERSION = "0.35.2115";
|
|
1362
|
+
var GIT_SHA = "37944a8";
|
|
1363
|
+
var BUILD_TIME = "2026-10-11T23:54:36.367Z";
|
|
846
1364
|
var SEMVER = {
|
|
847
|
-
version: "0.
|
|
848
|
-
gitSha: "
|
|
849
|
-
buildTime: "2026-
|
|
1365
|
+
version: "0.35.2115",
|
|
1366
|
+
gitSha: "37944a8",
|
|
1367
|
+
buildTime: "2026-10-11T23:54:36.367Z"
|
|
850
1368
|
};
|
|
851
1369
|
|
|
852
1370
|
exports.BUILD_TIME = BUILD_TIME;
|
|
853
1371
|
exports.BlockKey = BlockKey;
|
|
854
1372
|
exports.CodeMetadata = CodeMetadata;
|
|
855
1373
|
exports.CodeStatement = CodeStatement;
|
|
856
|
-
exports.Duration = Duration;
|
|
857
1374
|
exports.GIT_SHA = GIT_SHA;
|
|
858
1375
|
exports.KNOWN_OUTPUT_TYPES = KNOWN_OUTPUT_TYPES;
|
|
859
1376
|
exports.LEGACY_ORIGIN_TO_OWNERSHIP_LAYER = LEGACY_ORIGIN_TO_OWNERSHIP_LAYER;
|
|
@@ -866,16 +1383,39 @@ exports.OutputStatement = OutputStatement;
|
|
|
866
1383
|
exports.OwnershipResolver = OwnershipResolver;
|
|
867
1384
|
exports.ParsedCodeStatement = ParsedCodeStatement;
|
|
868
1385
|
exports.SEMVER = SEMVER;
|
|
869
|
-
exports.
|
|
1386
|
+
exports.SYSTEM_DEFAULT_OUTPUT_UNIT = SYSTEM_DEFAULT_OUTPUT_UNIT;
|
|
1387
|
+
exports.UNIT_CATALOG = UNIT_CATALOG;
|
|
1388
|
+
exports.UnitConversionError = UnitConversionError;
|
|
870
1389
|
exports.VALID_FENCE_DIALECTS = VALID_FENCE_DIALECTS;
|
|
871
1390
|
exports.VERSION = VERSION;
|
|
1391
|
+
exports.blockContentId = blockContentId;
|
|
1392
|
+
exports.buildRawContent = buildRawContent;
|
|
1393
|
+
exports.calculateTotalLines = calculateTotalLines;
|
|
1394
|
+
exports.convertViaCatalog = convertViaCatalog;
|
|
872
1395
|
exports.createMetricOwnershipLedger = createMetricOwnershipLedger;
|
|
1396
|
+
exports.detectScriptBlocks = detectScriptBlocks;
|
|
1397
|
+
exports.dimensionKeyOf = dimensionKeyOf;
|
|
1398
|
+
exports.extractBlockContent = extractBlockContent;
|
|
1399
|
+
exports.fieldRefFromKey = fieldRefFromKey;
|
|
1400
|
+
exports.fieldRefKey = fieldRefKey;
|
|
1401
|
+
exports.findBlockAtLine = findBlockAtLine;
|
|
1402
|
+
exports.flattenFieldLeaves = flattenFieldLeaves;
|
|
873
1403
|
exports.fromNotebookTag = fromNotebookTag;
|
|
1404
|
+
exports.generateSectionId = generateSectionId;
|
|
874
1405
|
exports.getMetricOwnershipLayer = getMetricOwnershipLayer;
|
|
875
1406
|
exports.isNotebookTag = isNotebookTag;
|
|
876
1407
|
exports.isWorkoutSectionType = isWorkoutSectionType;
|
|
1408
|
+
exports.lookupUnit = lookupUnit;
|
|
1409
|
+
exports.matchDialectFence = matchDialectFence;
|
|
1410
|
+
exports.matchSectionIds = matchSectionIds;
|
|
1411
|
+
exports.normalizeFieldComponent = normalizeFieldComponent;
|
|
1412
|
+
exports.normalizeFieldPath = normalizeFieldPath;
|
|
877
1413
|
exports.ownershipRank = ownershipRank;
|
|
1414
|
+
exports.parseDocumentSections = parseDocumentSections;
|
|
1415
|
+
exports.resolveLayer = resolveLayer;
|
|
878
1416
|
exports.runAffordance = runAffordance;
|
|
1417
|
+
exports.systemDefaultUnit = systemDefaultUnit;
|
|
879
1418
|
exports.toNotebookTag = toNotebookTag;
|
|
1419
|
+
exports.valueKindOf = valueKindOf;
|
|
880
1420
|
//# sourceMappingURL=index.cjs.map
|
|
881
1421
|
//# sourceMappingURL=index.cjs.map
|