dirac-lang 0.1.14 → 0.1.16
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/config.test.yml +5 -0
- package/dist/{chunk-VOD5GGHB.js → chunk-CP4YCRBG.js} +233 -146
- package/dist/{chunk-SOHSXT3M.js → chunk-FEOBVBSI.js} +4 -2
- package/dist/chunk-HRHAMPOB.js +123 -0
- package/dist/cli.js +4 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -3
- package/dist/{interpreter-FT22JGOO.js → interpreter-GNO4J3HN.js} +2 -1
- package/dist/parser-T6W3WPLU.js +6 -0
- package/dist/{tag-validator-DYWFTEBE.js → tag-validator-CLYGULLQ.js} +10 -8
- package/dist/test-runner.js +6 -5
- package/examples/llm-command-more.di +6 -0
- package/package.json +1 -1
- package/src/runtime/interpreter.ts +10 -0
- package/src/tags/attr.ts +64 -0
- package/src/tags/available-subroutines.ts +19 -6
- package/src/tags/call.ts +4 -0
- package/src/tags/defvar.ts +53 -2
- package/src/tags/foreach.ts +170 -0
- package/src/tags/tag-check.ts +19 -6
- package/src/test-runner.ts +4 -4
- package/src/types/index.ts +1 -0
- package/src/utils/tag-validator.ts +12 -8
- package/tests/available-subroutines-foreach.test.di +32 -0
- package/tests/tag-check.test.di +27 -0
- package/config.yml +0 -9
- package/config.yml.bak +0 -8
- package/config.yml.ollama +0 -6
- package/config.yml.openai +0 -6
package/config.test.yml
ADDED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DiracParser
|
|
3
|
+
} from "./chunk-HRHAMPOB.js";
|
|
1
4
|
import {
|
|
2
5
|
executeSubroutine
|
|
3
6
|
} from "./chunk-E7PWEMZA.js";
|
|
@@ -91,7 +94,9 @@ async function executeDefvar(session, element) {
|
|
|
91
94
|
if (valueAttr !== void 0) {
|
|
92
95
|
value = substituteVariables(session, valueAttr);
|
|
93
96
|
} else if (literal) {
|
|
94
|
-
if (element.
|
|
97
|
+
if (element.children && element.children.length > 0) {
|
|
98
|
+
value = serializeToXml(element.children);
|
|
99
|
+
} else if (element.text) {
|
|
95
100
|
value = substituteVariables(session, element.text);
|
|
96
101
|
} else {
|
|
97
102
|
value = "";
|
|
@@ -118,6 +123,35 @@ async function executeDefvar(session, element) {
|
|
|
118
123
|
}
|
|
119
124
|
setVariable(session, name, value, visible);
|
|
120
125
|
}
|
|
126
|
+
function serializeToXml(children) {
|
|
127
|
+
let xml = "";
|
|
128
|
+
for (const child of children) {
|
|
129
|
+
if (!child.tag || child.tag === "") {
|
|
130
|
+
xml += child.text || "";
|
|
131
|
+
} else {
|
|
132
|
+
xml += `<${child.tag}`;
|
|
133
|
+
for (const [attrName, attrValue] of Object.entries(child.attributes)) {
|
|
134
|
+
xml += ` ${attrName}="${escapeXml(attrValue)}"`;
|
|
135
|
+
}
|
|
136
|
+
if (child.children.length === 0 && !child.text) {
|
|
137
|
+
xml += " />";
|
|
138
|
+
} else {
|
|
139
|
+
xml += ">";
|
|
140
|
+
if (child.text) {
|
|
141
|
+
xml += escapeXml(child.text);
|
|
142
|
+
}
|
|
143
|
+
if (child.children.length > 0) {
|
|
144
|
+
xml += serializeToXml(child.children);
|
|
145
|
+
}
|
|
146
|
+
xml += `</${child.tag}>`;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return xml;
|
|
151
|
+
}
|
|
152
|
+
function escapeXml(text) {
|
|
153
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
154
|
+
}
|
|
121
155
|
|
|
122
156
|
// src/tags/variable.ts
|
|
123
157
|
function executeVariable(session, element) {
|
|
@@ -234,6 +268,8 @@ async function executeCallInternal(session, subroutine, callElement, isExtendExe
|
|
|
234
268
|
const oldBoundary = setBoundary(session);
|
|
235
269
|
const wasReturn = session.isReturn;
|
|
236
270
|
session.isReturn = false;
|
|
271
|
+
const oldSubroutineName = session.currentSubroutineName;
|
|
272
|
+
session.currentSubroutineName = callElement.tag;
|
|
237
273
|
const oldSkipFlag = session.skipSubroutineRegistration;
|
|
238
274
|
if (isExtendExecution) {
|
|
239
275
|
session.skipSubroutineRegistration = true;
|
|
@@ -360,12 +396,12 @@ async function executeIf(session, element) {
|
|
|
360
396
|
const condition = await evaluatePredicate(session, conditionElement);
|
|
361
397
|
if (condition) {
|
|
362
398
|
if (thenElement) {
|
|
363
|
-
const { integrateChildren: integrateChildren2 } = await import("./interpreter-
|
|
399
|
+
const { integrateChildren: integrateChildren2 } = await import("./interpreter-GNO4J3HN.js");
|
|
364
400
|
await integrateChildren2(session, thenElement);
|
|
365
401
|
}
|
|
366
402
|
} else {
|
|
367
403
|
if (elseElement) {
|
|
368
|
-
const { integrateChildren: integrateChildren2 } = await import("./interpreter-
|
|
404
|
+
const { integrateChildren: integrateChildren2 } = await import("./interpreter-GNO4J3HN.js");
|
|
369
405
|
await integrateChildren2(session, elseElement);
|
|
370
406
|
}
|
|
371
407
|
}
|
|
@@ -378,7 +414,7 @@ async function evaluatePredicate(session, predicateElement) {
|
|
|
378
414
|
return await evaluateCondition(session, predicateElement);
|
|
379
415
|
}
|
|
380
416
|
const outputLengthBefore = session.output.length;
|
|
381
|
-
const { integrate: integrate2 } = await import("./interpreter-
|
|
417
|
+
const { integrate: integrate2 } = await import("./interpreter-GNO4J3HN.js");
|
|
382
418
|
await integrate2(session, predicateElement);
|
|
383
419
|
const newOutputChunks = session.output.slice(outputLengthBefore);
|
|
384
420
|
const result = newOutputChunks.join("").trim();
|
|
@@ -401,11 +437,11 @@ async function evaluateCondition(session, condElement) {
|
|
|
401
437
|
}
|
|
402
438
|
const outputLengthBefore = session.output.length;
|
|
403
439
|
const args = [];
|
|
404
|
-
const { integrate: integrate2 } = await import("./interpreter-
|
|
440
|
+
const { integrate: integrate2 } = await import("./interpreter-GNO4J3HN.js");
|
|
405
441
|
for (const child of condElement.children) {
|
|
406
442
|
if (child.tag.toLowerCase() === "arg") {
|
|
407
443
|
const argOutputStart = session.output.length;
|
|
408
|
-
const { integrateChildren: integrateChildren2 } = await import("./interpreter-
|
|
444
|
+
const { integrateChildren: integrateChildren2 } = await import("./interpreter-GNO4J3HN.js");
|
|
409
445
|
await integrateChildren2(session, child);
|
|
410
446
|
const newChunks = session.output.slice(argOutputStart);
|
|
411
447
|
const argValue = newChunks.join("");
|
|
@@ -463,126 +499,6 @@ function evaluateConditionType(evalType, args) {
|
|
|
463
499
|
}
|
|
464
500
|
}
|
|
465
501
|
|
|
466
|
-
// src/runtime/parser.ts
|
|
467
|
-
import { XMLParser } from "fast-xml-parser";
|
|
468
|
-
var DiracParser = class {
|
|
469
|
-
parser;
|
|
470
|
-
constructor() {
|
|
471
|
-
this.parser = new XMLParser({
|
|
472
|
-
ignoreAttributes: false,
|
|
473
|
-
attributeNamePrefix: "@_",
|
|
474
|
-
trimValues: false,
|
|
475
|
-
// Preserve whitespace in mixed content
|
|
476
|
-
parseAttributeValue: false,
|
|
477
|
-
parseTagValue: false,
|
|
478
|
-
textNodeName: "#text",
|
|
479
|
-
cdataPropName: "#cdata",
|
|
480
|
-
preserveOrder: true,
|
|
481
|
-
// Preserve element order!
|
|
482
|
-
commentPropName: "#comment"
|
|
483
|
-
});
|
|
484
|
-
}
|
|
485
|
-
parse(source) {
|
|
486
|
-
if (source.startsWith("#!")) {
|
|
487
|
-
source = source.replace(/^#!.*\n/, "");
|
|
488
|
-
}
|
|
489
|
-
source = `<DIRAC-ROOT>
|
|
490
|
-
${source}
|
|
491
|
-
</DIRAC-ROOT>`;
|
|
492
|
-
const result = this.parser.parse(source);
|
|
493
|
-
if (!Array.isArray(result) || result.length === 0) {
|
|
494
|
-
throw new Error("Empty or invalid XML");
|
|
495
|
-
}
|
|
496
|
-
for (const item of result) {
|
|
497
|
-
if (!item["#comment"]) {
|
|
498
|
-
return this.convertOrderedToElement(item);
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
throw new Error("No root element found");
|
|
502
|
-
}
|
|
503
|
-
convertOrderedToElement(obj) {
|
|
504
|
-
const tagName = Object.keys(obj).find((k) => k !== ":@" && k !== "#comment");
|
|
505
|
-
if (!tagName) {
|
|
506
|
-
throw new Error("Invalid element structure");
|
|
507
|
-
}
|
|
508
|
-
const element = {
|
|
509
|
-
tag: tagName,
|
|
510
|
-
attributes: {},
|
|
511
|
-
children: []
|
|
512
|
-
};
|
|
513
|
-
if (obj[":@"]) {
|
|
514
|
-
for (const [key, value] of Object.entries(obj[":@"])) {
|
|
515
|
-
if (key.startsWith("@_")) {
|
|
516
|
-
element.attributes[key.slice(2)] = value;
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
const children = obj[tagName];
|
|
521
|
-
if (Array.isArray(children)) {
|
|
522
|
-
for (const child of children) {
|
|
523
|
-
if (child["#text"]) {
|
|
524
|
-
element.children.push({
|
|
525
|
-
tag: "",
|
|
526
|
-
text: child["#text"],
|
|
527
|
-
attributes: {},
|
|
528
|
-
children: []
|
|
529
|
-
});
|
|
530
|
-
if (!element.text) {
|
|
531
|
-
element.text = child["#text"];
|
|
532
|
-
} else {
|
|
533
|
-
element.text += child["#text"];
|
|
534
|
-
}
|
|
535
|
-
} else if (child["#comment"]) {
|
|
536
|
-
continue;
|
|
537
|
-
} else {
|
|
538
|
-
element.children.push(this.convertOrderedToElement(child));
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
return element;
|
|
543
|
-
}
|
|
544
|
-
// Old method - no longer used
|
|
545
|
-
convertToElement(obj, tagName) {
|
|
546
|
-
if (!tagName) {
|
|
547
|
-
const keys = Object.keys(obj);
|
|
548
|
-
if (keys.length === 0) {
|
|
549
|
-
throw new Error("Empty XML");
|
|
550
|
-
}
|
|
551
|
-
tagName = keys[0];
|
|
552
|
-
obj = obj[tagName];
|
|
553
|
-
}
|
|
554
|
-
const element = {
|
|
555
|
-
tag: tagName,
|
|
556
|
-
attributes: {},
|
|
557
|
-
children: []
|
|
558
|
-
};
|
|
559
|
-
if (typeof obj === "string") {
|
|
560
|
-
element.text = obj;
|
|
561
|
-
return element;
|
|
562
|
-
}
|
|
563
|
-
if (!obj) {
|
|
564
|
-
return element;
|
|
565
|
-
}
|
|
566
|
-
for (const key of Object.keys(obj)) {
|
|
567
|
-
const value = obj[key];
|
|
568
|
-
if (key === "#text") {
|
|
569
|
-
element.text = value;
|
|
570
|
-
} else if (key.startsWith("@_")) {
|
|
571
|
-
element.attributes[key.slice(2)] = value;
|
|
572
|
-
} else {
|
|
573
|
-
if (Array.isArray(value)) {
|
|
574
|
-
for (const item of value) {
|
|
575
|
-
element.children.push(this.convertToElement(item, key));
|
|
576
|
-
}
|
|
577
|
-
} else {
|
|
578
|
-
element.children.push(this.convertToElement(value, key));
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
return element;
|
|
583
|
-
}
|
|
584
|
-
};
|
|
585
|
-
|
|
586
502
|
// src/tags/llm.ts
|
|
587
503
|
async function executeLLM(session, element) {
|
|
588
504
|
if (!session.llmClient) {
|
|
@@ -761,7 +677,7 @@ ${result}
|
|
|
761
677
|
const parser = new DiracParser();
|
|
762
678
|
let dynamicAST = parser.parse(diracCode);
|
|
763
679
|
if (validateTags) {
|
|
764
|
-
const { validateDiracCode, applyCorrectedTags } = await import("./tag-validator-
|
|
680
|
+
const { validateDiracCode, applyCorrectedTags } = await import("./tag-validator-CLYGULLQ.js");
|
|
765
681
|
let validation = await validateDiracCode(session, dynamicAST, { autocorrect });
|
|
766
682
|
let retryCount = 0;
|
|
767
683
|
while (!validation.valid && retryCount < maxRetries) {
|
|
@@ -1190,18 +1106,24 @@ import fs from "fs";
|
|
|
1190
1106
|
import yaml from "js-yaml";
|
|
1191
1107
|
var SIMILARITY_CUTOFF = 0.75;
|
|
1192
1108
|
function getEmbeddingServerConfig() {
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1109
|
+
try {
|
|
1110
|
+
const configPath = process.env.DIRAC_CONFIG || "config.yml";
|
|
1111
|
+
const config = yaml.load(fs.readFileSync(configPath, "utf8"));
|
|
1112
|
+
const host = config.embeddingServer?.host || "localhost";
|
|
1113
|
+
const port = config.embeddingServer?.port || 11434;
|
|
1114
|
+
const model = config.embeddingServer?.model || "embeddinggemma";
|
|
1115
|
+
return { host, port, model };
|
|
1116
|
+
} catch (e) {
|
|
1117
|
+
return { host: "localhost", port: 11434, model: "embeddinggemma" };
|
|
1118
|
+
}
|
|
1197
1119
|
}
|
|
1198
1120
|
async function getEmbeddings(tags) {
|
|
1199
|
-
const { host, port } = getEmbeddingServerConfig();
|
|
1121
|
+
const { host, port, model } = getEmbeddingServerConfig();
|
|
1200
1122
|
return await Promise.all(tags.map(async (tag) => {
|
|
1201
1123
|
const response = await fetch(`http://${host}:${port}/api/embeddings`, {
|
|
1202
1124
|
method: "POST",
|
|
1203
1125
|
headers: { "Content-Type": "application/json" },
|
|
1204
|
-
body: JSON.stringify({ model
|
|
1126
|
+
body: JSON.stringify({ model, prompt: tag })
|
|
1205
1127
|
});
|
|
1206
1128
|
const data = await response.json();
|
|
1207
1129
|
return data.embedding;
|
|
@@ -1237,6 +1159,9 @@ async function executeTagCheck(session, element) {
|
|
|
1237
1159
|
const shouldExecute = element.attributes?.execute === "true";
|
|
1238
1160
|
for (const child of element.children) {
|
|
1239
1161
|
const tagName = child.tag;
|
|
1162
|
+
if (!tagName || tagName.trim() === "") {
|
|
1163
|
+
continue;
|
|
1164
|
+
}
|
|
1240
1165
|
console.error(`[tag-check] Checking tag: <${tagName}>`);
|
|
1241
1166
|
let allValid = false;
|
|
1242
1167
|
let correctedTag = null;
|
|
@@ -1319,7 +1244,7 @@ async function executeTagCheck(session, element) {
|
|
|
1319
1244
|
const executeTag = correctedTag || tagName;
|
|
1320
1245
|
console.error(`[tag-check] Executing <${executeTag}/> as all checks passed and execute=true.`);
|
|
1321
1246
|
const elementToExecute = correctedTag ? { ...child, tag: correctedTag } : child;
|
|
1322
|
-
const { integrate: integrate2 } = await import("./interpreter-
|
|
1247
|
+
const { integrate: integrate2 } = await import("./interpreter-GNO4J3HN.js");
|
|
1323
1248
|
await integrate2(session, elementToExecute);
|
|
1324
1249
|
}
|
|
1325
1250
|
}
|
|
@@ -1328,7 +1253,7 @@ async function executeTagCheck(session, element) {
|
|
|
1328
1253
|
// src/tags/throw.ts
|
|
1329
1254
|
async function executeThrow(session, element) {
|
|
1330
1255
|
const exceptionName = element.attributes?.name || "exception";
|
|
1331
|
-
const { integrateChildren: integrateChildren2 } = await import("./interpreter-
|
|
1256
|
+
const { integrateChildren: integrateChildren2 } = await import("./interpreter-GNO4J3HN.js");
|
|
1332
1257
|
const exceptionDom = {
|
|
1333
1258
|
tag: "exception-content",
|
|
1334
1259
|
attributes: { name: exceptionName },
|
|
@@ -1341,7 +1266,7 @@ async function executeThrow(session, element) {
|
|
|
1341
1266
|
// src/tags/try.ts
|
|
1342
1267
|
async function executeTry(session, element) {
|
|
1343
1268
|
setExceptionBoundary(session);
|
|
1344
|
-
const { integrateChildren: integrateChildren2 } = await import("./interpreter-
|
|
1269
|
+
const { integrateChildren: integrateChildren2 } = await import("./interpreter-GNO4J3HN.js");
|
|
1345
1270
|
await integrateChildren2(session, element);
|
|
1346
1271
|
unsetExceptionBoundary(session);
|
|
1347
1272
|
}
|
|
@@ -1351,7 +1276,7 @@ async function executeCatch(session, element) {
|
|
|
1351
1276
|
const exceptionName = element.attributes?.name || "exception";
|
|
1352
1277
|
const caughtCount = lookupException(session, exceptionName);
|
|
1353
1278
|
if (caughtCount > 0) {
|
|
1354
|
-
const { integrateChildren: integrateChildren2 } = await import("./interpreter-
|
|
1279
|
+
const { integrateChildren: integrateChildren2 } = await import("./interpreter-GNO4J3HN.js");
|
|
1355
1280
|
await integrateChildren2(session, element);
|
|
1356
1281
|
}
|
|
1357
1282
|
flushCurrentException(session);
|
|
@@ -1360,7 +1285,7 @@ async function executeCatch(session, element) {
|
|
|
1360
1285
|
// src/tags/exception.ts
|
|
1361
1286
|
async function executeException(session, element) {
|
|
1362
1287
|
const exceptions = getCurrentExceptions(session);
|
|
1363
|
-
const { integrateChildren: integrateChildren2 } = await import("./interpreter-
|
|
1288
|
+
const { integrateChildren: integrateChildren2 } = await import("./interpreter-GNO4J3HN.js");
|
|
1364
1289
|
for (const exceptionDom of exceptions) {
|
|
1365
1290
|
await integrateChildren2(session, exceptionDom);
|
|
1366
1291
|
}
|
|
@@ -1449,32 +1374,189 @@ function evaluateCondition2(session, test) {
|
|
|
1449
1374
|
// src/tags/available-subroutines.ts
|
|
1450
1375
|
async function executeAvailableSubroutines(session, element) {
|
|
1451
1376
|
const availableSubroutines = /* @__PURE__ */ new Map();
|
|
1377
|
+
const currentSubroutineName = session.subBoundary < session.subroutines.length ? session.subroutines[session.subBoundary].name : null;
|
|
1452
1378
|
for (let i = session.subroutines.length - 1; i >= session.subBoundary; i--) {
|
|
1453
1379
|
const sub = session.subroutines[i];
|
|
1380
|
+
if (sub.name === currentSubroutineName) {
|
|
1381
|
+
continue;
|
|
1382
|
+
}
|
|
1454
1383
|
if (!availableSubroutines.has(sub.name)) {
|
|
1455
1384
|
availableSubroutines.set(sub.name, sub.element);
|
|
1456
1385
|
}
|
|
1457
1386
|
}
|
|
1387
|
+
session.output.push("<subroutines>");
|
|
1458
1388
|
for (const [name, subElement] of availableSubroutines) {
|
|
1459
|
-
const attrs = [];
|
|
1389
|
+
const attrs = [`name="${escapeXml2(name)}"`];
|
|
1460
1390
|
const description = subElement.attributes.description;
|
|
1461
1391
|
if (description) {
|
|
1462
|
-
attrs.push(`description="${
|
|
1392
|
+
attrs.push(`description="${escapeXml2(description)}"`);
|
|
1463
1393
|
}
|
|
1464
1394
|
for (const [attrName, attrValue] of Object.entries(subElement.attributes)) {
|
|
1465
1395
|
if (attrName.startsWith("param-")) {
|
|
1466
|
-
|
|
1467
|
-
attrs.push(`${paramName}="${escapeXml(attrValue)}"`);
|
|
1396
|
+
attrs.push(`${attrName}="${escapeXml2(attrValue)}"`);
|
|
1468
1397
|
}
|
|
1469
1398
|
}
|
|
1470
|
-
const attrString = attrs.
|
|
1471
|
-
session.output.push(
|
|
1399
|
+
const attrString = attrs.join(" ");
|
|
1400
|
+
session.output.push(` <subroutine ${attrString} />`);
|
|
1472
1401
|
}
|
|
1402
|
+
session.output.push("</subroutines>");
|
|
1473
1403
|
}
|
|
1474
|
-
function
|
|
1404
|
+
function escapeXml2(text) {
|
|
1475
1405
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1476
1406
|
}
|
|
1477
1407
|
|
|
1408
|
+
// src/tags/foreach.ts
|
|
1409
|
+
import { XMLParser } from "fast-xml-parser";
|
|
1410
|
+
async function executeForeach(session, element) {
|
|
1411
|
+
const fromAttr = element.attributes.from;
|
|
1412
|
+
const asVar = element.attributes.as || "item";
|
|
1413
|
+
const xpath = element.attributes.xpath;
|
|
1414
|
+
if (!fromAttr) {
|
|
1415
|
+
throw new Error('<foreach> requires "from" attribute');
|
|
1416
|
+
}
|
|
1417
|
+
let xmlContent;
|
|
1418
|
+
if (fromAttr.startsWith("$")) {
|
|
1419
|
+
const varName = fromAttr.substring(1);
|
|
1420
|
+
xmlContent = getVariable(session, varName) || "";
|
|
1421
|
+
} else if (fromAttr.startsWith("<")) {
|
|
1422
|
+
const savedOutput = session.output;
|
|
1423
|
+
session.output = [];
|
|
1424
|
+
const { DiracParser: DiracParser2 } = await import("./parser-T6W3WPLU.js");
|
|
1425
|
+
const parser2 = new DiracParser2();
|
|
1426
|
+
try {
|
|
1427
|
+
const fromElement = parser2.parse(fromAttr);
|
|
1428
|
+
const { integrate: integrate2 } = await import("./interpreter-GNO4J3HN.js");
|
|
1429
|
+
await integrate2(session, fromElement);
|
|
1430
|
+
} catch (e) {
|
|
1431
|
+
session.output = savedOutput;
|
|
1432
|
+
throw new Error(`Failed to evaluate from="${fromAttr}": ${e}`);
|
|
1433
|
+
}
|
|
1434
|
+
xmlContent = session.output.join("");
|
|
1435
|
+
session.output = savedOutput;
|
|
1436
|
+
} else {
|
|
1437
|
+
xmlContent = substituteVariables(session, fromAttr);
|
|
1438
|
+
}
|
|
1439
|
+
if (!xmlContent || xmlContent.trim() === "") {
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
const parser = new XMLParser({
|
|
1443
|
+
ignoreAttributes: false,
|
|
1444
|
+
attributeNamePrefix: "@_",
|
|
1445
|
+
parseAttributeValue: false,
|
|
1446
|
+
preserveOrder: true
|
|
1447
|
+
});
|
|
1448
|
+
let parsed;
|
|
1449
|
+
try {
|
|
1450
|
+
parsed = parser.parse(`<root>${xmlContent}</root>`);
|
|
1451
|
+
} catch (e) {
|
|
1452
|
+
throw new Error(`Failed to parse XML in <foreach>: ${e}`);
|
|
1453
|
+
}
|
|
1454
|
+
const items = extractElements(parsed, xpath);
|
|
1455
|
+
for (const item of items) {
|
|
1456
|
+
setVariable(session, asVar, item, false);
|
|
1457
|
+
await integrateChildren(session, element);
|
|
1458
|
+
if (session.isBreak) {
|
|
1459
|
+
session.isBreak = false;
|
|
1460
|
+
break;
|
|
1461
|
+
}
|
|
1462
|
+
if (session.isReturn) {
|
|
1463
|
+
break;
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
function extractElements(parsed, xpath) {
|
|
1468
|
+
const items = [];
|
|
1469
|
+
if (!Array.isArray(parsed)) {
|
|
1470
|
+
return items;
|
|
1471
|
+
}
|
|
1472
|
+
const extractFromNode = (node) => {
|
|
1473
|
+
if (!node) return;
|
|
1474
|
+
const tagName = Object.keys(node).find((k) => k !== ":@" && k !== "#text" && k !== "#comment");
|
|
1475
|
+
if (!tagName) return;
|
|
1476
|
+
const item = {
|
|
1477
|
+
tag: tagName,
|
|
1478
|
+
attributes: {}
|
|
1479
|
+
};
|
|
1480
|
+
if (node[":@"]) {
|
|
1481
|
+
for (const [key, value] of Object.entries(node[":@"])) {
|
|
1482
|
+
if (key.startsWith("@_")) {
|
|
1483
|
+
item.attributes[key.slice(2)] = value;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
const children = node[tagName];
|
|
1488
|
+
if (Array.isArray(children)) {
|
|
1489
|
+
for (const child of children) {
|
|
1490
|
+
if (child["#text"]) {
|
|
1491
|
+
item.text = (item.text || "") + child["#text"];
|
|
1492
|
+
} else {
|
|
1493
|
+
extractFromNode(child);
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
if (!xpath || matchesXPath(item, xpath)) {
|
|
1498
|
+
items.push(item);
|
|
1499
|
+
}
|
|
1500
|
+
};
|
|
1501
|
+
for (const rootItem of parsed) {
|
|
1502
|
+
if (rootItem["root"]) {
|
|
1503
|
+
const rootChildren = rootItem["root"];
|
|
1504
|
+
if (Array.isArray(rootChildren)) {
|
|
1505
|
+
for (const child of rootChildren) {
|
|
1506
|
+
extractFromNode(child);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
return items;
|
|
1512
|
+
}
|
|
1513
|
+
function matchesXPath(item, xpath) {
|
|
1514
|
+
const tagMatch = xpath.match(/\/{0,2}(\w+)/);
|
|
1515
|
+
if (tagMatch) {
|
|
1516
|
+
return item.tag === tagMatch[1];
|
|
1517
|
+
}
|
|
1518
|
+
return true;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
// src/tags/attr.ts
|
|
1522
|
+
async function executeAttr(session, element) {
|
|
1523
|
+
const nameAttr = element.attributes.name;
|
|
1524
|
+
const fromAttr = element.attributes.from;
|
|
1525
|
+
if (!nameAttr) {
|
|
1526
|
+
throw new Error('<attr> requires "name" attribute');
|
|
1527
|
+
}
|
|
1528
|
+
if (!fromAttr) {
|
|
1529
|
+
throw new Error('<attr> requires "from" attribute');
|
|
1530
|
+
}
|
|
1531
|
+
let item;
|
|
1532
|
+
if (fromAttr.startsWith("$")) {
|
|
1533
|
+
const varName = fromAttr.substring(1);
|
|
1534
|
+
item = getVariable(session, varName);
|
|
1535
|
+
} else {
|
|
1536
|
+
const substituted = substituteVariables(session, fromAttr);
|
|
1537
|
+
item = getVariable(session, substituted);
|
|
1538
|
+
}
|
|
1539
|
+
if (!item) {
|
|
1540
|
+
return;
|
|
1541
|
+
}
|
|
1542
|
+
let value = "";
|
|
1543
|
+
if (typeof item === "object") {
|
|
1544
|
+
if (item.attributes && typeof item.attributes === "object") {
|
|
1545
|
+
value = item.attributes[nameAttr] || "";
|
|
1546
|
+
} else if (item[nameAttr] !== void 0) {
|
|
1547
|
+
value = String(item[nameAttr]);
|
|
1548
|
+
}
|
|
1549
|
+
} else if (typeof item === "string") {
|
|
1550
|
+
value = extractAttrFromXml(item, nameAttr);
|
|
1551
|
+
}
|
|
1552
|
+
session.output.push(value);
|
|
1553
|
+
}
|
|
1554
|
+
function extractAttrFromXml(xml, attrName) {
|
|
1555
|
+
const regex = new RegExp(`${attrName}="([^"]*)"`, "i");
|
|
1556
|
+
const match = xml.match(regex);
|
|
1557
|
+
return match ? match[1] : "";
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1478
1560
|
// src/runtime/interpreter.ts
|
|
1479
1561
|
async function integrate(session, element) {
|
|
1480
1562
|
if (session.limits.currentDepth >= session.limits.maxDepth) {
|
|
@@ -1561,6 +1643,12 @@ async function integrate(session, element) {
|
|
|
1561
1643
|
case "available-subroutines":
|
|
1562
1644
|
await executeAvailableSubroutines(session, element);
|
|
1563
1645
|
break;
|
|
1646
|
+
case "foreach":
|
|
1647
|
+
await executeForeach(session, element);
|
|
1648
|
+
break;
|
|
1649
|
+
case "attr":
|
|
1650
|
+
await executeAttr(session, element);
|
|
1651
|
+
break;
|
|
1564
1652
|
case "require_module":
|
|
1565
1653
|
await executeRequireModule(session, element);
|
|
1566
1654
|
break;
|
|
@@ -1594,7 +1682,6 @@ async function integrateChildren(session, element) {
|
|
|
1594
1682
|
}
|
|
1595
1683
|
|
|
1596
1684
|
export {
|
|
1597
|
-
DiracParser,
|
|
1598
1685
|
integrate,
|
|
1599
1686
|
integrateChildren
|
|
1600
1687
|
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// src/runtime/parser.ts
|
|
2
|
+
import { XMLParser } from "fast-xml-parser";
|
|
3
|
+
var DiracParser = class {
|
|
4
|
+
parser;
|
|
5
|
+
constructor() {
|
|
6
|
+
this.parser = new XMLParser({
|
|
7
|
+
ignoreAttributes: false,
|
|
8
|
+
attributeNamePrefix: "@_",
|
|
9
|
+
trimValues: false,
|
|
10
|
+
// Preserve whitespace in mixed content
|
|
11
|
+
parseAttributeValue: false,
|
|
12
|
+
parseTagValue: false,
|
|
13
|
+
textNodeName: "#text",
|
|
14
|
+
cdataPropName: "#cdata",
|
|
15
|
+
preserveOrder: true,
|
|
16
|
+
// Preserve element order!
|
|
17
|
+
commentPropName: "#comment"
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
parse(source) {
|
|
21
|
+
if (source.startsWith("#!")) {
|
|
22
|
+
source = source.replace(/^#!.*\n/, "");
|
|
23
|
+
}
|
|
24
|
+
source = `<DIRAC-ROOT>
|
|
25
|
+
${source}
|
|
26
|
+
</DIRAC-ROOT>`;
|
|
27
|
+
const result = this.parser.parse(source);
|
|
28
|
+
if (!Array.isArray(result) || result.length === 0) {
|
|
29
|
+
throw new Error("Empty or invalid XML");
|
|
30
|
+
}
|
|
31
|
+
for (const item of result) {
|
|
32
|
+
if (!item["#comment"]) {
|
|
33
|
+
return this.convertOrderedToElement(item);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
throw new Error("No root element found");
|
|
37
|
+
}
|
|
38
|
+
convertOrderedToElement(obj) {
|
|
39
|
+
const tagName = Object.keys(obj).find((k) => k !== ":@" && k !== "#comment");
|
|
40
|
+
if (!tagName) {
|
|
41
|
+
throw new Error("Invalid element structure");
|
|
42
|
+
}
|
|
43
|
+
const element = {
|
|
44
|
+
tag: tagName,
|
|
45
|
+
attributes: {},
|
|
46
|
+
children: []
|
|
47
|
+
};
|
|
48
|
+
if (obj[":@"]) {
|
|
49
|
+
for (const [key, value] of Object.entries(obj[":@"])) {
|
|
50
|
+
if (key.startsWith("@_")) {
|
|
51
|
+
element.attributes[key.slice(2)] = value;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const children = obj[tagName];
|
|
56
|
+
if (Array.isArray(children)) {
|
|
57
|
+
for (const child of children) {
|
|
58
|
+
if (child["#text"]) {
|
|
59
|
+
element.children.push({
|
|
60
|
+
tag: "",
|
|
61
|
+
text: child["#text"],
|
|
62
|
+
attributes: {},
|
|
63
|
+
children: []
|
|
64
|
+
});
|
|
65
|
+
if (!element.text) {
|
|
66
|
+
element.text = child["#text"];
|
|
67
|
+
} else {
|
|
68
|
+
element.text += child["#text"];
|
|
69
|
+
}
|
|
70
|
+
} else if (child["#comment"]) {
|
|
71
|
+
continue;
|
|
72
|
+
} else {
|
|
73
|
+
element.children.push(this.convertOrderedToElement(child));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return element;
|
|
78
|
+
}
|
|
79
|
+
// Old method - no longer used
|
|
80
|
+
convertToElement(obj, tagName) {
|
|
81
|
+
if (!tagName) {
|
|
82
|
+
const keys = Object.keys(obj);
|
|
83
|
+
if (keys.length === 0) {
|
|
84
|
+
throw new Error("Empty XML");
|
|
85
|
+
}
|
|
86
|
+
tagName = keys[0];
|
|
87
|
+
obj = obj[tagName];
|
|
88
|
+
}
|
|
89
|
+
const element = {
|
|
90
|
+
tag: tagName,
|
|
91
|
+
attributes: {},
|
|
92
|
+
children: []
|
|
93
|
+
};
|
|
94
|
+
if (typeof obj === "string") {
|
|
95
|
+
element.text = obj;
|
|
96
|
+
return element;
|
|
97
|
+
}
|
|
98
|
+
if (!obj) {
|
|
99
|
+
return element;
|
|
100
|
+
}
|
|
101
|
+
for (const key of Object.keys(obj)) {
|
|
102
|
+
const value = obj[key];
|
|
103
|
+
if (key === "#text") {
|
|
104
|
+
element.text = value;
|
|
105
|
+
} else if (key.startsWith("@_")) {
|
|
106
|
+
element.attributes[key.slice(2)] = value;
|
|
107
|
+
} else {
|
|
108
|
+
if (Array.isArray(value)) {
|
|
109
|
+
for (const item of value) {
|
|
110
|
+
element.children.push(this.convertToElement(item, key));
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
element.children.push(this.convertToElement(value, key));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return element;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export {
|
|
122
|
+
DiracParser
|
|
123
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
execute
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-FEOBVBSI.js";
|
|
5
|
+
import "./chunk-CP4YCRBG.js";
|
|
6
|
+
import "./chunk-HRHAMPOB.js";
|
|
6
7
|
import "./chunk-E7PWEMZA.js";
|
|
7
8
|
import "./chunk-52ED23DR.js";
|
|
8
9
|
|
|
@@ -12,7 +13,7 @@ import "dotenv/config";
|
|
|
12
13
|
// package.json
|
|
13
14
|
var package_default = {
|
|
14
15
|
name: "dirac-lang",
|
|
15
|
-
version: "0.1.
|
|
16
|
+
version: "0.1.16",
|
|
16
17
|
description: "LLM-Augmented Declarative Execution",
|
|
17
18
|
type: "module",
|
|
18
19
|
main: "dist/index.js",
|