drools-builder 0.1.1 → 0.1.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/README.md CHANGED
@@ -77,6 +77,7 @@ Plain metamodel objects are accepted everywhere a builder is expected.
77
77
  const file = createFile('fraud-rules')
78
78
  .import('com.example.Account')
79
79
  .import('com.example.FraudAlert')
80
+ .global('com.example.AlertService', 'alertService')
80
81
  .addRule(rule)
81
82
  .addRule(createRule('Another Rule').when(...).then(...))
82
83
  .build()
package/dist/index.cjs CHANGED
@@ -430,6 +430,7 @@ function resolveRule(input) {
430
430
  var DroolsFileBuilder = class {
431
431
  constructor(name) {
432
432
  this._imports = [];
433
+ this._globals = [];
433
434
  this._rules = [];
434
435
  this._name = name;
435
436
  }
@@ -444,6 +445,17 @@ var DroolsFileBuilder = class {
444
445
  this._imports.push(className);
445
446
  return this;
446
447
  }
448
+ /**
449
+ * Declare a global variable available to all rules in this file.
450
+ * Emits `global type name;` in the DRL header.
451
+ *
452
+ * @example
453
+ * .global('com.example.AlertService', 'alertService')
454
+ */
455
+ global(type, name) {
456
+ this._globals.push({ type, name });
457
+ return this;
458
+ }
447
459
  /**
448
460
  * Add a rule to the file.
449
461
  * Accepts a plain Rule object or a RuleBuilder (auto-resolved via .build()).
@@ -460,6 +472,7 @@ var DroolsFileBuilder = class {
460
472
  return {
461
473
  name: this._name,
462
474
  imports: [...this._imports],
475
+ globals: [...this._globals],
463
476
  rules: [...this._rules]
464
477
  };
465
478
  }
@@ -524,6 +537,114 @@ function rawConsequence(code) {
524
537
  return { kind: "RawConsequence", code };
525
538
  }
526
539
 
540
+ // src/rule-builder/parser/MetaToDRLTransformer.ts
541
+ function generateConstraint(c) {
542
+ switch (c.kind) {
543
+ case "FieldConstraint":
544
+ return `${c.binding ? `${c.binding} : ` : ""}${c.field} ${c.operator} ${c.value}`;
545
+ case "BindingConstraint":
546
+ return `${c.binding} : ${c.field}`;
547
+ case "RawConstraint":
548
+ return c.expression;
549
+ }
550
+ }
551
+ function generateCondition(cond, indent = " ") {
552
+ switch (cond.kind) {
553
+ case "FactPattern": {
554
+ const binding = cond.binding ? `${cond.binding} : ` : "";
555
+ const constraints = cond.constraints.map(generateConstraint).join(", ");
556
+ return `${binding}${cond.factType}( ${constraints} )`;
557
+ }
558
+ case "UnboundPattern": {
559
+ const constraints = cond.constraints.map(generateConstraint).join(", ");
560
+ return `${cond.factType}( ${constraints} )`;
561
+ }
562
+ case "And": {
563
+ const parts = cond.conditions.map((c) => generateCondition(c, indent + " "));
564
+ return `( ${parts.join(`
565
+ ${indent} and `)} )`;
566
+ }
567
+ case "Or": {
568
+ const parts = cond.conditions.map((c) => generateCondition(c, indent + " "));
569
+ return `( ${parts.join(`
570
+ ${indent} or `)} )`;
571
+ }
572
+ case "Not":
573
+ return `not( ${generateCondition(cond.condition, indent)} )`;
574
+ case "Exists":
575
+ return `exists( ${generateCondition(cond.condition, indent)} )`;
576
+ case "Forall":
577
+ return `forall( ${generateCondition(cond.condition, indent)} )`;
578
+ case "Accumulate": {
579
+ const source = generateCondition(cond.source, indent + " ");
580
+ const fns = cond.functions.map((f) => `${f.binding} : ${f.function}( ${f.argument} )`).join(", ");
581
+ const result = cond.resultConstraint ? `;
582
+ ${indent} ${cond.resultConstraint}` : "";
583
+ return `accumulate(
584
+ ${indent} ${source};
585
+ ${indent} ${fns}${result}
586
+ ${indent})`;
587
+ }
588
+ case "From":
589
+ return `${generateCondition(cond.pattern, indent)} from ${cond.expression}`;
590
+ case "Eval":
591
+ return `eval( ${cond.expression} )`;
592
+ case "RawCondition":
593
+ return cond.drl;
594
+ }
595
+ }
596
+ function generateWhenBlock(conditions, indent = " ") {
597
+ const flat = conditions.length === 1 && conditions[0].kind === "And" ? conditions[0].conditions : conditions;
598
+ return flat.map((c) => `${indent}${generateCondition(c, indent)}`).join("\n");
599
+ }
600
+ function generateConsequence(cons, indent = " ") {
601
+ switch (cons.kind) {
602
+ case "ModifyConsequence": {
603
+ const mods = cons.modifications.map((m) => `${m.method}( ${m.args.join(", ")} )`).join(`,
604
+ ${indent} `);
605
+ return `modify( ${cons.binding} ) {
606
+ ${indent} ${mods}
607
+ ${indent}}`;
608
+ }
609
+ case "InsertConsequence":
610
+ return `insert( ${cons.objectExpression} );`;
611
+ case "RetractConsequence":
612
+ return `retract( ${cons.binding} );`;
613
+ case "SetGlobalConsequence":
614
+ return `${cons.expression};`;
615
+ case "RawConsequence":
616
+ return `${cons.code};`;
617
+ }
618
+ }
619
+ function generateRule(rule) {
620
+ const lines = [`rule "${rule.name}"`];
621
+ if (rule.salience !== void 0) lines.push(` salience ${rule.salience}`);
622
+ if (rule.agendaGroup !== void 0) lines.push(` agenda-group "${rule.agendaGroup}"`);
623
+ if (rule.ruleFlowGroup !== void 0) lines.push(` ruleflow-group "${rule.ruleFlowGroup}"`);
624
+ if (rule.noLoop) lines.push(" no-loop true");
625
+ if (rule.lockOnActive) lines.push(" lock-on-active true");
626
+ lines.push(" when");
627
+ lines.push(generateWhenBlock(rule.conditions));
628
+ lines.push(" then");
629
+ lines.push(rule.consequences.map((c) => ` ${generateConsequence(c)}`).join("\n"));
630
+ lines.push("end");
631
+ return lines.join("\n");
632
+ }
633
+ var MetaToDRLTransformer = {
634
+ generate(file) {
635
+ const sections = [];
636
+ if (file.imports.length > 0)
637
+ sections.push(file.imports.map((i) => `import ${i};`).join("\n"));
638
+ if (file.globals.length > 0)
639
+ sections.push(file.globals.map((g) => `global ${g.type} ${g.name};`).join("\n"));
640
+ sections.push(file.rules.map(generateRule).join("\n\n"));
641
+ return sections.join("\n\n");
642
+ },
643
+ generateRule(rule) {
644
+ return generateRule(rule);
645
+ }
646
+ };
647
+
527
648
  // src/rule-builder/parser/DRLToMetaTransformer.ts
528
649
  function indexAtDepth0(text, needle) {
529
650
  let depth = 0;
@@ -624,6 +745,13 @@ function parseImports(drl) {
624
745
  while ((m = re.exec(drl)) !== null) imports.push(m[1].trim());
625
746
  return imports;
626
747
  }
748
+ function parseGlobals(drl) {
749
+ const globals = [];
750
+ const re = /^\s*global\s+(\S+)\s+(\S+?)\s*;?$/gm;
751
+ let m;
752
+ while ((m = re.exec(drl)) !== null) globals.push({ type: m[1], name: m[2] });
753
+ return globals;
754
+ }
627
755
  function extractRuleBlocks(drl) {
628
756
  const blocks = [];
629
757
  const re = /\brule\s+"[^"]*"[\s\S]*?\bend\b/g;
@@ -864,6 +992,7 @@ var DRLToMetaTransformer = {
864
992
  return {
865
993
  name: "parsed",
866
994
  imports: parseImports(clean),
995
+ globals: parseGlobals(clean),
867
996
  rules: extractRuleBlocks(clean).map((block) => DRLToMetaTransformer.parseRule(block))
868
997
  };
869
998
  },
@@ -876,112 +1005,6 @@ var DRLToMetaTransformer = {
876
1005
  };
877
1006
  }
878
1007
  };
879
-
880
- // src/rule-builder/parser/MetaToDRLTransformer.ts
881
- function generateConstraint(c) {
882
- switch (c.kind) {
883
- case "FieldConstraint":
884
- return `${c.binding ? `${c.binding} : ` : ""}${c.field} ${c.operator} ${c.value}`;
885
- case "BindingConstraint":
886
- return `${c.binding} : ${c.field}`;
887
- case "RawConstraint":
888
- return c.expression;
889
- }
890
- }
891
- function generateCondition(cond, indent = " ") {
892
- switch (cond.kind) {
893
- case "FactPattern": {
894
- const binding = cond.binding ? `${cond.binding} : ` : "";
895
- const constraints = cond.constraints.map(generateConstraint).join(", ");
896
- return `${binding}${cond.factType}( ${constraints} )`;
897
- }
898
- case "UnboundPattern": {
899
- const constraints = cond.constraints.map(generateConstraint).join(", ");
900
- return `${cond.factType}( ${constraints} )`;
901
- }
902
- case "And": {
903
- const parts = cond.conditions.map((c) => generateCondition(c, indent + " "));
904
- return `( ${parts.join(`
905
- ${indent} and `)} )`;
906
- }
907
- case "Or": {
908
- const parts = cond.conditions.map((c) => generateCondition(c, indent + " "));
909
- return `( ${parts.join(`
910
- ${indent} or `)} )`;
911
- }
912
- case "Not":
913
- return `not( ${generateCondition(cond.condition, indent)} )`;
914
- case "Exists":
915
- return `exists( ${generateCondition(cond.condition, indent)} )`;
916
- case "Forall":
917
- return `forall( ${generateCondition(cond.condition, indent)} )`;
918
- case "Accumulate": {
919
- const source = generateCondition(cond.source, indent + " ");
920
- const fns = cond.functions.map((f) => `${f.binding} : ${f.function}( ${f.argument} )`).join(", ");
921
- const result = cond.resultConstraint ? `;
922
- ${indent} ${cond.resultConstraint}` : "";
923
- return `accumulate(
924
- ${indent} ${source};
925
- ${indent} ${fns}${result}
926
- ${indent})`;
927
- }
928
- case "From":
929
- return `${generateCondition(cond.pattern, indent)} from ${cond.expression}`;
930
- case "Eval":
931
- return `eval( ${cond.expression} )`;
932
- case "RawCondition":
933
- return cond.drl;
934
- }
935
- }
936
- function generateWhenBlock(conditions, indent = " ") {
937
- const flat = conditions.length === 1 && conditions[0].kind === "And" ? conditions[0].conditions : conditions;
938
- return flat.map((c) => `${indent}${generateCondition(c, indent)}`).join("\n");
939
- }
940
- function generateConsequence(cons, indent = " ") {
941
- switch (cons.kind) {
942
- case "ModifyConsequence": {
943
- const mods = cons.modifications.map((m) => `${m.method}( ${m.args.join(", ")} )`).join(`,
944
- ${indent} `);
945
- return `modify( ${cons.binding} ) {
946
- ${indent} ${mods}
947
- ${indent}}`;
948
- }
949
- case "InsertConsequence":
950
- return `insert( ${cons.objectExpression} );`;
951
- case "RetractConsequence":
952
- return `retract( ${cons.binding} );`;
953
- case "SetGlobalConsequence":
954
- return `${cons.expression};`;
955
- case "RawConsequence":
956
- return `${cons.code};`;
957
- }
958
- }
959
- function generateRule(rule) {
960
- const lines = [`rule "${rule.name}"`];
961
- if (rule.salience !== void 0) lines.push(` salience ${rule.salience}`);
962
- if (rule.agendaGroup !== void 0) lines.push(` agenda-group "${rule.agendaGroup}"`);
963
- if (rule.ruleFlowGroup !== void 0) lines.push(` ruleflow-group "${rule.ruleFlowGroup}"`);
964
- if (rule.noLoop) lines.push(" no-loop true");
965
- if (rule.lockOnActive) lines.push(" lock-on-active true");
966
- lines.push(" when");
967
- lines.push(generateWhenBlock(rule.conditions));
968
- lines.push(" then");
969
- lines.push(rule.consequences.map((c) => ` ${generateConsequence(c)}`).join("\n"));
970
- lines.push("end");
971
- return lines.join("\n");
972
- }
973
- var MetaToDRLTransformer = {
974
- generate(file) {
975
- const sections = [];
976
- if (file.imports.length > 0)
977
- sections.push(file.imports.map((i) => `import ${i};`).join("\n"));
978
- sections.push(file.rules.map(generateRule).join("\n\n"));
979
- return sections.join("\n\n");
980
- },
981
- generateRule(rule) {
982
- return generateRule(rule);
983
- }
984
- };
985
1008
  // Annotate the CommonJS export names for ESM import in node:
986
1009
  0 && (module.exports = {
987
1010
  AccumulateBuilder,