drools-builder 0.1.3 → 1.0.1

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 CHANGED
@@ -614,8 +614,72 @@ ${indent}}`;
614
614
  return `${cons.expression};`;
615
615
  case "RawConsequence":
616
616
  return `${cons.code};`;
617
+ case "ReturnConsequence":
618
+ return cons.expression ? `return ${cons.expression};` : "return;";
619
+ case "WhileConsequence": {
620
+ const body = cons.body.map((c) => `${indent} ${generateConsequence(c, indent + " ")}`).join("\n");
621
+ return `while (${cons.condition}) {
622
+ ${body}
623
+ ${indent}}`;
624
+ }
625
+ case "ForEachConsequence": {
626
+ const body = cons.body.map((c) => `${indent} ${generateConsequence(c, indent + " ")}`).join("\n");
627
+ return `for (${cons.typeName} ${cons.varName} : ${cons.collection}) {
628
+ ${body}
629
+ ${indent}}`;
630
+ }
631
+ case "ForConsequence": {
632
+ const body = cons.body.map((c) => `${indent} ${generateConsequence(c, indent + " ")}`).join("\n");
633
+ return `for (${cons.init}; ${cons.condition}; ${cons.update}) {
634
+ ${body}
635
+ ${indent}}`;
636
+ }
637
+ case "VarDeclConsequence":
638
+ return `${cons.typeName} ${cons.name} = ${cons.value};`;
639
+ case "MethodCallConsequence":
640
+ return `${cons.object}.${cons.method}(${cons.args});`;
641
+ case "SwitchConsequence": {
642
+ const caseLines = cons.cases.map((c) => {
643
+ const body = c.body.map((b) => `${indent} ${generateConsequence(b, indent + " ")}`).join("\n");
644
+ return `${indent} case ${c.value}:
645
+ ${body}
646
+ ${indent} break;`;
647
+ });
648
+ if (cons.default && cons.default.length > 0) {
649
+ const defBody = cons.default.map((b) => `${indent} ${generateConsequence(b, indent + " ")}`).join("\n");
650
+ caseLines.push(`${indent} default:
651
+ ${defBody}`);
652
+ }
653
+ return `switch (${cons.expression}) {
654
+ ${caseLines.join("\n")}
655
+ ${indent}}`;
656
+ }
657
+ case "IfConsequence": {
658
+ const thenLines = cons.then.map((c) => `${indent} ${generateConsequence(c, indent + " ")}`).join("\n");
659
+ if (cons.else && cons.else.length > 0) {
660
+ const elseLines = cons.else.map((c) => `${indent} ${generateConsequence(c, indent + " ")}`).join("\n");
661
+ return `if (${cons.condition}) {
662
+ ${thenLines}
663
+ ${indent}} else {
664
+ ${elseLines}
665
+ ${indent}}`;
666
+ }
667
+ return `if (${cons.condition}) {
668
+ ${thenLines}
669
+ ${indent}}`;
670
+ }
617
671
  }
618
672
  }
673
+ function generateDeclaration(decl) {
674
+ const attrs = decl.attributes.map((a) => ` ${a.name} : ${a.type}`).join("\n");
675
+ return `declare ${decl.className}${attrs ? "\n" + attrs + "\n" : "\n"}end`;
676
+ }
677
+ function generateFunction(fn, indent = " ") {
678
+ const body = fn.body.map((c) => `${indent}${generateConsequence(c, indent)}`).join("\n");
679
+ return `function ${fn.returnType} ${fn.name}(${fn.params}) {
680
+ ${body}
681
+ }`;
682
+ }
619
683
  function generateRule(rule) {
620
684
  const lines = [`rule "${rule.name}"`];
621
685
  if (rule.salience !== void 0) lines.push(` salience ${rule.salience}`);
@@ -637,6 +701,10 @@ var MetaToDRLTransformer = {
637
701
  sections.push(file.imports.map((i) => `import ${i};`).join("\n"));
638
702
  if (file.globals.length > 0)
639
703
  sections.push(file.globals.map((g) => `global ${g.type} ${g.name};`).join("\n"));
704
+ if (file.declarations && file.declarations.length > 0)
705
+ sections.push(file.declarations.map((d) => generateDeclaration(d)).join("\n\n"));
706
+ if (file.functions && file.functions.length > 0)
707
+ sections.push(file.functions.map((fn) => generateFunction(fn)).join("\n\n"));
640
708
  sections.push(file.rules.map(generateRule).join("\n\n"));
641
709
  return sections.join("\n\n");
642
710
  },
@@ -754,24 +822,54 @@ function parseGlobals(drl) {
754
822
  }
755
823
  function extractRuleBlocks(drl) {
756
824
  const blocks = [];
757
- const re = /\brule\s+"[^"]*"[\s\S]*?\bend\b/g;
825
+ const re = /\brule\s+(?:"[^"]*"|'[^']*')[\s\S]*?\bend\b/g;
758
826
  let m;
759
827
  while ((m = re.exec(drl)) !== null) blocks.push(m[0]);
760
828
  return blocks;
761
829
  }
830
+ function parseFunctions(drl) {
831
+ const results = [];
832
+ const re = /\bfunction\s+([\w<>?,\s\[\]]+?)\s+(\w+)\s*\(([^)]*)\)\s*\{([^{}]*(?:\{[^{}]*\}[^{}]*)*)\}/g;
833
+ let m;
834
+ while ((m = re.exec(drl)) !== null) {
835
+ results.push({
836
+ returnType: m[1].trim(),
837
+ name: m[2].trim(),
838
+ params: m[3].trim(),
839
+ body: parseConsequences(m[4].trim())
840
+ });
841
+ }
842
+ return results;
843
+ }
844
+ function parseDeclarations(drl) {
845
+ const results = [];
846
+ const re = /\bdeclare\s+(\w+)\s*([\s\S]*?)\bend\b/g;
847
+ let m;
848
+ while ((m = re.exec(drl)) !== null) {
849
+ const className = m[1].trim();
850
+ const attributes = [];
851
+ const attrRe = /^\s*(\w+)\s*:\s*(\S+)/gm;
852
+ let a;
853
+ while ((a = attrRe.exec(m[2])) !== null) {
854
+ attributes.push({ name: a[1].trim(), type: a[2].trim() });
855
+ }
856
+ results.push({ className, attributes });
857
+ }
858
+ return results;
859
+ }
762
860
  function parseRuleName(block) {
763
- const m = block.match(/\brule\s+"([^"]+)"/);
764
- return m ? m[1] : "unknown";
861
+ const m = block.match(/\brule\s+(?:"([^"]+)"|'([^']+)')/);
862
+ return m ? m[1] ?? m[2] : "unknown";
765
863
  }
766
864
  function parseRuleAttributes(block) {
767
865
  const attrs = {};
768
- const m = block.match(/\brule\s+"[^"]+"\s*([\s\S]*?)\bwhen\b/);
866
+ const m = block.match(/\brule\s+(?:"[^"]+"|'[^']+')\s*([\s\S]*?)\bwhen\b/);
769
867
  if (!m) return attrs;
770
868
  const attr = m[1];
771
869
  const salience = attr.match(/\bsalience\s+(-?\d+)/);
772
870
  if (salience) attrs.salience = parseInt(salience[1], 10);
773
- if (/\bno-loop\s+true\b/.test(attr)) attrs.noLoop = true;
774
- if (/\block-on-active\s+true\b/.test(attr)) attrs.lockOnActive = true;
871
+ if (!/\bno-loop\s+false\b/.test(attr) && /\bno-loop\b/.test(attr)) attrs.noLoop = true;
872
+ if (!/\block-on-active\s+false\b/.test(attr) && /\block-on-active\b/.test(attr)) attrs.lockOnActive = true;
775
873
  const ag = attr.match(/\bagenda-group\s+"([^"]+)"/);
776
874
  if (ag) attrs.agendaGroup = ag[1];
777
875
  const rfg = attr.match(/\bruleflow-group\s+"([^"]+)"/);
@@ -937,6 +1035,31 @@ function parseFrom(text, fromIdx) {
937
1035
  expression: text.slice(fromIdx + " from ".length).trim()
938
1036
  };
939
1037
  }
1038
+ function parseSwitchBody(body) {
1039
+ const cases = [];
1040
+ let defaultBody;
1041
+ const markers = [];
1042
+ const caseRe = /\bcase\s+([^:]+):/g;
1043
+ const defRe = /\bdefault\s*:/g;
1044
+ let m;
1045
+ while ((m = caseRe.exec(body)) !== null)
1046
+ markers.push({ index: m.index, headerLen: m[0].length, type: "case", value: m[1].trim() });
1047
+ while ((m = defRe.exec(body)) !== null)
1048
+ markers.push({ index: m.index, headerLen: m[0].length, type: "default" });
1049
+ markers.sort((a, b) => a.index - b.index);
1050
+ for (let i = 0; i < markers.length; i++) {
1051
+ const marker = markers[i];
1052
+ const contentStart = marker.index + marker.headerLen;
1053
+ const contentEnd = i + 1 < markers.length ? markers[i + 1].index : body.length;
1054
+ const raw = body.slice(contentStart, contentEnd).trim();
1055
+ const content = raw.replace(/\s*\bbreak\s*;\s*$/, "").trim();
1056
+ if (marker.type === "case")
1057
+ cases.push({ kind: "CaseConsequence", value: marker.value, body: parseConsequences(content) });
1058
+ else
1059
+ defaultBody = parseConsequences(content);
1060
+ }
1061
+ return { cases, ...defaultBody !== void 0 && { default: defaultBody } };
1062
+ }
940
1063
  function parseConsequences(then) {
941
1064
  const consequences = [];
942
1065
  let remaining = then.trim();
@@ -951,6 +1074,65 @@ function parseConsequences(then) {
951
1074
  function parseNextConsequence(text) {
952
1075
  const t = text.trim();
953
1076
  if (!t) return null;
1077
+ if (/^while\s*\(/.test(t)) {
1078
+ const condition = extractBalanced(t, "(", ")");
1079
+ const afterCond = t.slice(t.indexOf("(") + condition.length + 2).trim();
1080
+ const body = extractBalanced(afterCond, "{", "}");
1081
+ const endIdx = afterCond.indexOf("{") + body.length + 2;
1082
+ return {
1083
+ consequence: { kind: "WhileConsequence", condition: condition.trim(), body: parseConsequences(body) },
1084
+ rest: afterCond.slice(endIdx)
1085
+ };
1086
+ }
1087
+ if (/^for\s*\(/.test(t)) {
1088
+ const header = extractBalanced(t, "(", ")");
1089
+ const afterHeader = t.slice(t.indexOf("(") + header.length + 2).trim();
1090
+ const body = extractBalanced(afterHeader, "{", "}");
1091
+ const endIdx = afterHeader.indexOf("{") + body.length + 2;
1092
+ const colonIdx = indexAtDepth0(header, ":");
1093
+ if (colonIdx !== -1 && indexAtDepth0(header, ";") === -1) {
1094
+ const parts = header.slice(0, colonIdx).trim().split(/\s+/);
1095
+ const varName = parts.pop();
1096
+ const typeName = parts.join(" ");
1097
+ return {
1098
+ consequence: { kind: "ForEachConsequence", typeName, varName, collection: header.slice(colonIdx + 1).trim(), body: parseConsequences(body) },
1099
+ rest: afterHeader.slice(endIdx)
1100
+ };
1101
+ } else {
1102
+ const parts = splitAtDepth0(header, ";");
1103
+ return {
1104
+ consequence: { kind: "ForConsequence", init: (parts[0] ?? "").trim(), condition: (parts[1] ?? "").trim(), update: (parts[2] ?? "").trim(), body: parseConsequences(body) },
1105
+ rest: afterHeader.slice(endIdx)
1106
+ };
1107
+ }
1108
+ }
1109
+ if (/^switch\s*\(/.test(t)) {
1110
+ const expression = extractBalanced(t, "(", ")");
1111
+ const afterExpr = t.slice(t.indexOf("(") + expression.length + 2).trim();
1112
+ const switchBody = extractBalanced(afterExpr, "{", "}");
1113
+ const endIdx = afterExpr.indexOf("{") + switchBody.length + 2;
1114
+ return {
1115
+ consequence: { kind: "SwitchConsequence", expression: expression.trim(), ...parseSwitchBody(switchBody) },
1116
+ rest: afterExpr.slice(endIdx)
1117
+ };
1118
+ }
1119
+ if (/^if\s*\(/.test(t)) {
1120
+ const condition = extractBalanced(t, "(", ")");
1121
+ const afterCond = t.slice(t.indexOf("(") + condition.length + 2).trim();
1122
+ const thenBlock = extractBalanced(afterCond, "{", "}");
1123
+ const thenConsequences = parseConsequences(thenBlock);
1124
+ let afterThen = afterCond.slice(afterCond.indexOf("{") + thenBlock.length + 2).trim();
1125
+ let elseConsequences;
1126
+ if (/^else\s*\{/.test(afterThen)) {
1127
+ const elseBlock = extractBalanced(afterThen, "{", "}");
1128
+ elseConsequences = parseConsequences(elseBlock);
1129
+ afterThen = afterThen.slice(afterThen.indexOf("{") + elseBlock.length + 2).trim();
1130
+ }
1131
+ return {
1132
+ consequence: { kind: "IfConsequence", condition: condition.trim(), then: thenConsequences, ...elseConsequences && { else: elseConsequences } },
1133
+ rest: afterThen
1134
+ };
1135
+ }
954
1136
  if (/^modify\s*\(/.test(t)) {
955
1137
  const m = t.match(/^modify\s*\(\s*(\$\w+)\s*\)/);
956
1138
  if (m) {
@@ -973,6 +1155,14 @@ function parseNextConsequence(text) {
973
1155
  const rest = t.slice(t.indexOf("(") + inner.length + 2).replace(/^\s*;/, "");
974
1156
  return { consequence: { kind: "RetractConsequence", binding: inner.trim() }, rest };
975
1157
  }
1158
+ if (/^return\b/.test(t)) {
1159
+ const semiIdx2 = indexAtDepth0(t, ";");
1160
+ const expression = t.slice("return".length, semiIdx2 !== -1 ? semiIdx2 : void 0).trim();
1161
+ return {
1162
+ consequence: { kind: "ReturnConsequence", expression },
1163
+ rest: semiIdx2 !== -1 ? t.slice(semiIdx2 + 1) : ""
1164
+ };
1165
+ }
976
1166
  const semiIdx = indexAtDepth0(t, ";");
977
1167
  if (semiIdx !== -1)
978
1168
  return { consequence: { kind: "RawConsequence", code: t.slice(0, semiIdx).trim() }, rest: t.slice(semiIdx + 1) };
@@ -991,8 +1181,10 @@ var DRLToMetaTransformer = {
991
1181
  const clean = stripComments(drl);
992
1182
  return {
993
1183
  name: "parsed",
994
- imports: parseImports(clean),
1184
+ imports: [...new Set(parseImports(clean))],
995
1185
  globals: parseGlobals(clean),
1186
+ declarations: parseDeclarations(clean),
1187
+ functions: parseFunctions(clean),
996
1188
  rules: extractRuleBlocks(clean).map((block) => DRLToMetaTransformer.parseRule(block))
997
1189
  };
998
1190
  },