@via-profit/ability 3.4.1 → 3.5.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/README.md CHANGED
@@ -385,7 +385,7 @@ deny permission.order.update
385
385
  const policies = new AbilityDSLParser(dsl).parse();
386
386
  const resolver = new AbilityResolver(policies);
387
387
 
388
- await resolver.enforce('order.update', resource); // will throw AbilityError
388
+ resolver.enforce('order.update', resource); // will throw AbilityError
389
389
  ```
390
390
 
391
391
  **Explanation**
@@ -669,7 +669,7 @@ const environment = {
669
669
  ip: req.ip,
670
670
  }
671
671
 
672
- await resolver.enforce('order.update', resource, environment);
672
+ resolver.enforce('order.update', resource, environment);
673
673
  ```
674
674
 
675
675
  ### Using environment in rules
@@ -797,7 +797,7 @@ export type Resources = {
797
797
  ```ts
798
798
  import { policyResolver } from './policies';
799
799
 
800
- await resolver.enforce('order.update', {
800
+ resolver.enforce('order.update', {
801
801
  user: { id: 'u1' },
802
802
  order: { ownerId: 'u1' },
803
803
  });
@@ -818,7 +818,7 @@ To simplify policy debugging, a special `AbilityResult` class is used, which is
818
818
  Example:
819
819
 
820
820
  ```ts
821
- const result = await resolver.resolve('order.update', resource);
821
+ const result = resolver.resolve('order.update', resource);
822
822
 
823
823
  if (result.isDenied()) {
824
824
  console.log('Access denied');
@@ -841,7 +841,7 @@ const explanations = result.explain(); // AbilityExplain
841
841
  Usage example:
842
842
 
843
843
  ```ts
844
- const result = await resolver.resolve('order.update', resource);
844
+ const result = resolver.resolve('order.update', resource);
845
845
  const explanations = result.explain();
846
846
 
847
847
  console.log(explanations.toString());
@@ -881,7 +881,7 @@ deny permission.test if all:
881
881
  const policies = new AbilityDSLParser(dsl).parse();
882
882
  const resolver = new AbilityResolver(policies);
883
883
 
884
- const result = await resolver.resolve('test', {
884
+ const result = resolver.resolve('test', {
885
885
  user: { age: 16 },
886
886
  });
887
887
 
@@ -895,7 +895,7 @@ the condition is met → the policy matches → effect `deny` → access denied.
895
895
  **What happens if the conditions are *not met*?**
896
896
 
897
897
  ```ts
898
- const result = await resolver.resolve('test', {
898
+ const result = resolver.resolve('test', {
899
899
  user: { age: 12 },
900
900
  });
901
901
 
@@ -984,7 +984,7 @@ export function useAbility<Permission extends keyof Resources>(
984
984
 
985
985
  async function check() {
986
986
  try {
987
- const result = await resolver.resolve(permission, resource);
987
+ const result = resolver.resolve(permission, resource);
988
988
  if (!cancelled) {
989
989
  setAllowed(result.isAllowed());
990
990
  }
@@ -1224,7 +1224,7 @@ Example: buying a ticket.
1224
1224
  The `enforce` method throws an `AbilityError` if access is denied.
1225
1225
 
1226
1226
  ```ts
1227
- await resolver.enforce('ticket.buy', {
1227
+ resolver.enforce('ticket.buy', {
1228
1228
  user: { age: 25, ticketsCount: 1 },
1229
1229
  env: { time: { hour: 18 } },
1230
1230
  });
@@ -1237,7 +1237,7 @@ If denied — an `AbilityError` exception is thrown.
1237
1237
  `resolve` returns a result object:
1238
1238
 
1239
1239
  ```ts
1240
- const result = await resolver.resolve('ticket.buy', {
1240
+ const result = resolver.resolve('ticket.buy', {
1241
1241
  user: { age: 25, ticketsCount: 1 },
1242
1242
  env: { time: { hour: 18 } },
1243
1243
  });
@@ -1252,7 +1252,7 @@ if (result.isAllowed()) {
1252
1252
  **Seller can only sell during working hours**
1253
1253
 
1254
1254
  ```ts
1255
- await resolver.enforce('ticket.sell', {
1255
+ resolver.enforce('ticket.sell', {
1256
1256
  user: { role: 'seller' },
1257
1257
  env: { time: { hour: 15 } },
1258
1258
  ticket: { status: 'available' },
package/dist/index.d.ts CHANGED
@@ -1,19 +1,574 @@
1
- export * from './core/AbilityCode';
2
- export * from './core/AbilityCompare';
3
- export * from './core/AbilityCondition';
4
- export * from './core/AbilityError';
5
- export * from './core/AbilityMatch';
6
- export * from './core/AbilityTypeGenerator';
7
- export * from './core/AbilityPolicy';
8
- export * from './core/AbilityPolicyEffect';
9
- export * from './core/AbilityResolver';
10
- export * from './core/AbilityRule';
11
- export * from './core/AbilityRuleSet';
12
- export * from './core/AbilityExplain';
13
- export * from './core/AbilityResult';
14
- export * from './cache/AbilityCacheAdapter';
15
- export * from './cache/AbilityInMemoryCache';
16
- export * from './parsers/json/AbilityJSONParser';
17
- export * from './parsers/dsl/AbilityDSLParser';
18
- export * from './parsers/dsl/AbilityDSLLexer';
19
- export * from './parsers/dsl/AbilityDSLToken';
1
+ declare class AbilityCode<Code extends string | number> {
2
+ _code: Code;
3
+ constructor(code: Code);
4
+ get code(): Code;
5
+ isEqual(compareWith: AbilityCode<Code> | null): boolean;
6
+ isNotEqual(compareWith: AbilityCode<Code> | null): boolean;
7
+ }
8
+
9
+ type AbilityCompareCodeType = 'and' | 'or';
10
+ declare class AbilityCompare extends AbilityCode<AbilityCompareCodeType> {
11
+ static and: AbilityCompare;
12
+ static or: AbilityCompare;
13
+ }
14
+
15
+ type AbilityConditionCodeType = '=' | '<>' | '>' | '<' | '>=' | '<=' | 'in' | 'not in' | 'contains' | 'not contains' | 'length greater than' | 'length less than' | 'length equals' | 'always' | 'never';
16
+ type AbilityConditionLiteralType = 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'in' | 'not_in' | 'greater_than' | 'less_than' | 'less_or_equal' | 'greater_or_equal' | 'length_greater_than' | 'length_less_than' | 'length_equals' | 'always' | 'never';
17
+ declare class AbilityCondition extends AbilityCode<AbilityConditionCodeType> {
18
+ static equals: AbilityCondition;
19
+ static not_equals: AbilityCondition;
20
+ static greater_than: AbilityCondition;
21
+ static less_than: AbilityCondition;
22
+ static less_or_equal: AbilityCondition;
23
+ static greater_or_equal: AbilityCondition;
24
+ static in: AbilityCondition;
25
+ static not_in: AbilityCondition;
26
+ static contains: AbilityCondition;
27
+ static not_contains: AbilityCondition;
28
+ static length_greater_than: AbilityCondition;
29
+ static length_less_than: AbilityCondition;
30
+ static length_equals: AbilityCondition;
31
+ static always: AbilityCondition;
32
+ static never: AbilityCondition;
33
+ static fromLiteral(literal: AbilityConditionLiteralType): AbilityCondition;
34
+ get literal(): AbilityConditionLiteralType;
35
+ }
36
+
37
+ declare class AbilityError extends Error {
38
+ constructor(message: string, options?: ErrorOptions);
39
+ }
40
+ declare class AbilityParserError extends Error {
41
+ constructor(message: string, options?: ErrorOptions);
42
+ }
43
+
44
+ type AbilityMatchCodeType = 'pending' | 'match' | 'mismatch';
45
+ declare class AbilityMatch extends AbilityCode<AbilityMatchCodeType> {
46
+ static pending: AbilityMatch;
47
+ static match: AbilityMatch;
48
+ static mismatch: AbilityMatch;
49
+ }
50
+
51
+ type AbilityRuleConfig = {
52
+ readonly id?: string | null;
53
+ readonly name?: string | null;
54
+ /**
55
+ * Subject key path like a 'user.name'
56
+ */
57
+ readonly subject: string;
58
+ /**
59
+ * Resource key path like a 'user.name' or value
60
+ */
61
+ readonly resource: string | number | boolean | null | (string | number | boolean | null)[];
62
+ readonly condition: AbilityConditionCodeType;
63
+ };
64
+ type AbilityRuleConstructorProps = Omit<AbilityRuleConfig, 'condition'> & {
65
+ readonly condition: AbilityCondition;
66
+ };
67
+ /**
68
+ * Represents a rule that defines a condition to be checked against a subject and resource.
69
+ */
70
+ declare class AbilityRule<Resources extends object = object, Environment = unknown> {
71
+ /**
72
+ * Subject key path like a 'user.name'
73
+ */
74
+ subject: string;
75
+ /**
76
+ * Resource key path like a 'user.name' or value
77
+ */
78
+ resource: AbilityRuleConfig['resource'];
79
+ condition: AbilityCondition;
80
+ name: string;
81
+ id: string;
82
+ state: AbilityMatch;
83
+ /**
84
+ * Creates an instance of AbilityRule.
85
+ * @param {string} params.id - The unique identifier of the rule.
86
+ * @param {string} params.name - The name of the rule.
87
+ * @param {AbilityCondition} params.condition - The condition to evaluate.
88
+ * @param {string} params.subject - The subject of the rule.
89
+ * @param {string} params.resource - The resource to compare against.
90
+ * @param params
91
+ */
92
+ constructor(params: AbilityRuleConstructorProps);
93
+ private isPrimitive;
94
+ private isNumber;
95
+ private isString;
96
+ private valueLen;
97
+ private operatorHandlers;
98
+ /**
99
+ * Check if the rule is matched
100
+ * @param resource - The resource to check
101
+ * @param environment
102
+ */
103
+ check(resource: Resources | null, environment?: Environment): AbilityMatch;
104
+ /**
105
+ * Extract values from the resourceData
106
+ * @param resourceData - The resourceData to extract values from
107
+ * @param environment - Environment data
108
+ */
109
+ extractValues(resourceData: Resources | null, environment?: Environment | null): [AbilityRuleConfig['resource'] | undefined, AbilityRuleConfig['resource'] | undefined];
110
+ /**
111
+ * Get the value of the object by dot notation
112
+ * @param resource - The object to get the value from
113
+ * @param desc - The dot notation string
114
+ */
115
+ getDotNotationValue<T = unknown>(resource: unknown, desc: string): T | undefined;
116
+ toString(): string;
117
+ copyWith(props: Partial<{
118
+ id: string | null;
119
+ name: string | null;
120
+ subject: string;
121
+ resource: AbilityRuleConfig['resource'];
122
+ condition: AbilityCondition;
123
+ }>): AbilityRule<Resources, Environment>;
124
+ static equals<Resources extends object = object, Environment = unknown>(subject: string, resource: AbilityRuleConfig['resource']): AbilityRule<Resources, Environment>;
125
+ static notEquals<Resources extends object = object, Environment = unknown>(subject: string, resource: AbilityRuleConfig['resource']): AbilityRule<Resources, Environment>;
126
+ static contains<Resources extends object = object, Environment = unknown>(subject: string, resource: AbilityRuleConfig['resource']): AbilityRule<Resources, Environment>;
127
+ static notContains<Resources extends object = object, Environment = unknown>(subject: string, resource: AbilityRuleConfig['resource']): AbilityRule<Resources, Environment>;
128
+ static notIn<Resources extends object = object, Environment = unknown>(subject: string, resource: AbilityRuleConfig['resource']): AbilityRule<Resources, Environment>;
129
+ static in<Resources extends object = object, Environment = unknown>(subject: string, resource: AbilityRuleConfig['resource']): AbilityRule<Resources, Environment>;
130
+ static notEqual<Resources extends object = object, Environment = unknown>(subject: string, resource: AbilityRuleConfig['resource']): AbilityRule<Resources, Environment>;
131
+ static lessThan<Resources extends object = object, Environment = unknown>(subject: string, resource: AbilityRuleConfig['resource']): AbilityRule<Resources, Environment>;
132
+ static lessOrEqual<Resources extends object = object, Environment = unknown>(subject: string, resource: AbilityRuleConfig['resource']): AbilityRule<Resources, Environment>;
133
+ static moreThan<Resources extends object = object, Environment = unknown>(subject: string, resource: AbilityRuleConfig['resource']): AbilityRule<Resources, Environment>;
134
+ static moreOrEqual<Resources extends object = object, Environment = unknown>(subject: string, resource: AbilityRuleConfig['resource']): AbilityRule<Resources, Environment>;
135
+ }
136
+
137
+ type AbilityRuleSetConfig = {
138
+ readonly id?: string | null;
139
+ readonly name?: string | null;
140
+ readonly compareMethod: AbilityCompareCodeType;
141
+ readonly rules: readonly AbilityRuleConfig[];
142
+ };
143
+ type AbilityRuleSetConstructorProps = {
144
+ readonly id?: string | null;
145
+ readonly name?: string | null;
146
+ readonly compareMethod: AbilityCompare;
147
+ };
148
+ declare class AbilityRuleSet<Resources extends ResourceObject = Record<string, unknown>, Environment = unknown> {
149
+ state: AbilityMatch;
150
+ /**
151
+ * List of rules
152
+ */
153
+ rules: AbilityRule<Resources, Environment>[];
154
+ /**
155
+ * Rules compare method.\
156
+ * For the «and» method the rule will be permitted if all\
157
+ * rules will be returns «permit» status and for the «or» - if\
158
+ * one of the rules returns as «permit»
159
+ */
160
+ compareMethod: AbilityCompare;
161
+ /**
162
+ * Group name
163
+ */
164
+ name: string;
165
+ /**
166
+ * Group ID
167
+ */
168
+ id: string;
169
+ constructor(params: AbilityRuleSetConstructorProps);
170
+ addRule(rule: AbilityRule<Resources, Environment>): this;
171
+ addRules(rules: AbilityRule<Resources, Environment>[]): this;
172
+ check(resources: Resources | null, environment?: Environment): AbilityMatch;
173
+ toString(): string;
174
+ copyWith(props: Partial<{
175
+ id: string | null;
176
+ name: string | null;
177
+ compareMethod: AbilityCompare;
178
+ rules: AbilityRule<Resources, Environment>[];
179
+ }>): AbilityRuleSet<Resources, Environment>;
180
+ static and(rules: AbilityRule[]): AbilityRuleSet<Record<string, unknown>, unknown>;
181
+ static or(rules: AbilityRule[]): AbilityRuleSet<Record<string, unknown>, unknown>;
182
+ }
183
+
184
+ type AbilityPolicyEffectCodeType = 'deny' | 'permit';
185
+ declare class AbilityPolicyEffect extends AbilityCode<AbilityPolicyEffectCodeType> {
186
+ static deny: AbilityPolicyEffect;
187
+ static permit: AbilityPolicyEffect;
188
+ }
189
+
190
+ type AbilityExplainConfig = {
191
+ readonly type: AbilityExplainType;
192
+ readonly name: string;
193
+ readonly match: AbilityMatch;
194
+ };
195
+ declare class AbilityExplain {
196
+ readonly type: AbilityExplainType;
197
+ readonly children: AbilityExplain[];
198
+ readonly name: string;
199
+ readonly match: AbilityMatch;
200
+ constructor(config: AbilityExplainConfig, children?: AbilityExplain[]);
201
+ toString(indent?: number): string;
202
+ }
203
+ declare class AbilityExplainRule extends AbilityExplain {
204
+ constructor(rule: AbilityRule);
205
+ }
206
+ declare class AbilityExplainRuleSet extends AbilityExplain {
207
+ constructor(ruleSet: AbilityRuleSet);
208
+ }
209
+ declare class AbilityExplainPolicy extends AbilityExplain {
210
+ constructor(policy: AbilityPolicy);
211
+ }
212
+ type AbilityExplainType = 'policy' | 'rule' | 'ruleSet';
213
+
214
+ type AbilityPolicyConfig = {
215
+ readonly permission: string;
216
+ readonly effect: AbilityPolicyEffectCodeType;
217
+ readonly compareMethod: AbilityCompareCodeType;
218
+ readonly ruleSet: readonly AbilityRuleSetConfig[];
219
+ readonly id: string;
220
+ readonly name: string;
221
+ };
222
+ type AbilityPolicyConstructorProps = {
223
+ id: string;
224
+ name: string;
225
+ permission: string;
226
+ effect: AbilityPolicyEffect;
227
+ compareMethod?: AbilityCompare;
228
+ };
229
+ declare class AbilityPolicy<Resource extends ResourceObject = Record<string, unknown>, Environment = unknown> {
230
+ matchState: AbilityMatch;
231
+ /**
232
+ * List of rules
233
+ */
234
+ ruleSet: AbilityRuleSet<Resource, Environment>[];
235
+ /**
236
+ * Policy effect
237
+ */
238
+ effect: AbilityPolicyEffect;
239
+ /**
240
+ * Rules compare method.\
241
+ * For the «and» method the rule will be permitted if all\
242
+ * rules will be returns «permit» status and for the «or» - if\
243
+ * one of the rules returns as «permit»
244
+ */
245
+ compareMethod: AbilityCompare;
246
+ /**
247
+ * Policy name
248
+ */
249
+ name: string;
250
+ /**
251
+ * Policy ID
252
+ */
253
+ id: string;
254
+ /**
255
+ * Running the `enforce` or `resolve` method
256
+ * will select only those from all passed policies that fall under the specified permission key.
257
+ */
258
+ permission: string;
259
+ constructor(params: AbilityPolicyConstructorProps);
260
+ /**
261
+ * Add rule set to the policy
262
+ * @param ruleSet - The rule set to add
263
+ */
264
+ addRuleSet(ruleSet: AbilityRuleSet<Resource, Environment>): this;
265
+ /**
266
+ * Add rule set to the policy
267
+ * @param ruleSets - The array of rule set to add
268
+ */
269
+ addRuleSets(ruleSets: readonly AbilityRuleSet<Resource, Environment>[]): this;
270
+ /**
271
+ * Check if the policy is matched
272
+ * @param resource - The resource to check
273
+ * @param environment - The user environment object
274
+ */
275
+ check(resource: Resource, environment?: Environment): AbilityMatch;
276
+ explain(): AbilityExplain;
277
+ copyWith(props: Partial<{
278
+ id: string;
279
+ name: string;
280
+ permission: string;
281
+ effect: AbilityPolicyEffect;
282
+ compareMethod: AbilityCompare;
283
+ ruleSet: AbilityRuleSet<Resource, Environment>[];
284
+ }>): AbilityPolicy<Resource, Environment>;
285
+ }
286
+
287
+ type Primitive = string | number | boolean | null | undefined;
288
+ type NestedDict<T = Primitive> = {
289
+ [key: string]: NestedDict<T> | T;
290
+ };
291
+ type ResourceObject = Record<string, unknown>;
292
+ type ResourcesMap = Record<string, ResourceObject>;
293
+ declare class AbilityTypeGenerator {
294
+ readonly policies: readonly AbilityPolicy[];
295
+ constructor(policies: readonly AbilityPolicy[]);
296
+ /**
297
+ * Generates TypeScript type definitions based on the provided policies.
298
+ * @returns A generated type definitions.
299
+ */
300
+ generateTypeDefs(): string;
301
+ /**
302
+ * Determines TypeScript type based on the rule
303
+ * @param rule - The rule to analyze
304
+ * @returns TypeScript type as string
305
+ */
306
+ private determineTypeFromRule;
307
+ /**
308
+ * Gets TypeScript type for array values
309
+ * @param resource - The resource value to analyze
310
+ * @returns TypeScript array type as string
311
+ */
312
+ private getArrayType;
313
+ /**
314
+ * Gets primitive TypeScript type for a value
315
+ * @param value - The value to analyze
316
+ * @returns TypeScript primitive type as string
317
+ */
318
+ private getPrimitiveType;
319
+ /**
320
+ * Builds nested structure from flat paths
321
+ * Example: 'user.profile.name' -> { user: { profile: { name: 'string' } } }
322
+ * @param flatStructure - Flat structure with dot notation paths
323
+ * @returns Nested object structure
324
+ */
325
+ private buildNestedStructure;
326
+ /**
327
+ * Formats type structure into a string
328
+ * @param structure - Nested type structure
329
+ * @returns Formatted TypeScript type definition string
330
+ */
331
+ private formatTypeDefinitions;
332
+ /**
333
+ * Recursively formats nested object
334
+ * @param obj - Object to format
335
+ * @param indent - Current indentation level
336
+ * @returns Formatted string
337
+ */
338
+ private formatNestedObject;
339
+ }
340
+
341
+ declare class AbilityResult<Resource extends ResourceObject = Record<string, unknown>> {
342
+ /**
343
+ * Already checked policies (after call the policy.check())
344
+ */
345
+ readonly policies: readonly AbilityPolicy<Resource>[];
346
+ constructor(policies: readonly AbilityPolicy<Resource>[]);
347
+ /**
348
+ * Returns a list of explanations for each policy involved in the ability evaluation.
349
+ * Each item describes how a specific policy contributed to the final permission result.
350
+ *
351
+ * Useful for debugging, logging, or building UI tools that visualize permission logic.
352
+ */
353
+ explain(): readonly AbilityExplain[];
354
+ getLastMatchedPolicy(): AbilityPolicy<Resource> | null;
355
+ isAllowed(): boolean;
356
+ isDenied(): boolean;
357
+ /**
358
+ * Get the last effect of the policy
359
+ *
360
+ * @returns {AbilityPolicyEffect | null}
361
+ */
362
+ getLastEffectOfMatchedPolicy(): AbilityPolicyEffect | null;
363
+ }
364
+
365
+ declare class AbilityResolver<Resources extends ResourcesMap, Environment = unknown> {
366
+ private policies;
367
+ constructor(
368
+ /**
369
+ * `Important!` The incorrect Resources type was intentionally passed to AbilityPolicy so that TypeScript could suggest the name of the permission and the structure of its resource in the parse method.
370
+ */
371
+ policyOrListOfPolicies: readonly AbilityPolicy<Resources>[] | AbilityPolicy<Resources>);
372
+ /**
373
+ * Resolve policy for the resource and permission key
374
+ *
375
+ * @param permission - Permission key
376
+ * @param resource - Resource
377
+ * @param environment
378
+ */
379
+ resolve<Permission extends keyof Resources>(permission: Permission, resource: Resources[Permission], environment?: Environment): AbilityResult<Resources[Permission]>;
380
+ enforce<Permission extends keyof Resources>(permission: Permission, resource: Resources[Permission], environment?: Environment): void | never;
381
+ /**
382
+ * Check if the permission key is contained in another permission key
383
+ * @param permissionA - The first permission to check
384
+ * @param permissionB - The second permission to check
385
+ */
386
+ static isInPermissionContain(permissionA: string, permissionB: string): boolean;
387
+ }
388
+
389
+ declare class AbilityJSONParser {
390
+ /**
391
+ * Parses an array of policy configurations into an array of AbilityPolicy instances.
392
+ * @param configs - Array of policy configurations
393
+ * @returns Array of AbilityPolicy instances
394
+ */
395
+ static parse<Resource extends ResourceObject, Environment = unknown>(configs: readonly AbilityPolicyConfig[]): AbilityPolicy<Resource, Environment>[];
396
+ static parsePolicy<Resource extends ResourceObject = Record<string, unknown>, Environment = unknown>(config: AbilityPolicyConfig): AbilityPolicy<Resource, Environment>;
397
+ static parseRule<Resources extends object, Environment = unknown>(config: AbilityRuleConfig): AbilityRule<Resources, Environment>;
398
+ /**
399
+ * Parse the config JSON format to Group class instance
400
+ */
401
+ static parseRuleSet<Resource extends ResourceObject = Record<string, unknown>, Environment = unknown>(config: AbilityRuleSetConfig): AbilityRuleSet<Resource, Environment>;
402
+ static ruleToJSON(rule: AbilityRule): AbilityRuleConfig;
403
+ static ruleSetToJSON(ruleSet: AbilityRuleSet): AbilityRuleSetConfig;
404
+ static policyToJSON(policy: AbilityPolicy): AbilityPolicyConfig;
405
+ static toJSON(policies: readonly AbilityPolicy[]): AbilityPolicyConfig[];
406
+ }
407
+
408
+ /**
409
+ * Parser for the Ability DSL.
410
+ *
411
+ * Converts a DSL string into one or more AbilityPolicy instances.
412
+ * The grammar follows the structure:
413
+ *
414
+ * <effect> <permission> if <group> [ <group> ... ]
415
+ *
416
+ * where <group> is either "all of:" or "any of:", followed by a colon,
417
+ * and then a list of rules (one per line).
418
+ *
419
+ * Each rule is: <identifier> <operator> <value>
420
+ *
421
+ * Operators can be simple (equals, contains, in) or
422
+ * composed (is null, is not null, greater than, less than or equal, etc.).
423
+ */
424
+ declare class AbilityDSLParser<Resource extends ResourceObject = Record<string, unknown>, Environment = unknown> {
425
+ private dsl;
426
+ private tokens;
427
+ private pos;
428
+ private annotationBuffer;
429
+ constructor(dsl: string);
430
+ /**
431
+ * Main entry point: tokenize the input and parse all policies.
432
+ * @returns Array of AbilityPolicy instances.
433
+ */
434
+ parse(): readonly AbilityPolicy<Resource, Environment>[];
435
+ /**
436
+ * Parses a single policy from the current token position.
437
+ *
438
+ * Grammar:
439
+ * policy = EFFECT PERMISSION IF (ALL | ANY) COLON ruleSets
440
+ */
441
+ private parsePolicy;
442
+ /**
443
+ * Parses a sequence of rule sets (groups) until a new policy starts or EOF.
444
+ */
445
+ private parseRuleSets;
446
+ /**
447
+ * Parses a single group, e.g. "all of:" or "any of:", and returns a RuleSet.
448
+ */
449
+ private parseGroup;
450
+ /**
451
+ * Parses a single rule: subject operator value
452
+ */
453
+ private parseRule;
454
+ /**
455
+ * Parses the comparison operator part of a rule.
456
+ * Returns both the resulting AbilityCondition and the token type that was consumed.
457
+ */
458
+ private parseConditionOperator;
459
+ /**
460
+ * Helper to match and consume a specific word token (KEYWORD or IDENTIFIER).
461
+ * @param word The exact string to look for.
462
+ * @returns True if the next token has that value.
463
+ */
464
+ private matchWord;
465
+ private matchSymbol;
466
+ /**
467
+ * Parses a resource value. Can be a string literal, number, boolean,
468
+ * null, a path (identifier), or an array.
469
+ */
470
+ private parseValue;
471
+ /**
472
+ * Parses an array literal: [ <value>, <value>, ... ]
473
+ * The opening bracket has already been consumed.
474
+ */
475
+ private parseArray;
476
+ private consumeLeadingComments;
477
+ private processCommentToken;
478
+ private takeAnnotations;
479
+ private syntaxError;
480
+ private suggest;
481
+ private levenshteinDistance;
482
+ private consumeOneOf;
483
+ private consume;
484
+ private check;
485
+ private isStartOfPolicy;
486
+ private isStartOfGroup;
487
+ private advance;
488
+ private peek;
489
+ private isAtEnd;
490
+ }
491
+
492
+ type TokenType = 'EFFECT' | 'IF' | 'PERMISSION' | 'IDENTIFIER' | 'COLON' | 'COMMA' | 'DOT' | 'LBRACKET' | 'RBRACKET' | 'ALL' | 'ANY' | 'OF' | 'EOF' | 'COMMENT' | 'EQ' | 'CONTAINS' | 'IN' | 'NOT_IN' | 'NOT_CONTAINS' | 'GT' | 'GTE' | 'LT' | 'LTE' | 'NULL' | 'EQ_NULL' | 'NOT_EQ_NULL' | 'NOT_EQ' | 'LEN_GT' | 'LEN_LT' | 'LEN_EQ' | 'ALWAYS' | 'NEVER' | 'STRING' | 'NUMBER' | 'BOOLEAN' | 'SYMBOL' | 'KEYWORD' | 'UNKNOWN';
493
+ /**
494
+ * Represents a single token produced by the Ability DSL lexer.
495
+ * Each token carries a type (e.g., EFFECT, IDENTIFIER, STRING) and its raw string value.
496
+ */
497
+ declare class AbilityDSLToken<Code extends TokenType = TokenType> extends AbilityCode<Code> {
498
+ /** The literal text of the token as it appeared in the input (e.g., "permit", "user.roles", "admin"). */
499
+ readonly value: string;
500
+ /** The line number in DSL */
501
+ readonly line: number;
502
+ /** The column in dsl */
503
+ readonly column: number;
504
+ constructor(type: Code, value: string, line: number, column: number);
505
+ /**
506
+ * Returns a human-readable representation of the token, useful for debugging.
507
+ * Example output: "AbilityDSLToken([EFFECT] permit"
508
+ */
509
+ toString(): string;
510
+ static readonly EFFECT: TokenType;
511
+ static readonly IF: TokenType;
512
+ static readonly PERMISSION: TokenType;
513
+ static readonly IDENTIFIER: TokenType;
514
+ static readonly COLON: TokenType;
515
+ static readonly COMMA: TokenType;
516
+ static readonly DOT: TokenType;
517
+ static readonly LBRACKET: TokenType;
518
+ static readonly RBRACKET: TokenType;
519
+ static readonly ALL: TokenType;
520
+ static readonly ANY: TokenType;
521
+ static readonly OF: TokenType;
522
+ static readonly EOF: TokenType;
523
+ static readonly COMMENT: TokenType;
524
+ static readonly EQ: TokenType;
525
+ static readonly CONTAINS: TokenType;
526
+ static readonly IN: TokenType;
527
+ static readonly NOT_IN: TokenType;
528
+ static readonly NOT_CONTAINS: TokenType;
529
+ static readonly GT: TokenType;
530
+ static readonly GTE: TokenType;
531
+ static readonly LT: TokenType;
532
+ static readonly LTE: TokenType;
533
+ static readonly NULL: TokenType;
534
+ static readonly EQ_NULL: TokenType;
535
+ static readonly NOT_EQ_NULL: TokenType;
536
+ static readonly LEN_GT: TokenType;
537
+ static readonly LEN_LT: TokenType;
538
+ static readonly LEN_EQ: TokenType;
539
+ static readonly NOT_EQ: TokenType;
540
+ static readonly ALWAYS: TokenType;
541
+ static readonly NEVER: TokenType;
542
+ static readonly STRING: TokenType;
543
+ static readonly NUMBER: TokenType;
544
+ static readonly BOOLEAN: TokenType;
545
+ static readonly SYMBOL: TokenType;
546
+ static readonly KEYWORD: TokenType;
547
+ }
548
+
549
+ declare class AbilityDSLLexer {
550
+ private readonly input;
551
+ private pos;
552
+ private tokens;
553
+ private line;
554
+ private column;
555
+ private readonly keywords;
556
+ constructor(input: string);
557
+ tokenize(): AbilityDSLToken[];
558
+ private readComment;
559
+ private readString;
560
+ private readNumber;
561
+ private readSymbol;
562
+ private readWord;
563
+ private skipWhitespace;
564
+ private isDigit;
565
+ private isAlpha;
566
+ private isSymbol;
567
+ private isNewline;
568
+ private peek;
569
+ private advance;
570
+ private isAtEnd;
571
+ }
572
+
573
+ export { AbilityCode, AbilityCompare, AbilityCondition, AbilityDSLLexer, AbilityDSLParser, AbilityDSLToken, AbilityError, AbilityExplain, AbilityExplainPolicy, AbilityExplainRule, AbilityExplainRuleSet, AbilityJSONParser, AbilityMatch, AbilityParserError, AbilityPolicy, AbilityPolicyEffect, AbilityResolver, AbilityResult, AbilityRule, AbilityRuleSet, AbilityTypeGenerator };
574
+ export type { AbilityCompareCodeType, AbilityConditionCodeType, AbilityConditionLiteralType, AbilityExplainConfig, AbilityExplainType, AbilityMatchCodeType, AbilityPolicyConfig, AbilityPolicyConstructorProps, AbilityPolicyEffectCodeType, AbilityRuleConfig, AbilityRuleConstructorProps, AbilityRuleSetConfig, AbilityRuleSetConstructorProps, NestedDict, Primitive, ResourceObject, ResourcesMap, TokenType };