@magda/typescript-common 1.2.0-rc.0 → 2.0.0-alpha.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/OpaCompileResponseParser.d.ts +147 -34
- package/dist/OpaCompileResponseParser.js +479 -293
- package/dist/OpaCompileResponseParser.js.map +1 -1
- package/dist/SQLUtils.d.ts +70 -0
- package/dist/SQLUtils.js +263 -0
- package/dist/SQLUtils.js.map +1 -0
- package/dist/ServerError.d.ts +9 -0
- package/dist/ServerError.js +17 -0
- package/dist/ServerError.js.map +1 -0
- package/dist/authorization-api/authMiddleware.d.ts +59 -1
- package/dist/authorization-api/authMiddleware.js +146 -3
- package/dist/authorization-api/authMiddleware.js.map +1 -1
- package/dist/authorization-api/constants.d.ts +5 -0
- package/dist/authorization-api/constants.js +13 -0
- package/dist/authorization-api/constants.js.map +1 -0
- package/dist/authorization-api/model.d.ts +1 -6
- package/dist/express/getNoCacheHeaders.d.ts +6 -0
- package/dist/express/getNoCacheHeaders.js +9 -0
- package/dist/express/getNoCacheHeaders.js.map +1 -0
- package/dist/express/setResponseNoCache.d.ts +3 -0
- package/dist/express/setResponseNoCache.js +9 -0
- package/dist/express/setResponseNoCache.js.map +1 -0
- package/dist/generated/registry/api.d.ts +36 -2
- package/dist/generated/registry/api.js +140 -2
- package/dist/generated/registry/api.js.map +1 -1
- package/dist/getAbsoluteUrl.d.ts +3 -2
- package/dist/getAbsoluteUrl.js +2 -1
- package/dist/getAbsoluteUrl.js.map +1 -1
- package/dist/opa/AspectQuery.d.ts +71 -0
- package/dist/opa/AspectQuery.js +216 -0
- package/dist/opa/AspectQuery.js.map +1 -0
- package/dist/opa/AuthDecision.d.ts +51 -0
- package/dist/opa/AuthDecision.js +241 -0
- package/dist/opa/AuthDecision.js.map +1 -0
- package/dist/opa/AuthDecisionQueryClient.d.ts +23 -0
- package/dist/opa/AuthDecisionQueryClient.js +110 -0
- package/dist/opa/AuthDecisionQueryClient.js.map +1 -0
- package/dist/pgTypes.d.ts +1 -0
- package/dist/pgTypes.js +18 -0
- package/dist/pgTypes.js.map +1 -0
- package/dist/registry/AuthorizedRegistryClient.d.ts +1 -0
- package/dist/registry/AuthorizedRegistryClient.js +17 -0
- package/dist/registry/AuthorizedRegistryClient.js.map +1 -1
- package/dist/registry/RegistryClient.d.ts +10 -0
- package/dist/registry/RegistryClient.js +32 -0
- package/dist/registry/RegistryClient.js.map +1 -1
- package/dist/test/getAuthDecision.spec.js +2 -2
- package/dist/test/getAuthDecision.spec.js.map +1 -1
- package/dist/test/sampleAuthDecisions/content.json +29 -0
- package/dist/test/sampleAuthDecisions/datasetPermissionWithOrgUnitConstraint.json +79 -0
- package/dist/test/sampleAuthDecisions/simple.json +29 -0
- package/dist/test/sampleAuthDecisions/singleTermAspectRef.json +39 -0
- package/dist/test/sampleAuthDecisions/unconditionalFalseSimple.json +6 -0
- package/dist/test/sampleAuthDecisions/unconditionalNotMacthed.json +6 -0
- package/dist/test/sampleAuthDecisions/unconditionalNotMacthedWithExtraRefs.json +6 -0
- package/dist/test/sampleAuthDecisions/unconditionalTrue.json +6 -0
- package/dist/test/sampleAuthDecisions/unconditionalTrueSimple.json +6 -0
- package/dist/test/sampleAuthDecisions/unconditionalTrueWithDefaultRule.json +6 -0
- package/dist/test/sampleAuthDecisions/withDefaultRule.json +6 -0
- package/dist/test/{sampleOpaResponse.json → sampleOpaResponses/content.json} +0 -0
- package/dist/test/sampleOpaResponses/datasetPermissionWithOrgUnitConstraint.json +341 -0
- package/dist/test/{sampleOpaResponseSimple.json → sampleOpaResponses/simple.json} +0 -0
- package/dist/test/sampleOpaResponses/singleTermAspectRef.json +233 -0
- package/dist/test/sampleOpaResponses/unconditionalFalseSimple.json +3 -0
- package/dist/test/sampleOpaResponses/unconditionalNotMacthed.json +73 -0
- package/dist/test/sampleOpaResponses/unconditionalNotMacthedWithExtraRefs.json +155 -0
- package/dist/test/{sampleOpaResponseUnconditionalTrue.json → sampleOpaResponses/unconditionalTrue.json} +0 -0
- package/dist/test/sampleOpaResponses/unconditionalTrueSimple.json +48 -0
- package/dist/test/{sampleOpaResponseUnconditionalTrueWithDefaultRule.json → sampleOpaResponses/unconditionalTrueWithDefaultRule.json} +0 -0
- package/dist/test/{sampleOpaResponseWithDefaultRule.json → sampleOpaResponses/withDefaultRule.json} +0 -0
- package/dist/test/testOpaCompileResponseParser.spec.js +195 -20
- package/dist/test/testOpaCompileResponseParser.spec.js.map +1 -1
- package/package.json +7 -3
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.unknown2Ref = exports.value2String = exports.RegoRef = exports.RegoExp = exports.RegoTerm = exports.RegoOperators = exports.RegoRule = void 0;
|
|
6
|
+
exports.unknown2Ref = exports.RegoRuleSet = exports.value2String = exports.RegoRef = exports.RegoExp = exports.RegoTerm = exports.RegoOperators = exports.RegoRule = void 0;
|
|
7
7
|
const lodash_1 = __importDefault(require("lodash"));
|
|
8
8
|
/**
|
|
9
9
|
* @class RegoRule
|
|
@@ -42,6 +42,7 @@ class RegoRule {
|
|
|
42
42
|
if (!(this.parser instanceof OpaCompileResponseParser)) {
|
|
43
43
|
throw new Error("Require parser parameter to create a RegoRule");
|
|
44
44
|
}
|
|
45
|
+
this.evaluate();
|
|
45
46
|
}
|
|
46
47
|
clone(options = {}) {
|
|
47
48
|
const regoRule = new RegoRule(Object.assign({ name: this.name, fullName: this.fullName, isDefault: this.isDefault, value: this.value, isCompleteEvaluated: this.isCompleteEvaluated, expressions: this.expressions.map((e) => e.clone()), parser: this.parser }, options));
|
|
@@ -56,30 +57,53 @@ class RegoRule {
|
|
|
56
57
|
* @memberof RegoRule
|
|
57
58
|
*/
|
|
58
59
|
evaluate() {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
var _a;
|
|
61
|
+
if (this.isCompleteEvaluated) {
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
if (!((_a = this === null || this === void 0 ? void 0 : this.expressions) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
65
|
+
// a rule with empty body / no expression is matched
|
|
64
66
|
this.isCompleteEvaluated = true;
|
|
65
|
-
this.isMatched =
|
|
67
|
+
this.isMatched = true;
|
|
68
|
+
return this;
|
|
66
69
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
this.isMatched = true;
|
|
70
|
+
let unresolvable = false;
|
|
71
|
+
for (let i = 0; i < this.expressions.length; i++) {
|
|
72
|
+
const exp = this.expressions[i];
|
|
73
|
+
exp.evaluate();
|
|
74
|
+
if (!exp.isResolvable()) {
|
|
75
|
+
unresolvable = true;
|
|
76
|
+
continue;
|
|
75
77
|
}
|
|
76
|
-
|
|
77
|
-
// ---
|
|
78
|
-
// ---
|
|
79
|
-
this.
|
|
78
|
+
if (!exp.isMatched()) {
|
|
79
|
+
// --- rule expressions are always evaluated in the context of AND
|
|
80
|
+
// --- any false expression will make the rule not match
|
|
81
|
+
this.isCompleteEvaluated = true;
|
|
82
|
+
this.isMatched = false;
|
|
83
|
+
return this;
|
|
80
84
|
}
|
|
81
85
|
}
|
|
82
|
-
|
|
86
|
+
if (unresolvable) {
|
|
87
|
+
// there is at least one exp is unresolvable now
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
this.isCompleteEvaluated = true;
|
|
92
|
+
this.isMatched = true;
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Whether or not the rule is resolvable (i.e. we can tell whether it's matched or not) now.
|
|
98
|
+
*
|
|
99
|
+
* @return {*} {boolean}
|
|
100
|
+
* @memberof RegoRule
|
|
101
|
+
*/
|
|
102
|
+
isResolvable() {
|
|
103
|
+
if (!this.isCompleteEvaluated) {
|
|
104
|
+
this.evaluate();
|
|
105
|
+
}
|
|
106
|
+
return this.isCompleteEvaluated;
|
|
83
107
|
}
|
|
84
108
|
/**
|
|
85
109
|
* Generate Human Readable string of this rule
|
|
@@ -103,6 +127,30 @@ class RegoRule {
|
|
|
103
127
|
return parts.join(" AND \n");
|
|
104
128
|
}
|
|
105
129
|
}
|
|
130
|
+
toData() {
|
|
131
|
+
return {
|
|
132
|
+
default: this.isDefault,
|
|
133
|
+
value: this.value,
|
|
134
|
+
fullName: this.fullName,
|
|
135
|
+
name: this.name,
|
|
136
|
+
expressions: this.expressions.map((exp, idx) => exp.toData(idx))
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
toJson() {
|
|
140
|
+
return JSON.stringify(this.toData());
|
|
141
|
+
}
|
|
142
|
+
toConciseData() {
|
|
143
|
+
return {
|
|
144
|
+
default: this.isDefault,
|
|
145
|
+
value: this.value,
|
|
146
|
+
fullName: this.fullName,
|
|
147
|
+
name: this.name,
|
|
148
|
+
expressions: this.expressions.map((exp) => exp.toConciseData())
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
toConciseJSON() {
|
|
152
|
+
return JSON.stringify(this.toConciseData());
|
|
153
|
+
}
|
|
106
154
|
/**
|
|
107
155
|
* Create RegoRule from Opa response data
|
|
108
156
|
*
|
|
@@ -129,7 +177,6 @@ class RegoRule {
|
|
|
129
177
|
parser
|
|
130
178
|
};
|
|
131
179
|
const regoRule = new RegoRule(ruleOptions);
|
|
132
|
-
regoRule.evaluate();
|
|
133
180
|
return regoRule;
|
|
134
181
|
}
|
|
135
182
|
static createExpressionsFromRuleBodyData(data, parser) {
|
|
@@ -338,13 +385,64 @@ class RegoTerm {
|
|
|
338
385
|
}
|
|
339
386
|
else {
|
|
340
387
|
const fullName = this.fullRefString();
|
|
341
|
-
|
|
342
|
-
if (lodash_1.default.isUndefined(result))
|
|
388
|
+
if (!this.parser.isRefResolvable(fullName)) {
|
|
343
389
|
return undefined;
|
|
344
|
-
|
|
390
|
+
}
|
|
391
|
+
return this.parser.getRefValue(fullName);
|
|
345
392
|
}
|
|
346
393
|
}
|
|
347
394
|
}
|
|
395
|
+
/**
|
|
396
|
+
* Whether or not the RegoTerm is resolvable
|
|
397
|
+
*
|
|
398
|
+
* @return {*} {boolean}
|
|
399
|
+
* @memberof RegoTerm
|
|
400
|
+
*/
|
|
401
|
+
isValueResolvable() {
|
|
402
|
+
if (!this.isRef()) {
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
if (this.isOperator()) {
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
const fullName = this.fullRefString();
|
|
411
|
+
return this.parser.isRefResolvable(fullName);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
toData() {
|
|
416
|
+
if (this.isRef()) {
|
|
417
|
+
return this.value.toData();
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
return {
|
|
421
|
+
type: this.type,
|
|
422
|
+
value: this.value
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
toJson() {
|
|
427
|
+
return JSON.stringify(this.toData());
|
|
428
|
+
}
|
|
429
|
+
toConciseData() {
|
|
430
|
+
if (this.isRef()) {
|
|
431
|
+
return {
|
|
432
|
+
isRef: true,
|
|
433
|
+
value: this.fullRefString()
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
return {
|
|
438
|
+
isRef: false,
|
|
439
|
+
value: this.value
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
toConciseJSON() {
|
|
444
|
+
return JSON.stringify(this.toConciseData());
|
|
445
|
+
}
|
|
348
446
|
static parseFromData(data, parser) {
|
|
349
447
|
if (data.type === "ref") {
|
|
350
448
|
return new RegoTerm(data.type, RegoRef.parseFromData(data), parser);
|
|
@@ -462,17 +560,40 @@ class RegoExp {
|
|
|
462
560
|
return this.value;
|
|
463
561
|
}
|
|
464
562
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
563
|
+
/**
|
|
564
|
+
* Whether or not a expression should be considered as "matched".
|
|
565
|
+
* If all expressions of a rule are "matched", the rule will be considered as "matched".
|
|
566
|
+
* Thus, the rule has a value.
|
|
567
|
+
*
|
|
568
|
+
* Please note: if an expression's value is `0`, empty string "", null etc, the expression is considered as "matched".
|
|
569
|
+
* We only consider an expression as "Not Matched" when the expression has value `false` or is undefined.
|
|
570
|
+
*
|
|
571
|
+
* @return {boolean}
|
|
572
|
+
* @memberof RegoExp
|
|
573
|
+
*/
|
|
574
|
+
isMatched() {
|
|
575
|
+
if (!this.isResolvable()) {
|
|
468
576
|
return undefined;
|
|
469
577
|
}
|
|
578
|
+
const isMatched = this.value === false || lodash_1.default.isUndefined(this.value) ? false : true;
|
|
579
|
+
if (this.isNegated) {
|
|
580
|
+
return !isMatched;
|
|
581
|
+
}
|
|
470
582
|
else {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
583
|
+
return isMatched;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Whether or not the expression is resolvable now.
|
|
588
|
+
*
|
|
589
|
+
* @return {boolean}
|
|
590
|
+
* @memberof RegoExp
|
|
591
|
+
*/
|
|
592
|
+
isResolvable() {
|
|
593
|
+
if (!this.isCompleteEvaluated) {
|
|
594
|
+
this.evaluate();
|
|
475
595
|
}
|
|
596
|
+
return this.isCompleteEvaluated;
|
|
476
597
|
}
|
|
477
598
|
/**
|
|
478
599
|
* Convert operator term to string and put rest operands into an array.
|
|
@@ -492,12 +613,7 @@ class RegoExp {
|
|
|
492
613
|
operator = t.asOperator();
|
|
493
614
|
}
|
|
494
615
|
else {
|
|
495
|
-
|
|
496
|
-
if (!lodash_1.default.isUndefined(value)) {
|
|
497
|
-
operands.push(new RegoTerm(typeof value, value, this.parser));
|
|
498
|
-
}
|
|
499
|
-
else
|
|
500
|
-
operands.push(t);
|
|
616
|
+
operands.push(t);
|
|
501
617
|
}
|
|
502
618
|
});
|
|
503
619
|
if (!operator) {
|
|
@@ -515,19 +631,24 @@ class RegoExp {
|
|
|
515
631
|
* @memberof RegoExp
|
|
516
632
|
*/
|
|
517
633
|
evaluate() {
|
|
634
|
+
if (this.isCompleteEvaluated) {
|
|
635
|
+
return this;
|
|
636
|
+
}
|
|
637
|
+
// --- so far there is no 2 terms expression e.g. ! x
|
|
638
|
+
// --- builtin function should never be included in residual rule
|
|
639
|
+
// --- as we won't apply them on unknowns
|
|
518
640
|
if (this.terms.length === 0) {
|
|
519
641
|
// --- exp should be considered as matched (true)
|
|
520
|
-
// --- unless isNegated is true
|
|
521
|
-
// --- will try to normalise isNegated here
|
|
522
642
|
this.isCompleteEvaluated = true;
|
|
523
|
-
this.value =
|
|
524
|
-
this
|
|
643
|
+
this.value = true;
|
|
644
|
+
return this;
|
|
525
645
|
}
|
|
526
|
-
if (this.terms.length === 1) {
|
|
646
|
+
else if (this.terms.length === 1) {
|
|
527
647
|
const term = this.terms[0];
|
|
528
|
-
|
|
529
|
-
if (lodash_1.default.isUndefined(value))
|
|
648
|
+
if (!term.isValueResolvable()) {
|
|
530
649
|
return this;
|
|
650
|
+
}
|
|
651
|
+
const value = term.getValue();
|
|
531
652
|
this.value = value;
|
|
532
653
|
this.isCompleteEvaluated = true;
|
|
533
654
|
return this;
|
|
@@ -536,47 +657,86 @@ class RegoExp {
|
|
|
536
657
|
// --- 3 terms expression e.g. true == true or x >= 3
|
|
537
658
|
// --- we only evalute some redundant expression e.g. true == true or false != true
|
|
538
659
|
const [operator, operands] = this.toOperatorOperandsArray();
|
|
539
|
-
if (operands.
|
|
540
|
-
|
|
660
|
+
if (!operands[0].isValueResolvable() ||
|
|
661
|
+
!operands[1].isValueResolvable()) {
|
|
662
|
+
// if one of the term value is resolvable now, we can't evaluate further.
|
|
541
663
|
return this;
|
|
542
664
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
this.isCompleteEvaluated = true;
|
|
569
|
-
this.value = value;
|
|
570
|
-
return this;
|
|
665
|
+
const operandsValues = operands.map((op) => op.getValue());
|
|
666
|
+
if (operandsValues.findIndex((v) => typeof v === "undefined")) {
|
|
667
|
+
}
|
|
668
|
+
let value = null;
|
|
669
|
+
switch (operator) {
|
|
670
|
+
case "=":
|
|
671
|
+
value = operandsValues[0] === operandsValues[1];
|
|
672
|
+
break;
|
|
673
|
+
case ">":
|
|
674
|
+
value = operandsValues[0] > operandsValues[1];
|
|
675
|
+
break;
|
|
676
|
+
case "<":
|
|
677
|
+
value = operandsValues[0] < operandsValues[1];
|
|
678
|
+
break;
|
|
679
|
+
case ">=":
|
|
680
|
+
value = operandsValues[0] >= operandsValues[1];
|
|
681
|
+
break;
|
|
682
|
+
case "<=":
|
|
683
|
+
value = operandsValues[0] <= operandsValues[1];
|
|
684
|
+
break;
|
|
685
|
+
case "!=":
|
|
686
|
+
value = operandsValues[0] != operandsValues[1];
|
|
687
|
+
break;
|
|
688
|
+
default:
|
|
689
|
+
throw new Error(`Invalid 3 terms rego expression, Unknown operator "${operator}": ${this.termsAsString()}`);
|
|
571
690
|
}
|
|
691
|
+
this.isCompleteEvaluated = true;
|
|
692
|
+
this.value = value;
|
|
693
|
+
return this;
|
|
572
694
|
}
|
|
573
695
|
else {
|
|
574
696
|
throw new Error(`Invalid ${this.terms.length} terms rego expression: ${this.termsAsString()}`);
|
|
575
697
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
698
|
+
}
|
|
699
|
+
toData(index = 0) {
|
|
700
|
+
const terms = this.terms.map((term) => term.toData());
|
|
701
|
+
if (this.isNegated) {
|
|
702
|
+
return {
|
|
703
|
+
negated: true,
|
|
704
|
+
index,
|
|
705
|
+
terms
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
return {
|
|
710
|
+
index,
|
|
711
|
+
terms
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
toJSON(index = 0) {
|
|
716
|
+
return JSON.stringify(this.toData(index));
|
|
717
|
+
}
|
|
718
|
+
toConciseData() {
|
|
719
|
+
let data;
|
|
720
|
+
if (this.terms.length === 1) {
|
|
721
|
+
const term = this.terms[0];
|
|
722
|
+
data = {
|
|
723
|
+
negated: this.isNegated,
|
|
724
|
+
operator: null,
|
|
725
|
+
operands: [term.toConciseData()]
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
else {
|
|
729
|
+
const [operator, operands] = this.toOperatorOperandsArray();
|
|
730
|
+
data = {
|
|
731
|
+
negated: this.isNegated,
|
|
732
|
+
operator,
|
|
733
|
+
operands: operands.map((item) => item.toConciseData())
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
return data;
|
|
737
|
+
}
|
|
738
|
+
toConciseJSON() {
|
|
739
|
+
return JSON.stringify(this.toConciseData());
|
|
580
740
|
}
|
|
581
741
|
static parseFromData(expData, parser) {
|
|
582
742
|
const isNegated = expData.negated === true;
|
|
@@ -613,6 +773,15 @@ class RegoRef {
|
|
|
613
773
|
clone() {
|
|
614
774
|
return new RegoRef(this.parts.map((p) => (Object.assign({}, p))));
|
|
615
775
|
}
|
|
776
|
+
toData() {
|
|
777
|
+
return {
|
|
778
|
+
type: "ref",
|
|
779
|
+
value: this.parts
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
toJson() {
|
|
783
|
+
return JSON.stringify(this.toData());
|
|
784
|
+
}
|
|
616
785
|
static parseFromData(data) {
|
|
617
786
|
if (data.type === "ref") {
|
|
618
787
|
return new RegoRef(data.value);
|
|
@@ -662,10 +831,8 @@ class RegoRef {
|
|
|
662
831
|
if (isFirstPart)
|
|
663
832
|
isFirstPart = false;
|
|
664
833
|
return partStr;
|
|
665
|
-
//--- a.[_].[_] should be a[_][_]
|
|
666
834
|
})
|
|
667
|
-
.join(".")
|
|
668
|
-
.replace(/\.\[/g, "[");
|
|
835
|
+
.join(".");
|
|
669
836
|
return this.removeAllPrefixs(str, removalPrefixs);
|
|
670
837
|
}
|
|
671
838
|
refString(removalPrefixs = []) {
|
|
@@ -718,6 +885,171 @@ function value2String(value) {
|
|
|
718
885
|
return JSON.stringify(value);
|
|
719
886
|
}
|
|
720
887
|
exports.value2String = value2String;
|
|
888
|
+
class RegoRuleSet {
|
|
889
|
+
constructor(parser, rules, fullName = "", name = "") {
|
|
890
|
+
var _a, _b;
|
|
891
|
+
this.fullName = "";
|
|
892
|
+
this.name = "";
|
|
893
|
+
this.rules = [];
|
|
894
|
+
this.defaultRule = null;
|
|
895
|
+
this.isCompleteEvaluated = false;
|
|
896
|
+
this.parser = parser;
|
|
897
|
+
if (rules === null || rules === void 0 ? void 0 : rules.length) {
|
|
898
|
+
const defaultRuleIdx = rules.findIndex((r) => r.isDefault);
|
|
899
|
+
if (defaultRuleIdx !== -1) {
|
|
900
|
+
this.defaultRule = rules[defaultRuleIdx];
|
|
901
|
+
}
|
|
902
|
+
this.rules = rules.filter((r) => !r.isDefault);
|
|
903
|
+
}
|
|
904
|
+
if (fullName) {
|
|
905
|
+
this.fullName = fullName;
|
|
906
|
+
}
|
|
907
|
+
else if ((_a = rules === null || rules === void 0 ? void 0 : rules[0]) === null || _a === void 0 ? void 0 : _a.fullName) {
|
|
908
|
+
this.fullName = rules[0].fullName;
|
|
909
|
+
}
|
|
910
|
+
if (name) {
|
|
911
|
+
this.name = name;
|
|
912
|
+
}
|
|
913
|
+
else if ((_b = rules === null || rules === void 0 ? void 0 : rules[0]) === null || _b === void 0 ? void 0 : _b.name) {
|
|
914
|
+
this.name = rules[0].name;
|
|
915
|
+
}
|
|
916
|
+
this.evaluate();
|
|
917
|
+
}
|
|
918
|
+
evaluate() {
|
|
919
|
+
var _a;
|
|
920
|
+
if (this.isCompleteEvaluated) {
|
|
921
|
+
return this;
|
|
922
|
+
}
|
|
923
|
+
if (!((_a = this.rules) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
924
|
+
if (!this.defaultRule) {
|
|
925
|
+
this.isCompleteEvaluated = true;
|
|
926
|
+
this.value = undefined;
|
|
927
|
+
return this;
|
|
928
|
+
}
|
|
929
|
+
else {
|
|
930
|
+
if (this.defaultRule.isResolvable()) {
|
|
931
|
+
this.isCompleteEvaluated = true;
|
|
932
|
+
this.value = this.defaultRule.value;
|
|
933
|
+
return this;
|
|
934
|
+
}
|
|
935
|
+
else {
|
|
936
|
+
return this;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
this.rules.forEach((r) => r.evaluate());
|
|
941
|
+
const matchedRule = this.rules.find((r) => r.isResolvable() && r.isMatched);
|
|
942
|
+
if (matchedRule) {
|
|
943
|
+
this.isCompleteEvaluated = true;
|
|
944
|
+
this.value = matchedRule.value;
|
|
945
|
+
return this;
|
|
946
|
+
}
|
|
947
|
+
if (this.rules.findIndex((r) => !r.isResolvable()) !== -1) {
|
|
948
|
+
// still has rule unresolvable
|
|
949
|
+
return this;
|
|
950
|
+
}
|
|
951
|
+
// rest (if any) are all unmatched rules
|
|
952
|
+
if (!this.defaultRule) {
|
|
953
|
+
this.isCompleteEvaluated = true;
|
|
954
|
+
this.value = undefined;
|
|
955
|
+
return this;
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
if (this.defaultRule.isResolvable()) {
|
|
959
|
+
this.isCompleteEvaluated = true;
|
|
960
|
+
this.value = this.defaultRule.value;
|
|
961
|
+
return this;
|
|
962
|
+
}
|
|
963
|
+
else {
|
|
964
|
+
return this;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
isResolvable() {
|
|
969
|
+
if (!this.isCompleteEvaluated) {
|
|
970
|
+
this.evaluate();
|
|
971
|
+
}
|
|
972
|
+
return this.isCompleteEvaluated;
|
|
973
|
+
}
|
|
974
|
+
getResidualRules() {
|
|
975
|
+
if (this.isResolvable()) {
|
|
976
|
+
return [];
|
|
977
|
+
}
|
|
978
|
+
let rules = this.defaultRule
|
|
979
|
+
? [this.defaultRule, ...this.rules]
|
|
980
|
+
: [...this.rules];
|
|
981
|
+
rules = this.rules.filter((r) => !r.isResolvable());
|
|
982
|
+
if (!rules.length) {
|
|
983
|
+
return [];
|
|
984
|
+
}
|
|
985
|
+
rules = lodash_1.default.flatMap(rules, (rule) => {
|
|
986
|
+
// all resolvable expressions can all be ignored as:
|
|
987
|
+
// - if the expression is resolved to "matched", it won't impact the result of the rule
|
|
988
|
+
// - if the expression is resolved to "unmatched", the rule should be resolved to "unmatched" earlier.
|
|
989
|
+
const unresolvedExpressions = rule.expressions.filter((exp) => !exp.isResolvable());
|
|
990
|
+
if (unresolvedExpressions.length !== 1) {
|
|
991
|
+
return [rule];
|
|
992
|
+
}
|
|
993
|
+
// For rules with single expression, reduce the layer by replacing it with target reference rules
|
|
994
|
+
const exp = unresolvedExpressions[0];
|
|
995
|
+
if (exp.terms.length === 1) {
|
|
996
|
+
const fullName = exp.terms[0].fullRefString();
|
|
997
|
+
const ruleSet = this.parser.ruleSets[fullName];
|
|
998
|
+
if (!ruleSet) {
|
|
999
|
+
const compressedRule = rule.clone();
|
|
1000
|
+
compressedRule.expressions = [exp];
|
|
1001
|
+
return [compressedRule];
|
|
1002
|
+
}
|
|
1003
|
+
return ruleSet.getResidualRules();
|
|
1004
|
+
}
|
|
1005
|
+
else if (exp.terms.length === 3) {
|
|
1006
|
+
const [operator, [op1, op2]] = exp.toOperatorOperandsArray();
|
|
1007
|
+
if (operator != "=" && operator != "!=") {
|
|
1008
|
+
// For now, we will only further process the ref when operator is = or !=
|
|
1009
|
+
return [rule];
|
|
1010
|
+
}
|
|
1011
|
+
if (!op1.isValueResolvable() && !op2.isValueResolvable()) {
|
|
1012
|
+
// when both op1 & op1 are not resolvable ref, we will not attempt to process further
|
|
1013
|
+
return [rule];
|
|
1014
|
+
}
|
|
1015
|
+
const value = op1.isValueResolvable()
|
|
1016
|
+
? op1.getValue()
|
|
1017
|
+
: op2.getValue();
|
|
1018
|
+
const refTerm = op1.isValueResolvable() ? op2 : op1;
|
|
1019
|
+
const fullName = refTerm.fullRefString();
|
|
1020
|
+
const ruleSet = this.parser.ruleSets[fullName];
|
|
1021
|
+
if (!ruleSet) {
|
|
1022
|
+
const compressedRule = rule.clone();
|
|
1023
|
+
compressedRule.expressions = [exp];
|
|
1024
|
+
return [compressedRule];
|
|
1025
|
+
}
|
|
1026
|
+
let refRules = ruleSet.getResidualRules();
|
|
1027
|
+
// when negated expression, reverse the operator
|
|
1028
|
+
const convertedOperator = exp.isNegated
|
|
1029
|
+
? operator == "="
|
|
1030
|
+
? "!="
|
|
1031
|
+
: "="
|
|
1032
|
+
: operator;
|
|
1033
|
+
if (convertedOperator == "=") {
|
|
1034
|
+
refRules = refRules.filter((r) => r.value == value);
|
|
1035
|
+
}
|
|
1036
|
+
else {
|
|
1037
|
+
refRules = refRules.filter((r) => r.value != value);
|
|
1038
|
+
}
|
|
1039
|
+
if (!refRules.length) {
|
|
1040
|
+
// this means this rule can never matched
|
|
1041
|
+
return [];
|
|
1042
|
+
}
|
|
1043
|
+
return refRules;
|
|
1044
|
+
}
|
|
1045
|
+
else {
|
|
1046
|
+
throw new Error(`Failed to produce residualRules for rule: ${rule.toJson()}`);
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
1049
|
+
return rules;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
exports.RegoRuleSet = RegoRuleSet;
|
|
721
1053
|
/**
|
|
722
1054
|
* OPA result Parser
|
|
723
1055
|
*
|
|
@@ -756,6 +1088,13 @@ class OpaCompileResponseParser {
|
|
|
756
1088
|
* @memberof OpaCompileResponseParser
|
|
757
1089
|
*/
|
|
758
1090
|
this.rules = [];
|
|
1091
|
+
/**
|
|
1092
|
+
* Parsed, compressed & evaluated rule sets
|
|
1093
|
+
*
|
|
1094
|
+
* @type {RegoRuleSet[]}
|
|
1095
|
+
* @memberof OpaCompileResponseParser
|
|
1096
|
+
*/
|
|
1097
|
+
this.ruleSets = {};
|
|
759
1098
|
this.queries = [];
|
|
760
1099
|
/**
|
|
761
1100
|
* A cache of all resolved rule result
|
|
@@ -797,20 +1136,26 @@ class OpaCompileResponseParser {
|
|
|
797
1136
|
else {
|
|
798
1137
|
this.data = json;
|
|
799
1138
|
}
|
|
800
|
-
|
|
1139
|
+
/**
|
|
1140
|
+
* OPA might output {"result": {}} as unconditional `false` or never matched
|
|
1141
|
+
*/
|
|
1142
|
+
if (!this.data.result || !Object.keys(this.data.result).length) {
|
|
801
1143
|
// --- mean no rule matched
|
|
802
1144
|
this.setQueryRuleResult(false);
|
|
803
1145
|
return [];
|
|
804
1146
|
}
|
|
805
1147
|
this.data = this.data.result;
|
|
806
|
-
if (
|
|
1148
|
+
if (!this.data.queries ||
|
|
807
1149
|
!lodash_1.default.isArray(this.data.queries) ||
|
|
808
|
-
!this.data.queries.length)
|
|
809
|
-
(!lodash_1.default.isArray(this.data.support) || !this.data.support.length)) {
|
|
810
|
-
// --- mean no rule matched
|
|
1150
|
+
!this.data.queries.length) {
|
|
811
1151
|
this.setQueryRuleResult(false);
|
|
812
1152
|
return [];
|
|
813
1153
|
}
|
|
1154
|
+
if (this.data.queries.findIndex((q) => !(q === null || q === void 0 ? void 0 : q.length)) !== -1) {
|
|
1155
|
+
// when query is always true, the "queries" value in the result will contain an empty array
|
|
1156
|
+
this.setQueryRuleResult(true);
|
|
1157
|
+
return [];
|
|
1158
|
+
}
|
|
814
1159
|
const queries = this.data.queries;
|
|
815
1160
|
if (queries) {
|
|
816
1161
|
if (queries.findIndex((ruleBody) => !ruleBody || !ruleBody.length) !== -1) {
|
|
@@ -828,7 +1173,6 @@ class OpaCompileResponseParser {
|
|
|
828
1173
|
value: true,
|
|
829
1174
|
parser: this
|
|
830
1175
|
});
|
|
831
|
-
rule.evaluate();
|
|
832
1176
|
this.originalRules.push(rule);
|
|
833
1177
|
this.rules.push(rule);
|
|
834
1178
|
});
|
|
@@ -845,84 +1189,48 @@ class OpaCompileResponseParser {
|
|
|
845
1189
|
rules.forEach((r) => {
|
|
846
1190
|
const regoRule = RegoRule.parseFromData(r, packageName, this);
|
|
847
1191
|
this.originalRules.push(regoRule);
|
|
848
|
-
|
|
849
|
-
if (!regoRule.isCompleteEvaluated) {
|
|
850
|
-
this.rules.push(regoRule);
|
|
851
|
-
}
|
|
852
|
-
else {
|
|
853
|
-
if (regoRule.isMatched) {
|
|
854
|
-
this.rules.push(regoRule);
|
|
855
|
-
}
|
|
856
|
-
}
|
|
1192
|
+
this.rules.push(regoRule);
|
|
857
1193
|
});
|
|
858
1194
|
});
|
|
859
1195
|
}
|
|
860
|
-
this.
|
|
861
|
-
this.
|
|
1196
|
+
lodash_1.default.uniq(this.rules.map((r) => r.fullName)).forEach((fullName) => (this.ruleSets[fullName] = new RegoRuleSet(this, this.rules.filter((r) => r.fullName === fullName), fullName)));
|
|
1197
|
+
this.resolveAllRuleSets();
|
|
862
1198
|
return this.rules;
|
|
863
1199
|
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
// --- if no unevaluated rule left, default rule value should be used
|
|
891
|
-
if (defaultRules.length) {
|
|
892
|
-
this.completeRuleResults[fullName] = this.createCompleteRuleResult(defaultRules[0]);
|
|
893
|
-
return;
|
|
894
|
-
}
|
|
895
|
-
else {
|
|
896
|
-
// --- no matched complete non default rule left; Not possible
|
|
897
|
-
throw new Error(`Unexpected empty rule result for ${fullName}`);
|
|
898
|
-
}
|
|
1200
|
+
isRefResolvable(fullName) {
|
|
1201
|
+
if (this.completeRuleResults[fullName]) {
|
|
1202
|
+
return true;
|
|
1203
|
+
}
|
|
1204
|
+
const ruleSet = this.ruleSets[fullName];
|
|
1205
|
+
if (!ruleSet) {
|
|
1206
|
+
return false;
|
|
1207
|
+
}
|
|
1208
|
+
return ruleSet.isResolvable();
|
|
1209
|
+
}
|
|
1210
|
+
getRefValue(fullName) {
|
|
1211
|
+
const completeResult = this.completeRuleResults[fullName];
|
|
1212
|
+
if (completeResult) {
|
|
1213
|
+
return completeResult.value;
|
|
1214
|
+
}
|
|
1215
|
+
const ruleSet = this.ruleSets[fullName];
|
|
1216
|
+
if (!ruleSet || !ruleSet.isResolvable()) {
|
|
1217
|
+
return undefined;
|
|
1218
|
+
}
|
|
1219
|
+
return ruleSet.value;
|
|
1220
|
+
}
|
|
1221
|
+
resolveAllRuleSets() {
|
|
1222
|
+
while (true) {
|
|
1223
|
+
const unresolvedSetsNum = Object.values(this.ruleSets).filter((rs) => !rs.isResolvable()).length;
|
|
1224
|
+
if (!unresolvedSetsNum) {
|
|
1225
|
+
break;
|
|
899
1226
|
}
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
1227
|
+
Object.values(this.ruleSets).forEach((rs) => rs.evaluate());
|
|
1228
|
+
const newUnresolvedSetsNum = Object.values(this.ruleSets).filter((rs) => !rs.isResolvable()).length;
|
|
1229
|
+
if (!newUnresolvedSetsNum ||
|
|
1230
|
+
newUnresolvedSetsNum >= unresolvedSetsNum) {
|
|
1231
|
+
break;
|
|
905
1232
|
}
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
/**
|
|
909
|
-
* Only for internal usage
|
|
910
|
-
*
|
|
911
|
-
* @returns
|
|
912
|
-
* @private
|
|
913
|
-
* @memberof OpaCompileResponseParser
|
|
914
|
-
*/
|
|
915
|
-
reduceDependencies() {
|
|
916
|
-
const rules = this.rules.filter((r) => !r.isCompleteEvaluated);
|
|
917
|
-
if (!rules.length)
|
|
918
|
-
return;
|
|
919
|
-
for (let i = 0; i < rules.length; i++) {
|
|
920
|
-
const rule = rules[i];
|
|
921
|
-
rule.expressions = rule.expressions.map((e) => e.evaluate());
|
|
922
|
-
rule.evaluate();
|
|
923
|
-
}
|
|
924
|
-
// --- unmatched non-default rule can be stripped out
|
|
925
|
-
this.rules = this.rules.filter((r) => !(r.isCompleteEvaluated && !r.isMatched && !r.isDefault));
|
|
1233
|
+
}
|
|
926
1234
|
}
|
|
927
1235
|
/**
|
|
928
1236
|
* Call to evaluate a rule
|
|
@@ -932,136 +1240,28 @@ class OpaCompileResponseParser {
|
|
|
932
1240
|
* @memberof OpaCompileResponseParser
|
|
933
1241
|
*/
|
|
934
1242
|
evaluateRule(fullName) {
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
// --- already evaluated during paring or dependencies removal
|
|
938
|
-
return (_c = this.completeRuleResults) === null || _c === void 0 ? void 0 : _c[fullName];
|
|
1243
|
+
if (this.completeRuleResults[fullName]) {
|
|
1244
|
+
return this.completeRuleResults[fullName];
|
|
939
1245
|
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
if (!rules.length) {
|
|
943
|
-
// --- no any rule matched; often (depends on your policy) it means a overall non-matched (false)
|
|
1246
|
+
const ruleSet = this.ruleSets[fullName];
|
|
1247
|
+
if (!ruleSet) {
|
|
944
1248
|
return null;
|
|
945
1249
|
}
|
|
946
|
-
|
|
947
|
-
const defaultValue = lodash_1.default.isUndefined(defaultRule)
|
|
948
|
-
? undefined
|
|
949
|
-
: defaultRule.value;
|
|
950
|
-
if (rules.find((r) => r.isCompleteEvaluated))
|
|
951
|
-
// --- filter out default rules & unmatched
|
|
952
|
-
// --- isMatch is only set when r.isCompleteEvaluated = true
|
|
953
|
-
rules = rules.filter((r) => !(r.isDefault || (r.isCompleteEvaluated && !r.isMatched)));
|
|
954
|
-
if (!rules.length) {
|
|
1250
|
+
if (ruleSet.isResolvable()) {
|
|
955
1251
|
return {
|
|
956
1252
|
fullName,
|
|
957
|
-
name:
|
|
958
|
-
value:
|
|
959
|
-
isCompleteEvaluated: true
|
|
960
|
-
residualRules: []
|
|
1253
|
+
name: ruleSet.name,
|
|
1254
|
+
value: ruleSet.value,
|
|
1255
|
+
isCompleteEvaluated: true
|
|
961
1256
|
};
|
|
962
1257
|
}
|
|
963
1258
|
else {
|
|
964
|
-
const matchedRule = rules.find((r) => r.isMatched);
|
|
965
|
-
if (matchedRule) {
|
|
966
|
-
return {
|
|
967
|
-
fullName,
|
|
968
|
-
name: originalRuleName,
|
|
969
|
-
value: matchedRule.value,
|
|
970
|
-
isCompleteEvaluated: true,
|
|
971
|
-
residualRules: []
|
|
972
|
-
};
|
|
973
|
-
}
|
|
974
|
-
const ruleWithEmptyExps = rules.find((r) => !r.expressions.length);
|
|
975
|
-
if (ruleWithEmptyExps) {
|
|
976
|
-
// empty exp / body means unconditional match
|
|
977
|
-
return {
|
|
978
|
-
fullName,
|
|
979
|
-
name: originalRuleName,
|
|
980
|
-
value: ruleWithEmptyExps.value,
|
|
981
|
-
isCompleteEvaluated: true,
|
|
982
|
-
residualRules: []
|
|
983
|
-
};
|
|
984
|
-
}
|
|
985
|
-
if (rules.length === 1 && rules[0].expressions.length === 1) {
|
|
986
|
-
rules[0].expressions[0].terms.length === 1;
|
|
987
|
-
}
|
|
988
|
-
// if a rules contains one expression only, we will try to resolve any possible rule ref
|
|
989
|
-
rules = lodash_1.default.flatMap(rules, (rule) => {
|
|
990
|
-
if (rules.length === 1 && rules[0].expressions.length === 1) {
|
|
991
|
-
const exp = rules[0].expressions[0];
|
|
992
|
-
if (exp.terms.length === 1 && exp.terms[0].isRef()) {
|
|
993
|
-
const ruleRef = exp.terms[0].fullRefString();
|
|
994
|
-
const result = this.evaluateRule(ruleRef);
|
|
995
|
-
if (result) {
|
|
996
|
-
if (result.isCompleteEvaluated) {
|
|
997
|
-
return [
|
|
998
|
-
RegoRule.createFromValue(result.value, this)
|
|
999
|
-
];
|
|
1000
|
-
}
|
|
1001
|
-
else {
|
|
1002
|
-
return result.residualRules;
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
else {
|
|
1006
|
-
return [rule];
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
else if (exp.terms.length === 3) {
|
|
1010
|
-
const [opStr, [op1, op2]] = exp.toOperatorOperandsArray();
|
|
1011
|
-
if (opStr === "=" &&
|
|
1012
|
-
((op1.isRef() && typeof op2.value === "boolean") ||
|
|
1013
|
-
(op2.isRef() && typeof op1.value === "boolean"))) {
|
|
1014
|
-
const ruleRef = op1.isRef()
|
|
1015
|
-
? op1.fullRefString()
|
|
1016
|
-
: op2.fullRefString();
|
|
1017
|
-
const bVal = typeof op1.value === "boolean"
|
|
1018
|
-
? op1.value
|
|
1019
|
-
: op2.value;
|
|
1020
|
-
const result = this.evaluateRule(ruleRef);
|
|
1021
|
-
if (result) {
|
|
1022
|
-
if (result.isCompleteEvaluated) {
|
|
1023
|
-
if (bVal === false) {
|
|
1024
|
-
return [
|
|
1025
|
-
RegoRule.createFromValue(!result.value, this)
|
|
1026
|
-
];
|
|
1027
|
-
}
|
|
1028
|
-
else {
|
|
1029
|
-
return [
|
|
1030
|
-
RegoRule.createFromValue(result.value, this)
|
|
1031
|
-
];
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
else {
|
|
1035
|
-
if (bVal === false) {
|
|
1036
|
-
return result.residualRules.map((r) => r.clone({ value: !r.value }));
|
|
1037
|
-
}
|
|
1038
|
-
else {
|
|
1039
|
-
return result.residualRules;
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
else {
|
|
1044
|
-
return [rule];
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
else {
|
|
1048
|
-
return [rule];
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
else {
|
|
1052
|
-
return [rule];
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
else {
|
|
1056
|
-
return [rule];
|
|
1057
|
-
}
|
|
1058
|
-
});
|
|
1059
1259
|
return {
|
|
1060
1260
|
fullName,
|
|
1061
|
-
name:
|
|
1261
|
+
name: ruleSet.name,
|
|
1062
1262
|
value: undefined,
|
|
1063
1263
|
isCompleteEvaluated: false,
|
|
1064
|
-
residualRules:
|
|
1264
|
+
residualRules: ruleSet.getResidualRules()
|
|
1065
1265
|
};
|
|
1066
1266
|
}
|
|
1067
1267
|
}
|
|
@@ -1086,6 +1286,9 @@ class OpaCompileResponseParser {
|
|
|
1086
1286
|
if (result === null)
|
|
1087
1287
|
return "null";
|
|
1088
1288
|
if (result.isCompleteEvaluated) {
|
|
1289
|
+
if (typeof result.value === "undefined") {
|
|
1290
|
+
return "undefined";
|
|
1291
|
+
}
|
|
1089
1292
|
return value2String(result.value);
|
|
1090
1293
|
}
|
|
1091
1294
|
let parts = result.residualRules.map((r) => r.toHumanReadableString());
|
|
@@ -1103,23 +1306,6 @@ class OpaCompileResponseParser {
|
|
|
1103
1306
|
evaluateAsHumanReadableString() {
|
|
1104
1307
|
return this.evaluateRuleAsHumanReadableString(this.pseudoQueryRuleName);
|
|
1105
1308
|
}
|
|
1106
|
-
/**
|
|
1107
|
-
* Only for internal usage
|
|
1108
|
-
*
|
|
1109
|
-
* @param {RegoRule} rule
|
|
1110
|
-
* @returns {CompleteRuleResult}
|
|
1111
|
-
* @private
|
|
1112
|
-
* @memberof OpaCompileResponseParser
|
|
1113
|
-
*/
|
|
1114
|
-
createCompleteRuleResult(rule) {
|
|
1115
|
-
return {
|
|
1116
|
-
fullName: rule.fullName,
|
|
1117
|
-
name: rule.name,
|
|
1118
|
-
value: rule.value,
|
|
1119
|
-
isCompleteEvaluated: true,
|
|
1120
|
-
residualRules: []
|
|
1121
|
-
};
|
|
1122
|
-
}
|
|
1123
1309
|
reportWarns(msg) {
|
|
1124
1310
|
this.warns.push(msg);
|
|
1125
1311
|
this.hasWarns = true;
|