drools-builder 0.1.0

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.js ADDED
@@ -0,0 +1,962 @@
1
+ // src/rule-builder/builders/enums.ts
2
+ var Operator = /* @__PURE__ */ ((Operator2) => {
3
+ Operator2["Eq"] = "==";
4
+ Operator2["Neq"] = "!=";
5
+ Operator2["Gt"] = ">";
6
+ Operator2["Lt"] = "<";
7
+ Operator2["Gte"] = ">=";
8
+ Operator2["Lte"] = "<=";
9
+ Operator2["Contains"] = "contains";
10
+ Operator2["NotContains"] = "not contains";
11
+ Operator2["MemberOf"] = "memberOf";
12
+ Operator2["NotMemberOf"] = "not memberOf";
13
+ Operator2["Matches"] = "matches";
14
+ Operator2["NotMatches"] = "not matches";
15
+ return Operator2;
16
+ })(Operator || {});
17
+ var Aggregate = /* @__PURE__ */ ((Aggregate2) => {
18
+ Aggregate2["Sum"] = "sum";
19
+ Aggregate2["Count"] = "count";
20
+ Aggregate2["Min"] = "min";
21
+ Aggregate2["Max"] = "max";
22
+ Aggregate2["Average"] = "average";
23
+ Aggregate2["CollectList"] = "collectList";
24
+ Aggregate2["CollectSet"] = "collectSet";
25
+ Aggregate2["CountDistinct"] = "countDistinct";
26
+ return Aggregate2;
27
+ })(Aggregate || {});
28
+
29
+ // src/rule-builder/builders/PatternBuilder.ts
30
+ var PatternBuilder = class {
31
+ constructor(factType, binding) {
32
+ this._constraints = [];
33
+ this._factType = factType;
34
+ this._binding = binding;
35
+ }
36
+ /**
37
+ * Add a field constraint: field operator value.
38
+ * Optionally binds the result to a variable: $v : field op value.
39
+ */
40
+ field(field, operator, value, binding) {
41
+ const constraint = binding ? { kind: "FieldConstraint", field, operator, value, binding } : { kind: "FieldConstraint", field, operator, value };
42
+ this._constraints.push(constraint);
43
+ return this;
44
+ }
45
+ /** Bind a field to a variable: $binding : field */
46
+ bind(binding, field) {
47
+ this._constraints.push({ kind: "BindingConstraint", binding, field });
48
+ return this;
49
+ }
50
+ /** Emit a verbatim DRL constraint expression. */
51
+ raw(expression) {
52
+ this._constraints.push({ kind: "RawConstraint", expression });
53
+ return this;
54
+ }
55
+ build() {
56
+ return {
57
+ kind: "FactPattern",
58
+ factType: this._factType,
59
+ ...this._binding !== void 0 ? { binding: this._binding } : {},
60
+ constraints: [...this._constraints]
61
+ };
62
+ }
63
+ };
64
+ var UnboundPatternBuilder = class {
65
+ constructor(factType) {
66
+ this._constraints = [];
67
+ this._factType = factType;
68
+ }
69
+ field(field, operator, value) {
70
+ this._constraints.push({ kind: "FieldConstraint", field, operator, value });
71
+ return this;
72
+ }
73
+ raw(expression) {
74
+ this._constraints.push({ kind: "RawConstraint", expression });
75
+ return this;
76
+ }
77
+ build() {
78
+ return {
79
+ kind: "UnboundPattern",
80
+ factType: this._factType,
81
+ constraints: [...this._constraints]
82
+ };
83
+ }
84
+ };
85
+
86
+ // src/rule-builder/builders/AccumulateBuilder.ts
87
+ var AccumulateBuilder = class {
88
+ constructor(source) {
89
+ this._functions = [];
90
+ this._source = source;
91
+ }
92
+ /**
93
+ * Register an accumulate function.
94
+ * @param binding - the variable the result is bound to, e.g. '$total'
95
+ * @param func - function name or Aggregate enum, e.g. Aggregate.Sum / 'collectList'
96
+ * @param argument - the argument expression, e.g. '$tx.amount'
97
+ */
98
+ fn(binding, func, argument) {
99
+ this._functions.push({ binding, function: func, argument });
100
+ return this;
101
+ }
102
+ /** Optional result constraint applied to the accumulated value, e.g. '$total > 50' */
103
+ resultConstraint(expression) {
104
+ this._resultConstraint = expression;
105
+ return this;
106
+ }
107
+ build() {
108
+ return {
109
+ kind: "Accumulate",
110
+ source: this._source,
111
+ functions: [...this._functions],
112
+ ...this._resultConstraint !== void 0 ? { resultConstraint: this._resultConstraint } : {}
113
+ };
114
+ }
115
+ };
116
+
117
+ // src/rule-builder/builders/ModifyBuilder.ts
118
+ var ModifyBuilder = class {
119
+ constructor(binding) {
120
+ this._modifications = [];
121
+ this._binding = binding;
122
+ }
123
+ /** Call a setter/method on the bound fact with the given arguments. */
124
+ call(method, ...args) {
125
+ this._modifications.push({ method, args });
126
+ return this;
127
+ }
128
+ build() {
129
+ return {
130
+ kind: "ModifyConsequence",
131
+ binding: this._binding,
132
+ modifications: [...this._modifications]
133
+ };
134
+ }
135
+ };
136
+
137
+ // src/rule-builder/builders/LHSBuilder.ts
138
+ var InnerPatternBuilder = class {
139
+ fact(factType, fn) {
140
+ const b = new UnboundPatternBuilder(factType);
141
+ fn?.(b);
142
+ this._inner = b.build();
143
+ return this;
144
+ }
145
+ eval(expression) {
146
+ this._inner = { kind: "Eval", expression };
147
+ return this;
148
+ }
149
+ raw(drl) {
150
+ this._inner = { kind: "RawCondition", drl };
151
+ return this;
152
+ }
153
+ /** @internal */
154
+ _build() {
155
+ if (!this._inner) throw new Error("not() / exists() block requires at least one condition");
156
+ return this._inner;
157
+ }
158
+ };
159
+ var LHSBuilder = class _LHSBuilder {
160
+ constructor() {
161
+ /** @internal collected conditions — consumed by RuleBuilder */
162
+ this._conditions = [];
163
+ }
164
+ fact(factType, bindingOrFn, fn) {
165
+ let binding;
166
+ let configureFn;
167
+ if (typeof bindingOrFn === "string") {
168
+ binding = bindingOrFn;
169
+ configureFn = fn;
170
+ } else {
171
+ configureFn = bindingOrFn;
172
+ }
173
+ const builder = new PatternBuilder(factType, binding);
174
+ configureFn?.(builder);
175
+ this._conditions.push(builder.build());
176
+ return this;
177
+ }
178
+ // ── Logical wrappers ───────────────────────────────────────────────────────
179
+ /** Add a not() wrapper. Inner condition must be unbound (no variable binding). */
180
+ not(fn) {
181
+ const b = new InnerPatternBuilder();
182
+ fn(b);
183
+ this._conditions.push({ kind: "Not", condition: b._build() });
184
+ return this;
185
+ }
186
+ /** Add an exists() wrapper. Inner condition must be unbound. */
187
+ exists(fn) {
188
+ const b = new InnerPatternBuilder();
189
+ fn(b);
190
+ this._conditions.push({ kind: "Exists", condition: b._build() });
191
+ return this;
192
+ }
193
+ /** Add an or() group. Each child is added via the nested LHSBuilder. */
194
+ or(fn) {
195
+ const inner = new _LHSBuilder();
196
+ fn(inner);
197
+ this._conditions.push({ kind: "Or", conditions: inner._conditions });
198
+ return this;
199
+ }
200
+ /** Add an and() group. Useful when composing nested boolean logic. */
201
+ and(fn) {
202
+ const inner = new _LHSBuilder();
203
+ fn(inner);
204
+ this._conditions.push({ kind: "And", conditions: inner._conditions });
205
+ return this;
206
+ }
207
+ /** Add a forall() wrapper. */
208
+ forall(fn) {
209
+ const inner = new _LHSBuilder();
210
+ fn(inner);
211
+ const condition = inner._conditions.length === 1 ? inner._conditions[0] : { kind: "And", conditions: inner._conditions };
212
+ this._conditions.push({ kind: "Forall", condition });
213
+ return this;
214
+ }
215
+ // ── Accumulate ─────────────────────────────────────────────────────────────
216
+ /**
217
+ * Add an accumulate pattern.
218
+ * @param sourceFn - builds the source condition (the pattern being accumulated)
219
+ * @param fn - configures the accumulate functions and result constraint
220
+ */
221
+ accumulate(sourceFn, fn) {
222
+ const sourceLhs = new _LHSBuilder();
223
+ sourceFn(sourceLhs);
224
+ const source = sourceLhs._conditions.length === 1 ? sourceLhs._conditions[0] : { kind: "And", conditions: sourceLhs._conditions };
225
+ const acc = new AccumulateBuilder(source);
226
+ fn(acc);
227
+ this._conditions.push(acc.build());
228
+ return this;
229
+ }
230
+ // ── From ───────────────────────────────────────────────────────────────────
231
+ /**
232
+ * Add a from condition: FactType( constraints ) from expression
233
+ * @param factType - the type to match
234
+ * @param binding - variable binding for the matched fact
235
+ * @param expression - the source expression (collection, method call, etc.)
236
+ * @param fn - optional constraint configuration
237
+ */
238
+ from(factType, binding, expression, fn) {
239
+ const builder = new PatternBuilder(factType, binding);
240
+ fn?.(builder);
241
+ this._conditions.push({ kind: "From", pattern: builder.build(), expression });
242
+ return this;
243
+ }
244
+ // ── Primitives ─────────────────────────────────────────────────────────────
245
+ /** Add an eval() condition with a raw boolean expression. */
246
+ eval(expression) {
247
+ this._conditions.push({ kind: "Eval", expression });
248
+ return this;
249
+ }
250
+ /** Add a verbatim DRL condition, emitted as-is. */
251
+ raw(drl) {
252
+ this._conditions.push({ kind: "RawCondition", drl });
253
+ return this;
254
+ }
255
+ };
256
+
257
+ // src/rule-builder/builders/RHSBuilder.ts
258
+ var RHSBuilder = class {
259
+ constructor() {
260
+ /** @internal collected consequences — consumed by RuleBuilder */
261
+ this._consequences = [];
262
+ }
263
+ /** modify($binding) { ... } — calls setters on an existing fact. */
264
+ modify(binding, fn) {
265
+ const builder = new ModifyBuilder(binding);
266
+ fn(builder);
267
+ this._consequences.push(builder.build());
268
+ return this;
269
+ }
270
+ /** insert(objectExpression) — inserts a new fact into working memory. */
271
+ insert(objectExpression) {
272
+ this._consequences.push({ kind: "InsertConsequence", objectExpression });
273
+ return this;
274
+ }
275
+ /** retract($binding) — removes a fact from working memory. */
276
+ retract(binding) {
277
+ this._consequences.push({ kind: "RetractConsequence", binding });
278
+ return this;
279
+ }
280
+ /** Assign a value to a global variable. */
281
+ global(expression) {
282
+ this._consequences.push({ kind: "SetGlobalConsequence", expression });
283
+ return this;
284
+ }
285
+ /** Emit a verbatim DRL statement, emitted as-is. */
286
+ raw(code) {
287
+ this._consequences.push({ kind: "RawConsequence", code });
288
+ return this;
289
+ }
290
+ };
291
+
292
+ // src/rule-builder/builders/RuleBuilder.ts
293
+ function resolveCondition(input) {
294
+ return typeof input.build === "function" ? input.build() : input;
295
+ }
296
+ function resolveConsequence(input) {
297
+ return typeof input.build === "function" ? input.build() : input;
298
+ }
299
+ var RuleBuilder = class {
300
+ constructor(name) {
301
+ this._rule = { name, conditions: [], consequences: [] };
302
+ }
303
+ // ── Rule attributes ────────────────────────────────────────────────────────
304
+ salience(value) {
305
+ this._rule.salience = value;
306
+ return this;
307
+ }
308
+ agendaGroup(value) {
309
+ this._rule.agendaGroup = value;
310
+ return this;
311
+ }
312
+ /** Defaults to true when called without an argument. */
313
+ noLoop(value = true) {
314
+ this._rule.noLoop = value;
315
+ return this;
316
+ }
317
+ /** Defaults to true when called without an argument. */
318
+ lockOnActive(value = true) {
319
+ this._rule.lockOnActive = value;
320
+ return this;
321
+ }
322
+ ruleFlowGroup(value) {
323
+ this._rule.ruleFlowGroup = value;
324
+ return this;
325
+ }
326
+ // ── Step-by-step style ─────────────────────────────────────────────────────
327
+ /**
328
+ * Append a single condition.
329
+ * Accepts a plain Condition object or any builder that exposes build().
330
+ */
331
+ addCondition(condition) {
332
+ this._rule.conditions.push(resolveCondition(condition));
333
+ return this;
334
+ }
335
+ /**
336
+ * Append a single consequence.
337
+ * Accepts a plain Consequence object or any builder that exposes build().
338
+ */
339
+ addConsequence(consequence) {
340
+ this._rule.consequences.push(resolveConsequence(consequence));
341
+ return this;
342
+ }
343
+ // ── Callback block style ───────────────────────────────────────────────────
344
+ /** Configure the when-block using an LHSBuilder. Appends to existing conditions. */
345
+ when(fn) {
346
+ const lhs = new LHSBuilder();
347
+ fn(lhs);
348
+ this._rule.conditions.push(...lhs._conditions);
349
+ return this;
350
+ }
351
+ /** Configure the then-block using an RHSBuilder. Appends to existing consequences. */
352
+ then(fn) {
353
+ const rhs = new RHSBuilder();
354
+ fn(rhs);
355
+ this._rule.consequences.push(...rhs._consequences);
356
+ return this;
357
+ }
358
+ // ── Terminal ───────────────────────────────────────────────────────────────
359
+ build() {
360
+ return {
361
+ ...this._rule,
362
+ conditions: [...this._rule.conditions],
363
+ consequences: [...this._rule.consequences]
364
+ };
365
+ }
366
+ };
367
+ function createRule(name) {
368
+ return new RuleBuilder(name);
369
+ }
370
+
371
+ // src/rule-builder/builders/DroolsFileBuilder.ts
372
+ function resolveRule(input) {
373
+ return typeof input.build === "function" ? input.build() : input;
374
+ }
375
+ var DroolsFileBuilder = class {
376
+ constructor(name) {
377
+ this._imports = [];
378
+ this._rules = [];
379
+ this._name = name;
380
+ }
381
+ /**
382
+ * Add a fully-qualified Java class import.
383
+ * Can be called multiple times — order is preserved.
384
+ *
385
+ * @example
386
+ * .import('com.example.model.Player')
387
+ */
388
+ import(className) {
389
+ this._imports.push(className);
390
+ return this;
391
+ }
392
+ /**
393
+ * Add a rule to the file.
394
+ * Accepts a plain Rule object or a RuleBuilder (auto-resolved via .build()).
395
+ *
396
+ * @example
397
+ * .addRule(createRule('My Rule').when(...).then(...))
398
+ * .addRule({ name: 'My Rule', conditions: [], consequences: [] })
399
+ */
400
+ addRule(rule) {
401
+ this._rules.push(resolveRule(rule));
402
+ return this;
403
+ }
404
+ build() {
405
+ return {
406
+ name: this._name,
407
+ imports: [...this._imports],
408
+ rules: [...this._rules]
409
+ };
410
+ }
411
+ };
412
+ function createFile(name) {
413
+ return new DroolsFileBuilder(name);
414
+ }
415
+
416
+ // src/rule-builder/builders/index.ts
417
+ function resolveCondition2(input) {
418
+ return typeof input.build === "function" ? input.build() : input;
419
+ }
420
+ function resolveNotExists(input) {
421
+ return typeof input.build === "function" ? input.build() : input;
422
+ }
423
+ function fact(factType, binding) {
424
+ return new PatternBuilder(factType, binding);
425
+ }
426
+ function unbound(factType) {
427
+ return new UnboundPatternBuilder(factType);
428
+ }
429
+ function not(condition) {
430
+ return { kind: "Not", condition: resolveNotExists(condition) };
431
+ }
432
+ function exists(condition) {
433
+ return { kind: "Exists", condition: resolveNotExists(condition) };
434
+ }
435
+ function or(...conditions) {
436
+ return { kind: "Or", conditions: conditions.map(resolveCondition2) };
437
+ }
438
+ function and(...conditions) {
439
+ return { kind: "And", conditions: conditions.map(resolveCondition2) };
440
+ }
441
+ function forall(condition) {
442
+ return { kind: "Forall", condition: resolveCondition2(condition) };
443
+ }
444
+ function accumulate(source) {
445
+ return new AccumulateBuilder(resolveCondition2(source));
446
+ }
447
+ function from_(pattern, expression) {
448
+ return { kind: "From", pattern: pattern.build(), expression };
449
+ }
450
+ function eval_(expression) {
451
+ return { kind: "Eval", expression };
452
+ }
453
+ function rawCondition(drl) {
454
+ return { kind: "RawCondition", drl };
455
+ }
456
+ function modify(binding) {
457
+ return new ModifyBuilder(binding);
458
+ }
459
+ function insert(objectExpression) {
460
+ return { kind: "InsertConsequence", objectExpression };
461
+ }
462
+ function retract(binding) {
463
+ return { kind: "RetractConsequence", binding };
464
+ }
465
+ function setGlobal(expression) {
466
+ return { kind: "SetGlobalConsequence", expression };
467
+ }
468
+ function rawConsequence(code) {
469
+ return { kind: "RawConsequence", code };
470
+ }
471
+
472
+ // src/rule-builder/parser/DRLToMetaTransformer.ts
473
+ function indexAtDepth0(text, needle) {
474
+ let depth = 0;
475
+ let inString = false;
476
+ let quote = "";
477
+ for (let i = 0; i < text.length; i++) {
478
+ const ch = text[i];
479
+ if (inString) {
480
+ if (ch === "\\") {
481
+ i++;
482
+ continue;
483
+ }
484
+ if (ch === quote) inString = false;
485
+ continue;
486
+ }
487
+ if (ch === '"' || ch === "'") {
488
+ inString = true;
489
+ quote = ch;
490
+ continue;
491
+ }
492
+ if (ch === "(" || ch === "{" || ch === "[") {
493
+ depth++;
494
+ continue;
495
+ }
496
+ if (ch === ")" || ch === "}" || ch === "]") {
497
+ depth--;
498
+ continue;
499
+ }
500
+ if (depth === 0 && text.startsWith(needle, i)) return i;
501
+ }
502
+ return -1;
503
+ }
504
+ function splitAtDepth0(text, separator) {
505
+ const parts = [];
506
+ const sepLen = separator.length;
507
+ let depth = 0;
508
+ let inString = false;
509
+ let quote = "";
510
+ let current = "";
511
+ for (let i = 0; i < text.length; i++) {
512
+ const ch = text[i];
513
+ if (inString) {
514
+ if (ch === "\\") {
515
+ current += ch + text[++i];
516
+ continue;
517
+ }
518
+ if (ch === quote) inString = false;
519
+ current += ch;
520
+ continue;
521
+ }
522
+ if (ch === '"' || ch === "'") {
523
+ inString = true;
524
+ quote = ch;
525
+ current += ch;
526
+ continue;
527
+ }
528
+ if (ch === "(" || ch === "{" || ch === "[") {
529
+ depth++;
530
+ current += ch;
531
+ continue;
532
+ }
533
+ if (ch === ")" || ch === "}" || ch === "]") {
534
+ depth--;
535
+ current += ch;
536
+ continue;
537
+ }
538
+ if (depth === 0 && text.startsWith(separator, i)) {
539
+ parts.push(current.trim());
540
+ current = "";
541
+ i += sepLen - 1;
542
+ continue;
543
+ }
544
+ current += ch;
545
+ }
546
+ if (current.trim()) parts.push(current.trim());
547
+ return parts.filter((p) => p.length > 0);
548
+ }
549
+ function extractBalanced(text, open, close) {
550
+ const start = text.indexOf(open);
551
+ if (start === -1) return "";
552
+ let depth = 0;
553
+ for (let i = start; i < text.length; i++) {
554
+ if (text[i] === open) depth++;
555
+ else if (text[i] === close) {
556
+ depth--;
557
+ if (depth === 0) return text.slice(start + 1, i);
558
+ }
559
+ }
560
+ return text.slice(start + 1);
561
+ }
562
+ function stripComments(drl) {
563
+ return drl.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
564
+ }
565
+ function parseImports(drl) {
566
+ const imports = [];
567
+ const re = /^\s*import\s+([^\s;]+)\s*;?/gm;
568
+ let m;
569
+ while ((m = re.exec(drl)) !== null) imports.push(m[1].trim());
570
+ return imports;
571
+ }
572
+ function extractRuleBlocks(drl) {
573
+ const blocks = [];
574
+ const re = /\brule\s+"[^"]*"[\s\S]*?\bend\b/g;
575
+ let m;
576
+ while ((m = re.exec(drl)) !== null) blocks.push(m[0]);
577
+ return blocks;
578
+ }
579
+ function parseRuleName(block) {
580
+ const m = block.match(/\brule\s+"([^"]+)"/);
581
+ return m ? m[1] : "unknown";
582
+ }
583
+ function parseRuleAttributes(block) {
584
+ const attrs = {};
585
+ const m = block.match(/\brule\s+"[^"]+"\s*([\s\S]*?)\bwhen\b/);
586
+ if (!m) return attrs;
587
+ const attr = m[1];
588
+ const salience = attr.match(/\bsalience\s+(-?\d+)/);
589
+ if (salience) attrs.salience = parseInt(salience[1], 10);
590
+ if (/\bno-loop\s+true\b/.test(attr)) attrs.noLoop = true;
591
+ if (/\block-on-active\s+true\b/.test(attr)) attrs.lockOnActive = true;
592
+ const ag = attr.match(/\bagenda-group\s+"([^"]+)"/);
593
+ if (ag) attrs.agendaGroup = ag[1];
594
+ const rfg = attr.match(/\bruleflow-group\s+"([^"]+)"/);
595
+ if (rfg) attrs.ruleFlowGroup = rfg[1];
596
+ return attrs;
597
+ }
598
+ function extractWhenBlock(block) {
599
+ const m = block.match(/\bwhen\b([\s\S]*?)\bthen\b/);
600
+ return m ? m[1].trim() : "";
601
+ }
602
+ function extractThenBlock(block) {
603
+ const m = block.match(/\bthen\b([\s\S]*?)\bend\b/);
604
+ return m ? m[1].trim() : "";
605
+ }
606
+ function parseConditions(when) {
607
+ const text = when.trim();
608
+ if (!text) return [];
609
+ const orParts = splitAtDepth0(text, " or ");
610
+ if (orParts.length > 1) {
611
+ return [{ kind: "Or", conditions: orParts.map((p) => parseAndGroup(p.trim())) }];
612
+ }
613
+ const result = parseAndGroup(text);
614
+ return result.kind === "And" ? result.conditions : [result];
615
+ }
616
+ function parseAndGroup(text) {
617
+ const andParts = splitAndConditions(text);
618
+ if (andParts.length === 1) return parseCondition(andParts[0]);
619
+ const conditions = andParts.map(parseCondition);
620
+ return conditions.length === 1 ? conditions[0] : { kind: "And", conditions };
621
+ }
622
+ function splitAndConditions(text) {
623
+ const byAnd = splitAtDepth0(text, " and ");
624
+ if (byAnd.length > 1) return byAnd.filter((p) => p.trim().length > 0);
625
+ const lines = text.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
626
+ if (lines.length <= 1) return [text.trim()];
627
+ const merged = [];
628
+ let current = "";
629
+ let depth = 0;
630
+ for (const line of lines) {
631
+ for (const ch of line) {
632
+ if (ch === "(" || ch === "{") depth++;
633
+ else if (ch === ")" || ch === "}") depth--;
634
+ }
635
+ current += (current ? " " : "") + line;
636
+ if (depth === 0) {
637
+ merged.push(current.trim());
638
+ current = "";
639
+ }
640
+ }
641
+ if (current.trim()) merged.push(current.trim());
642
+ return merged.filter((p) => p.length > 0);
643
+ }
644
+ function parseCondition(raw) {
645
+ const text = raw.trim();
646
+ if (text.startsWith("(") && text.endsWith(")")) {
647
+ const inner = text.slice(1, -1).trim();
648
+ const conditions = parseConditions(inner);
649
+ return conditions.length === 1 ? conditions[0] : { kind: "And", conditions };
650
+ }
651
+ if (/^not\s*\(/.test(text))
652
+ return { kind: "Not", condition: parseUnboundCondition(extractBalanced(text, "(", ")")) };
653
+ if (/^not\s+\w/.test(text))
654
+ return { kind: "Not", condition: parseUnboundCondition(text.replace(/^not\s+/, "").trim()) };
655
+ if (/^exists\s*\(/.test(text))
656
+ return { kind: "Exists", condition: parseUnboundCondition(extractBalanced(text, "(", ")")) };
657
+ if (/^forall\s*\(/.test(text))
658
+ return { kind: "Forall", condition: parseCondition(extractBalanced(text, "(", ")")) };
659
+ if (/^accumulate\s*\(/.test(text))
660
+ return parseAccumulate(text);
661
+ if (/^eval\s*\(/.test(text))
662
+ return { kind: "Eval", expression: extractBalanced(text, "(", ")").trim() };
663
+ const fromIdx = indexAtDepth0(text, " from ");
664
+ if (fromIdx !== -1)
665
+ return parseFrom(text, fromIdx);
666
+ if (/^(\$\w+\s*:\s*)?\w[\w.]*\s*\(/.test(text))
667
+ return parseFactPattern(text);
668
+ return { kind: "RawCondition", drl: text };
669
+ }
670
+ function parseFactPattern(text) {
671
+ const m = text.match(/^(\$\w+\s*:\s*)?(\w[\w.]*)\s*\(([\s\S]*)\)\s*$/);
672
+ if (!m) return { kind: "FactPattern", factType: text, constraints: [] };
673
+ const binding = m[1] ? m[1].replace(":", "").trim() : void 0;
674
+ const constraints = m[3].trim() ? parseConstraints(m[3].trim()) : [];
675
+ return { kind: "FactPattern", factType: m[2].trim(), binding, constraints };
676
+ }
677
+ function parseUnboundCondition(text) {
678
+ const trimmed = text.trim();
679
+ if (/^eval\s*\(/.test(trimmed))
680
+ return { kind: "Eval", expression: extractBalanced(trimmed, "(", ")").trim() };
681
+ const m = trimmed.match(/^(?:\$\w+\s*:\s*)?(\w[\w.]*)\s*\(([\s\S]*)\)\s*$/);
682
+ if (m) {
683
+ const constraints = m[2].trim() ? parseConstraints(m[2].trim()) : [];
684
+ return { kind: "UnboundPattern", factType: m[1].trim(), constraints };
685
+ }
686
+ return { kind: "RawCondition", drl: trimmed };
687
+ }
688
+ function parseConstraints(text) {
689
+ return splitAtDepth0(text, ",").map((s) => s.trim()).filter(Boolean).map(parseConstraint);
690
+ }
691
+ function parseConstraint(text) {
692
+ const s = text.trim();
693
+ const bindingOnly = s.match(/^(\$\w+)\s*:\s*(\w[\w.]*)$/);
694
+ if (bindingOnly)
695
+ return { kind: "BindingConstraint", binding: bindingOnly[1], field: bindingOnly[2] };
696
+ const OPERATORS = [
697
+ "not contains",
698
+ "not memberOf",
699
+ "not matches",
700
+ "contains",
701
+ "memberOf",
702
+ "matches",
703
+ "==",
704
+ "!=",
705
+ ">=",
706
+ "<=",
707
+ ">",
708
+ "<"
709
+ ];
710
+ for (const op of OPERATORS) {
711
+ const idx = indexAtDepth0(s, op);
712
+ if (idx === -1) continue;
713
+ const lhs = s.slice(0, idx).trim();
714
+ const rhs = s.slice(idx + op.length).trim();
715
+ const lhsMatch = lhs.match(/^(\$\w+)\s*:\s*(\w[\w.]*)$/);
716
+ return {
717
+ kind: "FieldConstraint",
718
+ field: lhsMatch ? lhsMatch[2] : lhs,
719
+ operator: op,
720
+ value: rhs,
721
+ ...lhsMatch && { binding: lhsMatch[1] }
722
+ };
723
+ }
724
+ return { kind: "RawConstraint", expression: s };
725
+ }
726
+ function parseAccumulate(text) {
727
+ const inner = extractBalanced(text, "(", ")").trim();
728
+ const parts = splitAtDepth0(inner, ";");
729
+ const source = parts[0] ? parseCondition(parts[0].trim()) : { kind: "RawCondition", drl: "" };
730
+ const functions = [];
731
+ let resultConstraint;
732
+ for (let i = 1; i < parts.length; i++) {
733
+ const part = parts[i].trim();
734
+ const candidates = splitAtDepth0(part, ",");
735
+ const parsed = [];
736
+ let allFunctions = true;
737
+ for (const candidate of candidates) {
738
+ const fn = candidate.trim().match(/^(\$\w+)\s*:\s*(\w+)\s*\(([^)]*)\)$/);
739
+ if (fn) parsed.push({ binding: fn[1], function: fn[2], argument: fn[3].trim() });
740
+ else {
741
+ allFunctions = false;
742
+ break;
743
+ }
744
+ }
745
+ if (allFunctions && parsed.length > 0) functions.push(...parsed);
746
+ else resultConstraint = part;
747
+ }
748
+ return { kind: "Accumulate", source, functions, ...resultConstraint && { resultConstraint } };
749
+ }
750
+ function parseFrom(text, fromIdx) {
751
+ return {
752
+ kind: "From",
753
+ pattern: parseFactPattern(text.slice(0, fromIdx).trim()),
754
+ expression: text.slice(fromIdx + " from ".length).trim()
755
+ };
756
+ }
757
+ function parseConsequences(then) {
758
+ const consequences = [];
759
+ let remaining = then.trim();
760
+ while (remaining.length > 0) {
761
+ const result = parseNextConsequence(remaining);
762
+ if (!result) break;
763
+ consequences.push(result.consequence);
764
+ remaining = result.rest.trim();
765
+ }
766
+ return consequences;
767
+ }
768
+ function parseNextConsequence(text) {
769
+ const t = text.trim();
770
+ if (!t) return null;
771
+ if (/^modify\s*\(/.test(t)) {
772
+ const m = t.match(/^modify\s*\(\s*(\$\w+)\s*\)/);
773
+ if (m) {
774
+ const afterBinding = t.slice(m[0].length).trim();
775
+ const block = extractBalanced(afterBinding, "{", "}");
776
+ const endIdx = afterBinding.indexOf("{") + block.length + 2;
777
+ return {
778
+ consequence: { kind: "ModifyConsequence", binding: m[1], modifications: parseModifications(block) },
779
+ rest: afterBinding.slice(endIdx)
780
+ };
781
+ }
782
+ }
783
+ if (/^insert\s*\(/.test(t)) {
784
+ const inner = extractBalanced(t, "(", ")");
785
+ const rest = t.slice(t.indexOf("(") + inner.length + 2).replace(/^\s*;/, "");
786
+ return { consequence: { kind: "InsertConsequence", objectExpression: inner.trim() }, rest };
787
+ }
788
+ if (/^retract\s*\(/.test(t)) {
789
+ const inner = extractBalanced(t, "(", ")");
790
+ const rest = t.slice(t.indexOf("(") + inner.length + 2).replace(/^\s*;/, "");
791
+ return { consequence: { kind: "RetractConsequence", binding: inner.trim() }, rest };
792
+ }
793
+ const semiIdx = indexAtDepth0(t, ";");
794
+ if (semiIdx !== -1)
795
+ return { consequence: { kind: "RawConsequence", code: t.slice(0, semiIdx).trim() }, rest: t.slice(semiIdx + 1) };
796
+ return { consequence: { kind: "RawConsequence", code: t }, rest: "" };
797
+ }
798
+ function parseModifications(block) {
799
+ return splitAtDepth0(block, ",").map((s) => s.trim()).filter(Boolean).map((text) => {
800
+ const m = text.match(/^(\w+)\s*\(([\s\S]*)\)$/);
801
+ if (!m) return { method: text, args: [] };
802
+ const args = m[2].trim() ? splitAtDepth0(m[2].trim(), ",").map((a) => a.trim()) : [];
803
+ return { method: m[1], args };
804
+ });
805
+ }
806
+ var DRLToMetaTransformer = {
807
+ parse(drl) {
808
+ const clean = stripComments(drl);
809
+ return {
810
+ name: "parsed",
811
+ imports: parseImports(clean),
812
+ rules: extractRuleBlocks(clean).map((block) => DRLToMetaTransformer.parseRule(block))
813
+ };
814
+ },
815
+ parseRule(block) {
816
+ return {
817
+ name: parseRuleName(block),
818
+ ...parseRuleAttributes(block),
819
+ conditions: parseConditions(extractWhenBlock(block)),
820
+ consequences: parseConsequences(extractThenBlock(block))
821
+ };
822
+ }
823
+ };
824
+
825
+ // src/rule-builder/parser/MetaToDRLTransformer.ts
826
+ function generateConstraint(c) {
827
+ switch (c.kind) {
828
+ case "FieldConstraint":
829
+ return `${c.binding ? `${c.binding} : ` : ""}${c.field} ${c.operator} ${c.value}`;
830
+ case "BindingConstraint":
831
+ return `${c.binding} : ${c.field}`;
832
+ case "RawConstraint":
833
+ return c.expression;
834
+ }
835
+ }
836
+ function generateCondition(cond, indent = " ") {
837
+ switch (cond.kind) {
838
+ case "FactPattern": {
839
+ const binding = cond.binding ? `${cond.binding} : ` : "";
840
+ const constraints = cond.constraints.map(generateConstraint).join(", ");
841
+ return `${binding}${cond.factType}( ${constraints} )`;
842
+ }
843
+ case "UnboundPattern": {
844
+ const constraints = cond.constraints.map(generateConstraint).join(", ");
845
+ return `${cond.factType}( ${constraints} )`;
846
+ }
847
+ case "And": {
848
+ const parts = cond.conditions.map((c) => generateCondition(c, indent + " "));
849
+ return `( ${parts.join(`
850
+ ${indent} and `)} )`;
851
+ }
852
+ case "Or": {
853
+ const parts = cond.conditions.map((c) => generateCondition(c, indent + " "));
854
+ return `( ${parts.join(`
855
+ ${indent} or `)} )`;
856
+ }
857
+ case "Not":
858
+ return `not( ${generateCondition(cond.condition, indent)} )`;
859
+ case "Exists":
860
+ return `exists( ${generateCondition(cond.condition, indent)} )`;
861
+ case "Forall":
862
+ return `forall( ${generateCondition(cond.condition, indent)} )`;
863
+ case "Accumulate": {
864
+ const source = generateCondition(cond.source, indent + " ");
865
+ const fns = cond.functions.map((f) => `${f.binding} : ${f.function}( ${f.argument} )`).join(", ");
866
+ const result = cond.resultConstraint ? `;
867
+ ${indent} ${cond.resultConstraint}` : "";
868
+ return `accumulate(
869
+ ${indent} ${source};
870
+ ${indent} ${fns}${result}
871
+ ${indent})`;
872
+ }
873
+ case "From":
874
+ return `${generateCondition(cond.pattern, indent)} from ${cond.expression}`;
875
+ case "Eval":
876
+ return `eval( ${cond.expression} )`;
877
+ case "RawCondition":
878
+ return cond.drl;
879
+ }
880
+ }
881
+ function generateWhenBlock(conditions, indent = " ") {
882
+ const flat = conditions.length === 1 && conditions[0].kind === "And" ? conditions[0].conditions : conditions;
883
+ return flat.map((c) => `${indent}${generateCondition(c, indent)}`).join("\n");
884
+ }
885
+ function generateConsequence(cons, indent = " ") {
886
+ switch (cons.kind) {
887
+ case "ModifyConsequence": {
888
+ const mods = cons.modifications.map((m) => `${m.method}( ${m.args.join(", ")} )`).join(`,
889
+ ${indent} `);
890
+ return `modify( ${cons.binding} ) {
891
+ ${indent} ${mods}
892
+ ${indent}}`;
893
+ }
894
+ case "InsertConsequence":
895
+ return `insert( ${cons.objectExpression} );`;
896
+ case "RetractConsequence":
897
+ return `retract( ${cons.binding} );`;
898
+ case "SetGlobalConsequence":
899
+ return `${cons.expression};`;
900
+ case "RawConsequence":
901
+ return `${cons.code};`;
902
+ }
903
+ }
904
+ function generateRule(rule) {
905
+ const lines = [`rule "${rule.name}"`];
906
+ if (rule.salience !== void 0) lines.push(` salience ${rule.salience}`);
907
+ if (rule.agendaGroup !== void 0) lines.push(` agenda-group "${rule.agendaGroup}"`);
908
+ if (rule.ruleFlowGroup !== void 0) lines.push(` ruleflow-group "${rule.ruleFlowGroup}"`);
909
+ if (rule.noLoop) lines.push(" no-loop true");
910
+ if (rule.lockOnActive) lines.push(" lock-on-active true");
911
+ lines.push(" when");
912
+ lines.push(generateWhenBlock(rule.conditions));
913
+ lines.push(" then");
914
+ lines.push(rule.consequences.map((c) => ` ${generateConsequence(c)}`).join("\n"));
915
+ lines.push("end");
916
+ return lines.join("\n");
917
+ }
918
+ var MetaToDRLTransformer = {
919
+ generate(file) {
920
+ const sections = [];
921
+ if (file.imports.length > 0)
922
+ sections.push(file.imports.map((i) => `import ${i};`).join("\n"));
923
+ sections.push(file.rules.map(generateRule).join("\n\n"));
924
+ return sections.join("\n\n");
925
+ },
926
+ generateRule(rule) {
927
+ return generateRule(rule);
928
+ }
929
+ };
930
+ export {
931
+ AccumulateBuilder,
932
+ Aggregate,
933
+ DRLToMetaTransformer,
934
+ DroolsFileBuilder,
935
+ LHSBuilder,
936
+ MetaToDRLTransformer,
937
+ ModifyBuilder,
938
+ Operator,
939
+ PatternBuilder,
940
+ RHSBuilder,
941
+ RuleBuilder,
942
+ UnboundPatternBuilder,
943
+ accumulate,
944
+ and,
945
+ createFile,
946
+ createRule,
947
+ eval_,
948
+ exists,
949
+ fact,
950
+ forall,
951
+ from_,
952
+ insert,
953
+ modify,
954
+ not,
955
+ or,
956
+ rawCondition,
957
+ rawConsequence,
958
+ retract,
959
+ setGlobal,
960
+ unbound
961
+ };
962
+ //# sourceMappingURL=index.js.map