dotdog 0.3.2 → 0.3.3
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/cli.js +112 -11
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2636,6 +2636,15 @@ function parseBlocks(lines, start, end) {
|
|
|
2636
2636
|
continue;
|
|
2637
2637
|
}
|
|
2638
2638
|
}
|
|
2639
|
+
const predMatch = line.match(/^###\s+Prediction:\s*(.+)/);
|
|
2640
|
+
if (predMatch) {
|
|
2641
|
+
const result = parseStructuredBlock(lines, i, end, "prediction", predMatch[1]);
|
|
2642
|
+
if (result) {
|
|
2643
|
+
blocks.push(result.node);
|
|
2644
|
+
i = result.nextLine;
|
|
2645
|
+
continue;
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2639
2648
|
if (/^\|.+\|/.test(line) && i + 1 < end && /^\|[-| ]+\|/.test(lines[i + 1])) {
|
|
2640
2649
|
const table = parseTable(lines, i, end);
|
|
2641
2650
|
if (table) {
|
|
@@ -2715,6 +2724,12 @@ function parseStructuredBlock(lines, start, end, kind, headerRest) {
|
|
|
2715
2724
|
nextLine: i
|
|
2716
2725
|
};
|
|
2717
2726
|
}
|
|
2727
|
+
if (kind === "prediction") {
|
|
2728
|
+
return {
|
|
2729
|
+
node: buildPredictionNode(headerRest, description, yaml, start, i),
|
|
2730
|
+
nextLine: i
|
|
2731
|
+
};
|
|
2732
|
+
}
|
|
2718
2733
|
return null;
|
|
2719
2734
|
}
|
|
2720
2735
|
function buildEntityNode(name, description, yaml, lineStart, lineEnd) {
|
|
@@ -2735,7 +2750,11 @@ function buildEntityNode(name, description, yaml, lineStart, lineEnd) {
|
|
|
2735
2750
|
}
|
|
2736
2751
|
const states = Array.isArray(yaml.states) ? yaml.states : [];
|
|
2737
2752
|
const lifecycleStr = yaml.lifecycle || "";
|
|
2738
|
-
const
|
|
2753
|
+
const lifecycleParts = lifecycleStr ? lifecycleStr.split(/\s*→\s*/).map((s) => s.trim()) : [];
|
|
2754
|
+
const lifecycle = [];
|
|
2755
|
+
for (let si = 0;si < lifecycleParts.length - 1; si++) {
|
|
2756
|
+
lifecycle.push(`${lifecycleParts[si]} → ${lifecycleParts[si + 1]}`);
|
|
2757
|
+
}
|
|
2739
2758
|
return {
|
|
2740
2759
|
kind: "entity",
|
|
2741
2760
|
name,
|
|
@@ -2758,6 +2777,7 @@ function buildRelationshipNode(headerRest, description, yaml, lineStart, lineEnd
|
|
|
2758
2777
|
source,
|
|
2759
2778
|
target,
|
|
2760
2779
|
verb: yaml.verb || "connects",
|
|
2780
|
+
description: description || yaml.description || "",
|
|
2761
2781
|
cardinality: yaml.cardinality || "N:M",
|
|
2762
2782
|
required: yaml.required === true,
|
|
2763
2783
|
cascade: yaml.cascade || "none",
|
|
@@ -2782,6 +2802,22 @@ function buildEventNode(name, description, yaml, lineStart, lineEnd) {
|
|
|
2782
2802
|
lineEnd
|
|
2783
2803
|
};
|
|
2784
2804
|
}
|
|
2805
|
+
function buildPredictionNode(name, description, yaml, lineStart, lineEnd) {
|
|
2806
|
+
return {
|
|
2807
|
+
kind: "prediction",
|
|
2808
|
+
statement: name,
|
|
2809
|
+
description,
|
|
2810
|
+
trigger: yaml.trigger || "",
|
|
2811
|
+
timeframe: yaml.timeframe || "",
|
|
2812
|
+
confidence: typeof yaml.confidence === "number" ? yaml.confidence : 0,
|
|
2813
|
+
measurement: yaml.measurement || "",
|
|
2814
|
+
preconditions: Array.isArray(yaml.preconditions) ? yaml.preconditions : [],
|
|
2815
|
+
postconditions: Array.isArray(yaml.postconditions) ? yaml.postconditions : [],
|
|
2816
|
+
yaml,
|
|
2817
|
+
lineStart: lineStart + 1,
|
|
2818
|
+
lineEnd
|
|
2819
|
+
};
|
|
2820
|
+
}
|
|
2785
2821
|
function parseTable(lines, start, end) {
|
|
2786
2822
|
const headerLine = lines[start];
|
|
2787
2823
|
const headers = headerLine.split("|").map((h) => h.trim()).filter(Boolean);
|
|
@@ -2854,15 +2890,25 @@ function parseSimpleYAML(lines) {
|
|
|
2854
2890
|
} else if (value.startsWith("[") && value.endsWith("]")) {
|
|
2855
2891
|
currentObj[nestedKey] = value.slice(1, -1).split(",").map((s) => s.trim());
|
|
2856
2892
|
} else {
|
|
2857
|
-
|
|
2858
|
-
if (inlineObj) {
|
|
2859
|
-
currentObj[nestedKey] = inlineObj;
|
|
2860
|
-
} else {
|
|
2861
|
-
currentObj[nestedKey] = value;
|
|
2862
|
-
}
|
|
2893
|
+
currentObj[nestedKey] = value;
|
|
2863
2894
|
}
|
|
2864
2895
|
continue;
|
|
2865
2896
|
}
|
|
2897
|
+
if (nestedMatch && !inNested) {
|
|
2898
|
+
const key = nestedMatch[1];
|
|
2899
|
+
const value = (nestedMatch[2] || "").trim();
|
|
2900
|
+
if (value === "true")
|
|
2901
|
+
result[key] = true;
|
|
2902
|
+
else if (value === "false")
|
|
2903
|
+
result[key] = false;
|
|
2904
|
+
else if (/^-?\d+(\.\d+)?$/.test(value))
|
|
2905
|
+
result[key] = parseFloat(value);
|
|
2906
|
+
else if (value.startsWith("[") && value.endsWith("]"))
|
|
2907
|
+
result[key] = value.slice(1, -1).split(",").map((s) => s.trim());
|
|
2908
|
+
else
|
|
2909
|
+
result[key] = value;
|
|
2910
|
+
continue;
|
|
2911
|
+
}
|
|
2866
2912
|
const deepMatch = line.match(/^\s{4}(\w[\w_]*):\s*(.+)?$/);
|
|
2867
2913
|
if (deepMatch && inNested && nestedKey && typeof currentObj[nestedKey] === "object") {
|
|
2868
2914
|
const deepNested = currentObj[nestedKey];
|
|
@@ -3285,9 +3331,9 @@ program2.command("compile [dir]").option("-o, --output <file>").action((d = ".",
|
|
|
3285
3331
|
const ast = parse(sources[f]);
|
|
3286
3332
|
for (const section of ast.sections) {
|
|
3287
3333
|
for (const block of section.blocks) {
|
|
3288
|
-
if (block.kind === "entity" || block.kind === "event"
|
|
3334
|
+
if (block.kind === "entity" || block.kind === "event") {
|
|
3289
3335
|
const compactProps = {};
|
|
3290
|
-
for (const [key, val] of Object.entries(block.properties)) {
|
|
3336
|
+
for (const [key, val] of Object.entries(block.properties || {})) {
|
|
3291
3337
|
let enc = "";
|
|
3292
3338
|
const t = val.type || "string";
|
|
3293
3339
|
if (t === "string")
|
|
@@ -3307,8 +3353,8 @@ program2.command("compile [dir]").option("-o, --output <file>").action((d = ".",
|
|
|
3307
3353
|
compactProps[key] = enc;
|
|
3308
3354
|
}
|
|
3309
3355
|
nodes.push({
|
|
3310
|
-
i: block.name,
|
|
3311
|
-
t: block.type,
|
|
3356
|
+
i: block.name || "",
|
|
3357
|
+
t: block.type || "",
|
|
3312
3358
|
g: block.kind,
|
|
3313
3359
|
d: block.description || "",
|
|
3314
3360
|
p: compactProps,
|
|
@@ -3316,6 +3362,21 @@ program2.command("compile [dir]").option("-o, --output <file>").action((d = ".",
|
|
|
3316
3362
|
l: block.lifecycle || []
|
|
3317
3363
|
});
|
|
3318
3364
|
}
|
|
3365
|
+
if (block.kind === "prediction") {
|
|
3366
|
+
nodes.push({
|
|
3367
|
+
i: block.statement || block.name || "",
|
|
3368
|
+
t: "prediction",
|
|
3369
|
+
g: "prediction",
|
|
3370
|
+
d: block.description || "",
|
|
3371
|
+
p: {},
|
|
3372
|
+
s: [],
|
|
3373
|
+
l: [],
|
|
3374
|
+
cf: block.confidence || 0,
|
|
3375
|
+
tf: block.timeframe || "",
|
|
3376
|
+
tg: block.trigger || "",
|
|
3377
|
+
ms: block.measurement || ""
|
|
3378
|
+
});
|
|
3379
|
+
}
|
|
3319
3380
|
if (block.kind === "relationship") {
|
|
3320
3381
|
edges.push({
|
|
3321
3382
|
s: block.source,
|
|
@@ -3347,6 +3408,46 @@ program2.command("compile [dir]").option("-o, --output <file>").action((d = ".",
|
|
|
3347
3408
|
if (!found)
|
|
3348
3409
|
console.log(source_default.yellow("No projects found."));
|
|
3349
3410
|
});
|
|
3411
|
+
program2.command("tokens [dir]").action((d = ".") => {
|
|
3412
|
+
const dir = resolvePath2(d);
|
|
3413
|
+
const dirs = [join2(dir, "projects"), join2(dir, "specs"), dir];
|
|
3414
|
+
let found = false;
|
|
3415
|
+
for (const dd of dirs) {
|
|
3416
|
+
if (!existsSync2(dd))
|
|
3417
|
+
continue;
|
|
3418
|
+
const projects = readdirSync2(dd, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
3419
|
+
for (const p of projects) {
|
|
3420
|
+
const pd = join2(dd, p);
|
|
3421
|
+
if (!existsSync2(join2(pd, "SPEC.dog")))
|
|
3422
|
+
continue;
|
|
3423
|
+
const dagFile = join2(pd, `${p}.dag`);
|
|
3424
|
+
if (!existsSync2(dagFile))
|
|
3425
|
+
continue;
|
|
3426
|
+
found = true;
|
|
3427
|
+
const dogFiles = readdirSync2(pd).filter((f) => f.endsWith(".dog"));
|
|
3428
|
+
let sourceBytes = 0, contentBytes = 0;
|
|
3429
|
+
for (const f of dogFiles) {
|
|
3430
|
+
const bytes = Buffer.byteLength(readFileSync2(join2(pd, f), "utf-8"), "utf-8");
|
|
3431
|
+
sourceBytes += bytes;
|
|
3432
|
+
if (bytes >= 100)
|
|
3433
|
+
contentBytes += bytes;
|
|
3434
|
+
}
|
|
3435
|
+
const dagBytes = Buffer.byteLength(readFileSync2(dagFile, "utf-8"), "utf-8");
|
|
3436
|
+
const savings = sourceBytes > 0 ? Math.round((1 - dagBytes / sourceBytes) * 1000) / 10 : 0;
|
|
3437
|
+
console.log(source_default.bold(`
|
|
3438
|
+
${p}`));
|
|
3439
|
+
console.log(source_default.gray(` ${dogFiles.length} .dog files: ${sourceBytes} bytes`));
|
|
3440
|
+
console.log(source_default.gray(` .dag file: ${dagBytes} bytes`));
|
|
3441
|
+
console.log(source_default.green(` ${savings}% smaller (${sourceBytes - dagBytes} bytes saved)`));
|
|
3442
|
+
if (contentBytes && contentBytes !== sourceBytes) {
|
|
3443
|
+
const cs = Math.round((1 - dagBytes / contentBytes) * 1000) / 10;
|
|
3444
|
+
console.log(source_default.gray(` content-only: ${contentBytes} bytes → ${cs}% savings`));
|
|
3445
|
+
}
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
if (!found)
|
|
3449
|
+
console.log(source_default.yellow("No .dag files found. Run compile first."));
|
|
3450
|
+
});
|
|
3350
3451
|
program2.command("visualize [dir]").option("-s, --save").action((d = ".", opts) => {
|
|
3351
3452
|
const dir = resolvePath2(d);
|
|
3352
3453
|
const dirs = [join2(dir, "projects"), join2(dir, "specs"), dir];
|