@via-profit/ability 2.0.0-rc.8 → 3.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.js CHANGED
@@ -9,9 +9,12 @@
9
9
  Object.defineProperty(exports, "__esModule", ({ value: true }));
10
10
  exports.AbilityCode = void 0;
11
11
  class AbilityCode {
12
- code;
12
+ _code;
13
13
  constructor(code) {
14
- this.code = code;
14
+ this._code = code;
15
+ }
16
+ get code() {
17
+ return this._code;
15
18
  }
16
19
  isEqual(compareWith) {
17
20
  return compareWith !== null && this.code === compareWith.code;
@@ -19,18 +22,6 @@ class AbilityCode {
19
22
  isNotEqual(compareWith) {
20
23
  return !this.isEqual(compareWith);
21
24
  }
22
- static fromLiteral(literal) {
23
- let Code = null;
24
- Object.keys(this).forEach(member => {
25
- if (member === literal) {
26
- Code = this[member];
27
- }
28
- });
29
- if (!Code) {
30
- throw new Error(`Mismatch error. The literal ${literal} can not be find as a member of this class`);
31
- }
32
- return new this(Code.code);
33
- }
34
25
  }
35
26
  exports.AbilityCode = AbilityCode;
36
27
  exports["default"] = AbilityCode;
@@ -68,15 +59,48 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
68
59
  Object.defineProperty(exports, "__esModule", ({ value: true }));
69
60
  exports.AbilityCondition = void 0;
70
61
  const AbilityCode_1 = __importDefault(__webpack_require__(19));
62
+ const AbilityError_1 = __webpack_require__(122);
71
63
  class AbilityCondition extends AbilityCode_1.default {
72
- static EQUAL = new AbilityCondition('=');
73
- static NOT_EQUAL = new AbilityCondition('<>');
74
- static MORE_THAN = new AbilityCondition('>');
75
- static LESS_THAN = new AbilityCondition('<');
76
- static LESS_OR_EQUAL = new AbilityCondition('<=');
77
- static MORE_OR_EQUAL = new AbilityCondition('>=');
78
- static IN = new AbilityCondition('in');
79
- static NOT_IN = new AbilityCondition('not in');
64
+ static equal = new AbilityCondition('=');
65
+ static not_equal = new AbilityCondition('<>');
66
+ static more_than = new AbilityCondition('>');
67
+ static less_than = new AbilityCondition('<');
68
+ static less_or_equal = new AbilityCondition('<=');
69
+ static more_or_equal = new AbilityCondition('>=');
70
+ static in = new AbilityCondition('in');
71
+ static not_in = new AbilityCondition('not in');
72
+ static fromLiteral(literal) {
73
+ switch (literal) {
74
+ case 'equal':
75
+ return this.equal;
76
+ case 'not_equal':
77
+ return this.not_equal;
78
+ case 'more_than':
79
+ return this.more_than;
80
+ case 'less_than':
81
+ return this.less_than;
82
+ case 'less_or_equal':
83
+ return this.less_or_equal;
84
+ case 'more_or_equal':
85
+ return this.more_or_equal;
86
+ case 'in':
87
+ return this.in;
88
+ case 'not_in':
89
+ return this.not_in;
90
+ default:
91
+ throw new AbilityError_1.AbilityParserError(`Literal ${literal} does not found in AbilityCondition class`);
92
+ }
93
+ }
94
+ get literal() {
95
+ const literal = Object.keys(AbilityCondition).find(member => {
96
+ const val = AbilityCondition[member];
97
+ return val.code === this.code;
98
+ });
99
+ if (typeof literal === 'undefined') {
100
+ throw new Error(`Literal value does not found in class AbilityCondition`);
101
+ }
102
+ return literal;
103
+ }
80
104
  }
81
105
  exports.AbilityCondition = AbilityCondition;
82
106
  exports["default"] = AbilityCondition;
@@ -89,7 +113,7 @@ exports["default"] = AbilityCondition;
89
113
 
90
114
 
91
115
  Object.defineProperty(exports, "__esModule", ({ value: true }));
92
- exports.PermissionError = exports.AbilityParserError = exports.AbilityError = void 0;
116
+ exports.AbilityParserError = exports.AbilityError = void 0;
93
117
  class AbilityError extends Error {
94
118
  constructor(message) {
95
119
  super(message);
@@ -102,12 +126,74 @@ class AbilityParserError extends Error {
102
126
  }
103
127
  }
104
128
  exports.AbilityParserError = AbilityParserError;
105
- class PermissionError extends Error {
106
- constructor(message) {
107
- super(message);
129
+
130
+
131
+ /***/ }),
132
+
133
+ /***/ 363:
134
+ /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
135
+
136
+
137
+ var __importDefault = (this && this.__importDefault) || function (mod) {
138
+ return (mod && mod.__esModule) ? mod : { "default": mod };
139
+ };
140
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
141
+ exports.AbilityExplainPolicy = exports.AbilityExplainRuleSet = exports.AbilityExplainRule = exports.AbilityExplain = void 0;
142
+ const AbilityMatch_1 = __importDefault(__webpack_require__(909));
143
+ class AbilityExplain {
144
+ type;
145
+ children;
146
+ name;
147
+ match;
148
+ constructor(config, children = []) {
149
+ this.type = config.type;
150
+ this.children = children;
151
+ this.name = config.name;
152
+ this.match = config.match;
153
+ }
154
+ toString(indent = 0) {
155
+ const pad = ' '.repeat(indent);
156
+ const mark = this.match.code === AbilityMatch_1.default.match.code ? '✓' : '✗';
157
+ let out = `${pad}${mark} ${this.type} «${this.name}» is ${this.match.code}`;
158
+ this.children.forEach(child => {
159
+ out += '\n' + child.toString(indent + 1);
160
+ });
161
+ return out;
162
+ }
163
+ }
164
+ exports.AbilityExplain = AbilityExplain;
165
+ class AbilityExplainRule extends AbilityExplain {
166
+ constructor(rule) {
167
+ super({
168
+ type: 'rule',
169
+ match: rule.state,
170
+ name: rule.name,
171
+ });
172
+ }
173
+ }
174
+ exports.AbilityExplainRule = AbilityExplainRule;
175
+ class AbilityExplainRuleSet extends AbilityExplain {
176
+ constructor(ruleSet) {
177
+ const children = ruleSet.rules.map(rule => new AbilityExplainRule(rule));
178
+ super({
179
+ type: 'ruleSet',
180
+ match: ruleSet.state,
181
+ name: ruleSet.name,
182
+ }, children);
108
183
  }
109
184
  }
110
- exports.PermissionError = PermissionError;
185
+ exports.AbilityExplainRuleSet = AbilityExplainRuleSet;
186
+ class AbilityExplainPolicy extends AbilityExplain {
187
+ constructor(policy) {
188
+ const children = policy.ruleSet.map(ruleSet => new AbilityExplainRuleSet(ruleSet));
189
+ super({
190
+ type: 'policy',
191
+ name: policy.name,
192
+ match: policy.matchState,
193
+ }, children);
194
+ }
195
+ }
196
+ exports.AbilityExplainPolicy = AbilityExplainPolicy;
111
197
 
112
198
 
113
199
  /***/ }),
@@ -145,20 +231,6 @@ exports.AbilityParser = void 0;
145
231
  const AbilityError_1 = __webpack_require__(122);
146
232
  const AbilityCondition_1 = __importDefault(__webpack_require__(261));
147
233
  class AbilityParser {
148
- /*
149
- *
150
- * readonly ['order.update']: {
151
- * readonly user: {
152
- * readonly roles: readonly string[];
153
- * readonly department: string;
154
- * };
155
- * readonly order: {
156
- * readonly estimatedArrivalAt: number;
157
- * readonly status: string;
158
- * }
159
- * }
160
- *
161
- * */
162
234
  /**
163
235
  * Sets a value in a nested object structure based on a dot/bracket notation path.
164
236
  * @param object - The target object to modify.
@@ -166,52 +238,222 @@ class AbilityParser {
166
238
  * @param value - The value to set at the specified path.
167
239
  */
168
240
  static setValueDotValue(object, path, value) {
169
- const way = path.replace(/\[/g, '.').replace(/\]/g, '').split('.');
241
+ if (!path || path.trim().length === 0) {
242
+ throw new AbilityError_1.AbilityParserError(`Invalid path provided on a [${path}]`);
243
+ }
244
+ const way = path.replace(/\[/g, '.').replace(/]/g, '').split('.');
170
245
  const last = way.pop();
171
246
  if (!last) {
172
247
  throw new AbilityError_1.AbilityParserError(`Invalid path provided on a [${path}]`);
173
248
  }
174
- way.reduce((o, k, i, kk) => {
175
- if (!o[k]) {
176
- o[k] = isFinite(Number(kk[i + 1])) ? [] : {};
249
+ const lastObj = way.reduce((acc, key, index, array) => {
250
+ const currentValue = acc[key];
251
+ const nextKey = array[index + 1];
252
+ const shouldBeArray = nextKey !== undefined && isFinite(Number(nextKey));
253
+ if (currentValue === undefined || currentValue === null) {
254
+ // Create missing property
255
+ const newValue = shouldBeArray ? [] : {};
256
+ acc[key] = newValue;
257
+ return newValue;
258
+ }
259
+ if (typeof currentValue !== 'object') {
260
+ throw new AbilityError_1.AbilityParserError(`Cannot set property '${key}' on non-object value at path: ${path}`);
177
261
  }
178
- return o[k];
179
- }, object)[last] = value;
262
+ return currentValue;
263
+ }, object);
264
+ const existingValue = lastObj[last];
265
+ if (existingValue !== undefined &&
266
+ typeof existingValue === 'object' &&
267
+ existingValue !== null &&
268
+ !Array.isArray(existingValue)) {
269
+ throw new AbilityError_1.AbilityParserError(`Cannot set primitive value on existing object at path: ${path}`);
270
+ }
271
+ lastObj[last] = value;
180
272
  }
181
273
  /**
182
274
  * Generates TypeScript type definitions based on the provided policies.
183
275
  * @param policies - An array of AbilityPolicy instances.
184
- * @param outPath - The output path for the generated type definitions.
185
- * @returns A record containing the generated type definitions.
276
+ * @returns A generated type definitions.
186
277
  */
187
- static generateTypeDefs(policies, outPath) {
188
- const record = {};
278
+ static generateTypeDefs(policies) {
279
+ // Structure to store types: { [action]: { [subjectPath]: type } }
280
+ const typeStructure = {};
281
+ // Iterate through all policies
189
282
  policies.forEach(policy => {
283
+ const action = policy.action;
284
+ // Initialize object for action if it doesn't exist
285
+ if (!typeStructure[action]) {
286
+ typeStructure[action] = {};
287
+ }
288
+ // Iterate through all ruleSets in the policy
190
289
  policy.ruleSet.forEach(ruleSet => {
290
+ // Iterate through all rules in the ruleSet
191
291
  ruleSet.rules.forEach(rule => {
192
- let value = 'any';
193
- switch (true) {
194
- case rule.condition.isEqual(AbilityCondition_1.default.NOT_EQUAL):
195
- case rule.condition.isEqual(AbilityCondition_1.default.EQUAL):
196
- value = typeof rule.resource;
197
- break;
198
- case rule.condition.isEqual(AbilityCondition_1.default.IN):
199
- case rule.condition.isEqual(AbilityCondition_1.default.NOT_IN):
200
- value = `${typeof rule.resource}[]`;
201
- break;
202
- case rule.condition.isEqual(AbilityCondition_1.default.MORE_OR_EQUAL):
203
- case rule.condition.isEqual(AbilityCondition_1.default.MORE_THAN):
204
- case rule.condition.isEqual(AbilityCondition_1.default.LESS_OR_EQUAL):
205
- case rule.condition.isEqual(AbilityCondition_1.default.LESS_THAN):
206
- value = 'number';
207
- break;
292
+ const subjectPath = rule.subject;
293
+ const existingType = typeStructure[action][subjectPath];
294
+ const ruleType = this.determineTypeFromRule(rule);
295
+ // If a type already exists for this path, create a union
296
+ if (existingType && existingType !== ruleType) {
297
+ typeStructure[action][subjectPath] = `${existingType} | ${ruleType}`;
298
+ }
299
+ else {
300
+ typeStructure[action][subjectPath] = ruleType;
208
301
  }
209
- AbilityParser.setValueDotValue(record, rule.subject, value);
210
302
  });
211
303
  });
212
304
  });
213
- console.log(JSON.stringify(record));
214
- return record;
305
+ // Transform flat structure into nested structure for easier use
306
+ const nestedStructure = this.buildNestedStructure(typeStructure);
307
+ return this.formatTypeDefinitions(nestedStructure);
308
+ }
309
+ /**
310
+ * Determines TypeScript type based on the rule
311
+ * @param rule - The rule to analyze
312
+ * @returns TypeScript type as string
313
+ */
314
+ static determineTypeFromRule(rule) {
315
+ // Numeric comparisons - always number
316
+ if (rule.condition.isEqual(AbilityCondition_1.default.more_than) ||
317
+ rule.condition.isEqual(AbilityCondition_1.default.less_than) ||
318
+ rule.condition.isEqual(AbilityCondition_1.default.more_or_equal) ||
319
+ rule.condition.isEqual(AbilityCondition_1.default.less_or_equal)) {
320
+ return 'number';
321
+ }
322
+ // Array operations
323
+ if (rule.condition.isEqual(AbilityCondition_1.default.in) ||
324
+ rule.condition.isEqual(AbilityCondition_1.default.not_in)) {
325
+ return this.getArrayType(rule.resource);
326
+ }
327
+ // Equality/Inequality operations
328
+ if (rule.condition.isEqual(AbilityCondition_1.default.equal) ||
329
+ rule.condition.isEqual(AbilityCondition_1.default.not_equal)) {
330
+ return this.getPrimitiveType(rule.resource);
331
+ }
332
+ return 'any';
333
+ }
334
+ /**
335
+ * Gets TypeScript type for array values
336
+ * @param resource - The resource value to analyze
337
+ * @returns TypeScript array type as string
338
+ */
339
+ static getArrayType(resource) {
340
+ if (Array.isArray(resource)) {
341
+ if (resource.length === 0)
342
+ return 'any[]';
343
+ // Determine types of array elements
344
+ const elementTypes = new Set(resource.map(item => this.getPrimitiveType(item)));
345
+ const elementType = elementTypes.size === 1
346
+ ? Array.from(elementTypes)[0]
347
+ : `(${Array.from(elementTypes).join(' | ')})`;
348
+ return `${elementType}[]`;
349
+ }
350
+ // If resource is not an array but condition is in/not_in,
351
+ // it expects an array of such elements
352
+ return `${this.getPrimitiveType(resource)}[]`;
353
+ }
354
+ /**
355
+ * Gets primitive TypeScript type for a value
356
+ * @param value - The value to analyze
357
+ * @returns TypeScript primitive type as string
358
+ */
359
+ static getPrimitiveType(value) {
360
+ if (value === null)
361
+ return 'null';
362
+ if (value === undefined)
363
+ return 'undefined';
364
+ switch (typeof value) {
365
+ case 'string':
366
+ return 'string';
367
+ case 'number':
368
+ return 'number';
369
+ case 'boolean':
370
+ return 'boolean';
371
+ case 'object':
372
+ if (Array.isArray(value)) {
373
+ return 'array'; // special marker, handled separately
374
+ }
375
+ return 'object';
376
+ default:
377
+ return 'any';
378
+ }
379
+ }
380
+ /**
381
+ * Builds nested structure from flat paths
382
+ * Example: 'user.profile.name' -> { user: { profile: { name: 'string' } } }
383
+ * @param flatStructure - Flat structure with dot notation paths
384
+ * @returns Nested object structure
385
+ */
386
+ static buildNestedStructure(flatStructure) {
387
+ const result = {};
388
+ Object.entries(flatStructure).forEach(([action, paths]) => {
389
+ result[action] = {};
390
+ Object.entries(paths).forEach(([path, type]) => {
391
+ const parts = path.split('.');
392
+ let current = result[action];
393
+ // Iterate through all parts except the last one
394
+ for (let i = 0; i < parts.length - 1; i++) {
395
+ const part = parts[i];
396
+ const currentValue = current[part];
397
+ if (!currentValue || typeof currentValue !== 'object') {
398
+ const newObj = {};
399
+ current[part] = newObj;
400
+ current = newObj;
401
+ }
402
+ else {
403
+ current = currentValue;
404
+ }
405
+ }
406
+ // Set type for the last part
407
+ const lastPart = parts[parts.length - 1];
408
+ current[lastPart] = type;
409
+ });
410
+ });
411
+ return result;
412
+ }
413
+ /**
414
+ * Formats type structure into a string
415
+ * @param structure - Nested type structure
416
+ * @returns Formatted TypeScript type definition string
417
+ */
418
+ static formatTypeDefinitions(structure) {
419
+ let output = '// Automatically generated by via-profit/ability\n';
420
+ output += '// Do not edit manually\n\n';
421
+ output += 'export type Resources = {\n';
422
+ // Sort actions for stable output
423
+ const sortedActions = Object.keys(structure).sort();
424
+ sortedActions.forEach(action => {
425
+ output += ` ['${action}']: {\n`;
426
+ output += this.formatNestedObject(structure[action], 4);
427
+ output += ' };\n';
428
+ });
429
+ output += '}\n';
430
+ return output;
431
+ }
432
+ /**
433
+ * Recursively formats nested object
434
+ * @param obj - Object to format
435
+ * @param indent - Current indentation level
436
+ * @returns Formatted string
437
+ */
438
+ static formatNestedObject(obj, indent) {
439
+ const spaces = ' '.repeat(indent);
440
+ let output = '';
441
+ // Sort keys for stable output
442
+ const sortedKeys = Object.keys(obj).sort();
443
+ sortedKeys.forEach(key => {
444
+ const value = obj[key];
445
+ if (typeof value === 'object' && value !== null) {
446
+ // Nested object
447
+ output += `${spaces}readonly ${key}: {\n`;
448
+ output += this.formatNestedObject(value, indent + 2);
449
+ output += `${spaces}};\n`;
450
+ }
451
+ else {
452
+ // Primitive type
453
+ output += `${spaces}readonly ${key}: ${value};\n`;
454
+ }
455
+ });
456
+ return output;
215
457
  }
216
458
  }
217
459
  exports.AbilityParser = AbilityParser;
@@ -233,6 +475,8 @@ const AbilityRuleSet_1 = __importDefault(__webpack_require__(402));
233
475
  const AbilityMatch_1 = __importDefault(__webpack_require__(909));
234
476
  const AbilityCompare_1 = __importDefault(__webpack_require__(923));
235
477
  const AbilityPolicyEffect_1 = __importDefault(__webpack_require__(277));
478
+ const AbilityExplain_1 = __webpack_require__(363);
479
+ const AbilityError_1 = __webpack_require__(122);
236
480
  class AbilityPolicy {
237
481
  matchState = AbilityMatch_1.default.pending;
238
482
  /**
@@ -259,15 +503,17 @@ class AbilityPolicy {
259
503
  */
260
504
  id;
261
505
  /**
262
- * Soon
506
+ * Running the `enforce` or `resolve` method
507
+ * will select only those from all passed policies that fall under the specified action.
263
508
  */
264
509
  action;
265
510
  constructor(params) {
266
- const { name, id, action, effect } = params;
511
+ const { name, id, action, effect, compareMethod = AbilityCompare_1.default.and } = params;
267
512
  this.name = name;
268
513
  this.id = id;
269
514
  this.action = action;
270
515
  this.effect = effect;
516
+ this.compareMethod = compareMethod;
271
517
  }
272
518
  /**
273
519
  * Add rule set to the policy
@@ -301,6 +547,20 @@ class AbilityPolicy {
301
547
  }
302
548
  return this.matchState;
303
549
  }
550
+ explain() {
551
+ if (this.matchState === AbilityMatch_1.default.pending) {
552
+ throw new AbilityError_1.AbilityError('First, run the check method, then explain');
553
+ }
554
+ return new AbilityExplain_1.AbilityExplainPolicy(this);
555
+ }
556
+ /**
557
+ * Parses an array of policy configurations into an array of AbilityPolicy instances.
558
+ * @param configs - Array of policy configurations
559
+ * @returns Array of AbilityPolicy instances
560
+ */
561
+ static parseAll(configs) {
562
+ return configs.map(config => this.parse(config));
563
+ }
304
564
  /**
305
565
  * Parse the config JSON format to Policy class instance
306
566
  */
@@ -313,7 +573,7 @@ class AbilityPolicy {
313
573
  action,
314
574
  effect: new AbilityPolicyEffect_1.default(effect),
315
575
  });
316
- policy.compareMethod = AbilityCompare_1.default.fromLiteral(compareMethod);
576
+ policy.compareMethod = new AbilityCompare_1.default(compareMethod);
317
577
  ruleSet.forEach(ruleSetConfig => {
318
578
  policy.addRuleSet(AbilityRuleSet_1.default.parse(ruleSetConfig));
319
579
  });
@@ -368,6 +628,7 @@ exports.AbilityResolver = void 0;
368
628
  const AbilityPolicyEffect_1 = __importDefault(__webpack_require__(277));
369
629
  const AbilityMatch_1 = __importDefault(__webpack_require__(909));
370
630
  const AbilityError_1 = __webpack_require__(122);
631
+ const AbilityExplain_1 = __webpack_require__(363);
371
632
  class AbilityResolver {
372
633
  policies;
373
634
  constructor(policyOrListOfPolicies) {
@@ -389,12 +650,15 @@ class AbilityResolver {
389
650
  this.policies = filteredPolicies;
390
651
  return this;
391
652
  }
653
+ resolveWithExplain(action, resource) {
654
+ return this.resolve(action, resource).policies.map(policy => {
655
+ return new AbilityExplain_1.AbilityExplainPolicy(policy);
656
+ });
657
+ }
392
658
  enforce(action, resource) {
393
659
  const resolver = this.resolve(action, resource);
394
- if (resolver) {
395
- if (resolver.isDeny()) {
396
- throw new AbilityError_1.PermissionError(resolver.getMatchedPolicy()?.name?.toString() || 'Unknown permission error');
397
- }
660
+ if (resolver.isDeny()) {
661
+ throw new AbilityError_1.AbilityError(resolver.getMatchedPolicy()?.name?.toString() || 'Unknown permission error');
398
662
  }
399
663
  }
400
664
  /**
@@ -437,8 +701,7 @@ class AbilityResolver {
437
701
  const actionBArray = String(actionB).split('.');
438
702
  const a = actionAArray.length >= actionBArray.length ? actionAArray : actionBArray;
439
703
  const b = actionBArray.length <= actionAArray.length ? actionBArray : actionAArray;
440
- const c = a
441
- .reduce((acc, chunk, index) => {
704
+ const c = a.reduce((acc, chunk, index) => {
442
705
  const iterationRes = chunk === b[index] || b[index] === '*' || chunk === '*';
443
706
  return acc.concat(iterationRes);
444
707
  }, []);
@@ -462,6 +725,9 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
462
725
  exports.AbilityRule = void 0;
463
726
  const AbilityMatch_1 = __importDefault(__webpack_require__(909));
464
727
  const AbilityCondition_1 = __importDefault(__webpack_require__(261));
728
+ /**
729
+ * Represents a rule that defines a condition to be checked against a subject and resource.
730
+ */
465
731
  class AbilityRule {
466
732
  /**
467
733
  * Subject key path like a 'user.name'
@@ -475,13 +741,22 @@ class AbilityRule {
475
741
  name;
476
742
  id;
477
743
  state = AbilityMatch_1.default.pending;
744
+ /**
745
+ * Creates an instance of AbilityRule.
746
+ * @param {string} options.id - The unique identifier of the rule.
747
+ * @param {string} options.name - The name of the rule.
748
+ * @param {AbilityCondition} options.condition - The condition to evaluate.
749
+ * @param {string} options.subject - The subject of the rule.
750
+ * @param {string} options.resource - The resource to compare against.
751
+ * @param params
752
+ */
478
753
  constructor(params) {
479
754
  const { id, name, subject, resource, condition } = params;
480
- this.id = id;
481
- this.name = name;
755
+ this.name = name || `${JSON.stringify(subject)} ${condition.code} ${JSON.stringify(resource)}`;
756
+ this.id = id || this.name;
482
757
  this.subject = subject;
483
758
  this.resource = resource;
484
- this.condition = new AbilityCondition_1.default(condition);
759
+ this.condition = condition;
485
760
  }
486
761
  /**
487
762
  * Check if the rule is matched
@@ -490,25 +765,25 @@ class AbilityRule {
490
765
  check(resource) {
491
766
  let is = false;
492
767
  const [valueS, valueO] = this.extractValues(resource);
493
- if (AbilityCondition_1.default.LESS_THAN.isEqual(this.condition)) {
768
+ if (AbilityCondition_1.default.less_than.isEqual(this.condition)) {
494
769
  is = Number(valueS) < Number(valueO);
495
770
  }
496
- if (AbilityCondition_1.default.LESS_OR_EQUAL.isEqual(this.condition)) {
771
+ if (AbilityCondition_1.default.less_or_equal.isEqual(this.condition)) {
497
772
  is = Number(valueS) <= Number(valueO);
498
773
  }
499
- if (AbilityCondition_1.default.MORE_THAN.isEqual(this.condition)) {
774
+ if (AbilityCondition_1.default.more_than.isEqual(this.condition)) {
500
775
  is = Number(valueS) > Number(valueO);
501
776
  }
502
- if (AbilityCondition_1.default.MORE_OR_EQUAL.isEqual(this.condition)) {
777
+ if (AbilityCondition_1.default.more_or_equal.isEqual(this.condition)) {
503
778
  is = Number(valueS) >= Number(valueO);
504
779
  }
505
- if (AbilityCondition_1.default.EQUAL.isEqual(this.condition)) {
780
+ if (AbilityCondition_1.default.equal.isEqual(this.condition)) {
506
781
  is = valueS === valueO;
507
782
  }
508
- if (AbilityCondition_1.default.NOT_EQUAL.isEqual(this.condition)) {
783
+ if (AbilityCondition_1.default.not_equal.isEqual(this.condition)) {
509
784
  is = valueS !== valueO;
510
785
  }
511
- if (AbilityCondition_1.default.IN.isEqual(this.condition)) {
786
+ if (AbilityCondition_1.default.in.isEqual(this.condition)) {
512
787
  // [<some>] and [<some>]
513
788
  if (Array.isArray(valueS) && Array.isArray(valueO)) {
514
789
  is = valueS.some(v => valueO.find(v1 => v1 === v));
@@ -522,7 +797,7 @@ class AbilityRule {
522
797
  is = valueS.includes(valueO);
523
798
  }
524
799
  }
525
- if (AbilityCondition_1.default.NOT_IN.isEqual(this.condition)) {
800
+ if (AbilityCondition_1.default.not_in.isEqual(this.condition)) {
526
801
  // [<some>] and [<some>]
527
802
  if (Array.isArray(valueS) && Array.isArray(valueO)) {
528
803
  is = !valueS.some(v => valueO.find(v1 => v1 === v));
@@ -601,7 +876,7 @@ class AbilityRule {
601
876
  name,
602
877
  subject,
603
878
  resource,
604
- condition,
879
+ condition: new AbilityCondition_1.default(condition),
605
880
  });
606
881
  }
607
882
  /**
@@ -616,6 +891,62 @@ class AbilityRule {
616
891
  condition: this.condition.code,
617
892
  };
618
893
  }
894
+ static equal(subject, resource) {
895
+ return new AbilityRule({
896
+ condition: AbilityCondition_1.default.equal,
897
+ subject,
898
+ resource,
899
+ });
900
+ }
901
+ static notIn(subject, resource) {
902
+ return new AbilityRule({
903
+ condition: AbilityCondition_1.default.not_in,
904
+ subject,
905
+ resource,
906
+ });
907
+ }
908
+ static in(subject, resource) {
909
+ return new AbilityRule({
910
+ condition: AbilityCondition_1.default.in,
911
+ subject,
912
+ resource,
913
+ });
914
+ }
915
+ static notEqual(subject, resource) {
916
+ return new AbilityRule({
917
+ condition: AbilityCondition_1.default.not_equal,
918
+ subject,
919
+ resource,
920
+ });
921
+ }
922
+ static lessThan(subject, resource) {
923
+ return new AbilityRule({
924
+ condition: AbilityCondition_1.default.less_than,
925
+ subject,
926
+ resource,
927
+ });
928
+ }
929
+ static lessOrEqual(subject, resource) {
930
+ return new AbilityRule({
931
+ condition: AbilityCondition_1.default.less_or_equal,
932
+ subject,
933
+ resource,
934
+ });
935
+ }
936
+ static moreThan(subject, resource) {
937
+ return new AbilityRule({
938
+ condition: AbilityCondition_1.default.more_than,
939
+ subject,
940
+ resource,
941
+ });
942
+ }
943
+ static moreOrEqual(subject, resource) {
944
+ return new AbilityRule({
945
+ condition: AbilityCondition_1.default.more_or_equal,
946
+ subject,
947
+ resource,
948
+ });
949
+ }
619
950
  }
620
951
  exports.AbilityRule = AbilityRule;
621
952
  exports["default"] = AbilityRule;
@@ -658,18 +989,16 @@ class AbilityRuleSet {
658
989
  id;
659
990
  constructor(params) {
660
991
  const { name, id, compareMethod } = params;
661
- this.name = name;
662
- this.id = id;
663
- this.compareMethod = AbilityCompare_1.default.fromLiteral(compareMethod);
664
- // this.compareMethod = new AbilityCompare(compareMethod);
992
+ this.name = name || 'No name';
993
+ this.id = id || this.name;
994
+ this.compareMethod = compareMethod;
665
995
  }
666
- addRule(rule, compareMethod) {
996
+ addRule(rule) {
667
997
  this.rules.push(rule);
668
- this.compareMethod = compareMethod;
669
998
  return this;
670
999
  }
671
- addRules(rules, compareMethod) {
672
- rules.forEach(rule => this.addRule(rule, compareMethod));
1000
+ addRules(rules) {
1001
+ rules.forEach(rule => this.addRule(rule));
673
1002
  return this;
674
1003
  }
675
1004
  check(resources) {
@@ -698,14 +1027,14 @@ class AbilityRuleSet {
698
1027
  static parse(config) {
699
1028
  const { id, name, rules, compareMethod } = config;
700
1029
  const ruleSet = new AbilityRuleSet({
701
- compareMethod,
1030
+ compareMethod: new AbilityCompare_1.default(compareMethod),
702
1031
  name,
703
1032
  id,
704
1033
  });
705
1034
  // Adding rules if exists
706
1035
  if (rules && rules.length > 0) {
707
1036
  const abilityRules = rules.map(ruleConfig => AbilityRule_1.default.parse(ruleConfig));
708
- ruleSet.addRules(abilityRules, ruleSet.compareMethod);
1037
+ ruleSet.addRules(abilityRules);
709
1038
  }
710
1039
  return ruleSet;
711
1040
  }
@@ -717,6 +1046,16 @@ class AbilityRuleSet {
717
1046
  rules: this.rules.map(rule => rule.export()),
718
1047
  };
719
1048
  }
1049
+ static and(rules) {
1050
+ return new AbilityRuleSet({
1051
+ compareMethod: AbilityCompare_1.default.and,
1052
+ }).addRules(rules);
1053
+ }
1054
+ static or(rules) {
1055
+ return new AbilityRuleSet({
1056
+ compareMethod: AbilityCompare_1.default.or,
1057
+ }).addRules(rules);
1058
+ }
720
1059
  }
721
1060
  exports.AbilityRuleSet = AbilityRuleSet;
722
1061
  exports["default"] = AbilityRuleSet;
@@ -754,6 +1093,7 @@ __exportStar(__webpack_require__(277), exports);
754
1093
  __exportStar(__webpack_require__(668), exports);
755
1094
  __exportStar(__webpack_require__(476), exports);
756
1095
  __exportStar(__webpack_require__(402), exports);
1096
+ __exportStar(__webpack_require__(363), exports);
757
1097
 
758
1098
 
759
1099
  /***/ })