aws-iam-language-server 0.0.13 → 0.0.15

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.
Files changed (54) hide show
  1. package/package.json +1 -1
  2. package/readme.md +12 -0
  3. package/src/handlers/completion/action-value.d.ts +2 -0
  4. package/src/handlers/completion/action-value.js +1 -1
  5. package/src/handlers/completion/condition-key.d.ts +2 -0
  6. package/src/handlers/completion/condition-key.js +3 -3
  7. package/src/handlers/completion/index.d.ts +2 -2
  8. package/src/handlers/completion/index.js +4 -4
  9. package/src/handlers/completion/principal-identifier-completions.d.ts +1 -1
  10. package/src/handlers/diagnostics/diagnostics.js +4 -2
  11. package/src/handlers/diagnostics/resource.js +4 -4
  12. package/src/handlers/diagnostics/sid.d.ts +1 -1
  13. package/src/handlers/diagnostics/sid.js +11 -2
  14. package/src/handlers/diagnostics/utils.js +1 -13
  15. package/src/handlers/document-link/document-link.js +1 -3
  16. package/src/handlers/hover/action-value.d.ts +3 -0
  17. package/src/handlers/hover/action-value.js +21 -0
  18. package/src/handlers/hover/condition-block.d.ts +3 -0
  19. package/src/handlers/hover/condition-block.js +18 -0
  20. package/src/handlers/hover/condition-key.d.ts +3 -0
  21. package/src/handlers/hover/condition-key.js +53 -0
  22. package/src/handlers/hover/condition-operator.d.ts +3 -0
  23. package/src/handlers/hover/condition-operator.js +14 -0
  24. package/src/handlers/hover/effect-value.d.ts +3 -0
  25. package/src/handlers/hover/effect-value.js +17 -0
  26. package/src/handlers/hover/index.d.ts +3 -0
  27. package/src/handlers/hover/index.js +69 -0
  28. package/src/handlers/hover/principal-block.d.ts +3 -0
  29. package/src/handlers/hover/principal-block.js +17 -0
  30. package/src/handlers/hover/principal-type.d.ts +3 -0
  31. package/src/handlers/hover/principal-type.js +25 -0
  32. package/src/handlers/hover/principal-typed-value.d.ts +3 -0
  33. package/src/handlers/hover/principal-typed-value.js +118 -0
  34. package/src/handlers/hover/principal-value.d.ts +3 -0
  35. package/src/handlers/hover/principal-value.js +13 -0
  36. package/src/handlers/hover/resource-value.d.ts +3 -0
  37. package/src/handlers/hover/resource-value.js +45 -0
  38. package/src/handlers/hover/statement-block.d.ts +3 -0
  39. package/src/handlers/hover/statement-block.js +14 -0
  40. package/src/handlers/hover/statement-key.d.ts +3 -0
  41. package/src/handlers/hover/statement-key.js +14 -0
  42. package/src/lib/iam-policy/arn.d.ts +17 -0
  43. package/src/lib/iam-policy/arn.js +77 -0
  44. package/src/lib/iam-policy/location.d.ts +31 -1
  45. package/src/lib/iam-policy/location.js +56 -19
  46. package/src/lib/iam-policy/reference/services.d.ts +5 -3
  47. package/src/lib/iam-policy/reference/services.js +58 -19
  48. package/src/lib/iam-policy/reference/types.d.ts +5 -0
  49. package/src/lib/treesitter/base.d.ts +3 -8
  50. package/src/lib/treesitter/base.js +3 -3
  51. package/src/lib/treesitter/hcl.js +32 -24
  52. package/src/lib/treesitter/json.js +14 -11
  53. package/src/lib/treesitter/yaml.js +30 -27
  54. package/src/server.js +5 -3
@@ -0,0 +1,118 @@
1
+ import { MarkupKind } from 'vscode-languageserver';
2
+ import { ServiceReference } from "../../lib/iam-policy/reference/services.js";
3
+ export function handlePrincipalTypedValueHover(location) {
4
+ if (location.value === '*') {
5
+ return {
6
+ range: location.range,
7
+ contents: {
8
+ kind: MarkupKind.Markdown,
9
+ value: '**All principals** of this type.',
10
+ },
11
+ };
12
+ }
13
+ const principalType = location.principalType;
14
+ if (principalType === 'Service') {
15
+ const principals = ServiceReference.getServicePrincipals();
16
+ if (principals.includes(location.value)) {
17
+ const serviceName = location.value.split('.')[0];
18
+ return {
19
+ range: location.range,
20
+ contents: {
21
+ kind: MarkupKind.Markdown,
22
+ value: `**AWS service principal**\n\n\`${location.value}\` — allows the \`${serviceName}\` service to assume this role or access this resource.`,
23
+ },
24
+ };
25
+ }
26
+ }
27
+ if (principalType === 'AWS') {
28
+ if (/^\d{12}$/.test(location.value)) {
29
+ return {
30
+ range: location.range,
31
+ contents: {
32
+ kind: MarkupKind.Markdown,
33
+ value: `**AWS account**\n\nGrants access to the root user and all IAM identities in account \`${location.value}\`.`,
34
+ },
35
+ };
36
+ }
37
+ if (location.value.startsWith('arn:')) {
38
+ const parts = location.value.split(':');
39
+ const resource = parts.slice(5).join(':');
40
+ if (resource.startsWith('root')) {
41
+ return {
42
+ range: location.range,
43
+ contents: {
44
+ kind: MarkupKind.Markdown,
45
+ value: `**AWS account root user**\n\nGrants access to the root user of this account. Equivalent to specifying the account ID.`,
46
+ },
47
+ };
48
+ }
49
+ if (resource.startsWith('role/')) {
50
+ return {
51
+ range: location.range,
52
+ contents: {
53
+ kind: MarkupKind.Markdown,
54
+ value: `**IAM role**\n\n\`${resource}\`\n\nAny identity that assumes this role will have the permissions granted by this statement.`,
55
+ },
56
+ };
57
+ }
58
+ if (resource.startsWith('user/')) {
59
+ return {
60
+ range: location.range,
61
+ contents: {
62
+ kind: MarkupKind.Markdown,
63
+ value: `**IAM user**\n\n\`${resource}\``,
64
+ },
65
+ };
66
+ }
67
+ if (resource.startsWith('assumed-role/')) {
68
+ return {
69
+ range: location.range,
70
+ contents: {
71
+ kind: MarkupKind.Markdown,
72
+ value: `**Assumed role session**\n\n\`${resource}\``,
73
+ },
74
+ };
75
+ }
76
+ }
77
+ }
78
+ if (principalType === 'Federated') {
79
+ if (location.value.startsWith('arn:')) {
80
+ const resource = location.value.split(':').slice(5).join(':');
81
+ if (resource.startsWith('oidc-provider/')) {
82
+ return {
83
+ range: location.range,
84
+ contents: {
85
+ kind: MarkupKind.Markdown,
86
+ value: `**OIDC identity provider**\n\n\`${resource}\``,
87
+ },
88
+ };
89
+ }
90
+ if (resource.startsWith('saml-provider/')) {
91
+ return {
92
+ range: location.range,
93
+ contents: {
94
+ kind: MarkupKind.Markdown,
95
+ value: `**SAML identity provider**\n\n\`${resource}\``,
96
+ },
97
+ };
98
+ }
99
+ }
100
+ const knownProviders = {
101
+ 'cognito-identity.amazonaws.com': 'Amazon Cognito identity pool',
102
+ 'www.amazon.com': 'Login with Amazon',
103
+ 'accounts.google.com': 'Google',
104
+ 'graph.facebook.com': 'Facebook',
105
+ };
106
+ const description = knownProviders[location.value];
107
+ if (description) {
108
+ return {
109
+ range: location.range,
110
+ contents: {
111
+ kind: MarkupKind.Markdown,
112
+ value: `**Federated identity provider**\n\n${description}`,
113
+ },
114
+ };
115
+ }
116
+ }
117
+ return null;
118
+ }
@@ -0,0 +1,3 @@
1
+ import { type Hover } from 'vscode-languageserver';
2
+ import type { PrincipalValueLocation } from '../../lib/iam-policy/location.ts';
3
+ export declare function handlePrincipalValueHover(location: PrincipalValueLocation): Hover | null;
@@ -0,0 +1,13 @@
1
+ import { MarkupKind } from 'vscode-languageserver';
2
+ export function handlePrincipalValueHover(location) {
3
+ if (location.value === '*') {
4
+ return {
5
+ range: location.range,
6
+ contents: {
7
+ kind: MarkupKind.Markdown,
8
+ value: '**Public (unauthenticated) access**\n\nMatches all principals, including anonymous users.\n\n> **Warning:** Combining `"Principal": "*"` with `"Effect": "Allow"` grants public access. Always scope with a `Condition` element unless public access is intended.',
9
+ },
10
+ };
11
+ }
12
+ return null;
13
+ }
@@ -0,0 +1,3 @@
1
+ import { type Hover } from 'vscode-languageserver';
2
+ import type { ResourceValueLocation } from '../../lib/iam-policy/location.ts';
3
+ export declare function handleResourceValueHover(location: ResourceValueLocation): Hover | null;
@@ -0,0 +1,45 @@
1
+ import { MarkupKind } from 'vscode-languageserver';
2
+ import { parseArn } from "../../lib/iam-policy/arn.js";
3
+ import { ServiceReference } from "../../lib/iam-policy/reference/services.js";
4
+ export function handleResourceValueHover(location) {
5
+ if (location.value === '*') {
6
+ return {
7
+ range: location.range,
8
+ contents: {
9
+ kind: MarkupKind.Markdown,
10
+ value: 'Matches **all resources**.\n\nSome actions do not support resource-level permissions and require `"Resource": "*"`.',
11
+ },
12
+ };
13
+ }
14
+ const parsed = parseArn(location.value);
15
+ if (!parsed)
16
+ return null;
17
+ const resources = ServiceReference.getResources(parsed);
18
+ if (resources.length === 0)
19
+ return null;
20
+ const lines = [];
21
+ for (let i = 0; i < resources.length; i++) {
22
+ lines.push(`**${parsed.service} ${resources[i].name}**`);
23
+ if (resources[i].arnFormats.length > 0) {
24
+ lines.push('\n**ARNs**');
25
+ for (const format of resources[i].arnFormats) {
26
+ lines.push(`- \`${format}\``);
27
+ }
28
+ }
29
+ if (resources[i].conditionKeys.length > 0) {
30
+ lines.push('\n**Condition keys**');
31
+ for (const key of resources[i].conditionKeys) {
32
+ lines.push(`- \`${key}\``);
33
+ }
34
+ }
35
+ if (i + 1 !== resources.length)
36
+ lines.push('\n---\n');
37
+ }
38
+ return {
39
+ range: location.range,
40
+ contents: {
41
+ kind: MarkupKind.Markdown,
42
+ value: lines.join('\n'),
43
+ },
44
+ };
45
+ }
@@ -0,0 +1,3 @@
1
+ import { type Hover } from 'vscode-languageserver';
2
+ import type { StatementBlockLocation } from '../../lib/iam-policy/location.ts';
3
+ export declare function handleStatementBlockHover(location: StatementBlockLocation): Hover | null;
@@ -0,0 +1,14 @@
1
+ import { MarkupKind } from 'vscode-languageserver';
2
+ import { findHclElement } from "../completion/statement-block.js";
3
+ export function handleStatementBlockHover(location) {
4
+ const element = findHclElement(location.value);
5
+ if (!element)
6
+ return null;
7
+ return {
8
+ range: location.range,
9
+ contents: {
10
+ kind: MarkupKind.Markdown,
11
+ value: element.description,
12
+ },
13
+ };
14
+ }
@@ -0,0 +1,3 @@
1
+ import { type Connection, type Hover } from 'vscode-languageserver';
2
+ import type { StatementKeyLocation } from '../../lib/iam-policy/location.ts';
3
+ export declare function handleStatementKeyHover(_connection: Connection, location: StatementKeyLocation): Hover | null;
@@ -0,0 +1,14 @@
1
+ import { MarkupKind } from 'vscode-languageserver';
2
+ import { StatementKeys } from "../../lib/iam-policy/statement-keys.js";
3
+ export function handleStatementKeyHover(_connection, location) {
4
+ const statementKey = StatementKeys[location.value];
5
+ if (!statementKey)
6
+ return null;
7
+ return {
8
+ range: location.range,
9
+ contents: {
10
+ kind: MarkupKind.Markdown,
11
+ value: statementKey.description,
12
+ },
13
+ };
14
+ }
@@ -0,0 +1,17 @@
1
+ export type ArnParts = {
2
+ partition: string;
3
+ service: string;
4
+ region: string;
5
+ account: string;
6
+ resource: string;
7
+ };
8
+ /**
9
+ * Parse an ARN string into its structural components.
10
+ * Returns null if the string is not a valid ARN structure (fewer than 6 colon-separated segments).
11
+ * Everything after the 5th colon is treated as the resource portion.
12
+ */
13
+ export declare function parseArn(arn: string): ArnParts | null;
14
+ /**
15
+ * Check if a parsed user ARN matches a parsed template ARN.
16
+ */
17
+ export declare function arnMatches(userArn: ArnParts, templateArn: ArnParts): boolean;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Parse an ARN string into its structural components.
3
+ * Returns null if the string is not a valid ARN structure (fewer than 6 colon-separated segments).
4
+ * Everything after the 5th colon is treated as the resource portion.
5
+ */
6
+ export function parseArn(arn) {
7
+ const segments = arn.split(':');
8
+ if (segments.length < 6)
9
+ return null;
10
+ if (segments[0] !== 'arn')
11
+ return null;
12
+ return {
13
+ partition: segments[1],
14
+ service: segments[2],
15
+ region: segments[3],
16
+ account: segments[4],
17
+ resource: segments.slice(5).join(':'),
18
+ };
19
+ }
20
+ const placeholderPattern = /\$\{[^}]+\}/;
21
+ /**
22
+ * Check if two ARN tokens match. A token matches if:
23
+ * - Either is a wildcard (`*`) or contains `?`
24
+ * - Either is a placeholder (`${...}`)
25
+ * - Both are empty (valid for region/account in some ARNs)
26
+ * - They are literally equal
27
+ */
28
+ function tokensMatch(a, b) {
29
+ if (a === b)
30
+ return true;
31
+ if (a === '*' || b === '*')
32
+ return true;
33
+ if (a.includes('?') || b.includes('?'))
34
+ return true;
35
+ // Placeholders expect a value — don't match empty strings
36
+ if (a !== '' && b !== '' && (placeholderPattern.test(a) || placeholderPattern.test(b)))
37
+ return true;
38
+ return false;
39
+ }
40
+ /**
41
+ * Tokenize a resource string by splitting on both `:` and `/` delimiters.
42
+ * Preserves the delimiter as a separate token so structural comparison
43
+ * handles both `function:name` and `role/name` patterns.
44
+ */
45
+ function tokenizeResource(resource) {
46
+ return resource.split(/(?<=[:\/])|(?=[:\/])/);
47
+ }
48
+ /**
49
+ * Check if the resource portion of a user ARN matches a template resource pattern.
50
+ * Splits on `:` and `/` and compares tokens positionally.
51
+ */
52
+ function resourceMatches(userResource, templateResource) {
53
+ const userTokens = tokenizeResource(userResource);
54
+ const templateTokens = tokenizeResource(templateResource);
55
+ if (userTokens.length !== templateTokens.length) {
56
+ // A trailing `*` in the user ARN can match multiple template tokens
57
+ if (userTokens.length < templateTokens.length && userTokens[userTokens.length - 1] === '*') {
58
+ return userTokens.slice(0, -1).every((token, i) => tokensMatch(token, templateTokens[i]));
59
+ }
60
+ return false;
61
+ }
62
+ return userTokens.every((token, i) => tokensMatch(token, templateTokens[i]));
63
+ }
64
+ /**
65
+ * Check if a parsed user ARN matches a parsed template ARN.
66
+ */
67
+ export function arnMatches(userArn, templateArn) {
68
+ if (!tokensMatch(userArn.partition, templateArn.partition))
69
+ return false;
70
+ if (!tokensMatch(userArn.service, templateArn.service))
71
+ return false;
72
+ if (!tokensMatch(userArn.region, templateArn.region))
73
+ return false;
74
+ if (!tokensMatch(userArn.account, templateArn.account))
75
+ return false;
76
+ return resourceMatches(userArn.resource, templateArn.resource);
77
+ }
@@ -1,68 +1,98 @@
1
- import type { CursorContext } from '../treesitter/base.ts';
1
+ import type { CursorContext, Range } from '../treesitter/base.ts';
2
2
  export type StatementKeyLocation = {
3
3
  type: 'statement-key';
4
4
  partial: string;
5
+ value: string;
6
+ range?: Range;
5
7
  };
6
8
  export type StatementBlockLocation = {
7
9
  type: 'statement-block';
8
10
  partial: string;
11
+ value: string;
12
+ range?: Range;
9
13
  };
10
14
  export type EffectValueLocation = {
11
15
  type: 'effect-value';
12
16
  partial: string;
17
+ value: string;
18
+ range?: Range;
13
19
  };
14
20
  export type ActionValueLocation = {
15
21
  type: 'action-value';
16
22
  partial: string;
23
+ value: string;
24
+ range?: Range;
17
25
  };
18
26
  export type ResourceValueLocation = {
19
27
  type: 'resource-value';
20
28
  partial: string;
29
+ value: string;
30
+ range?: Range;
21
31
  };
22
32
  export type PrincipalValueLocation = {
23
33
  type: 'principal-value';
24
34
  partial: string;
35
+ value: string;
36
+ range?: Range;
25
37
  };
26
38
  export type PrincipalTypeLocation = {
27
39
  type: 'principal-type';
28
40
  partial: string;
41
+ value: string;
42
+ range?: Range;
29
43
  };
30
44
  export type PrincipalBlockLocation = {
31
45
  type: 'principal-block';
32
46
  partial: string;
47
+ value: string;
48
+ range?: Range;
33
49
  };
34
50
  export type PrincipalBlockTypeLocation = {
35
51
  type: 'principal-block-type';
36
52
  partial: string;
53
+ value: string;
54
+ range?: Range;
37
55
  };
38
56
  export type PrincipalBlockIdentifierLocation = {
39
57
  type: 'principal-block-identifier';
40
58
  principalType: string | null;
41
59
  partial: string;
60
+ value: string;
61
+ range?: Range;
42
62
  };
43
63
  export type PrincipalTypedValueLocation = {
44
64
  type: 'principal-typed-value';
45
65
  principalType: string;
46
66
  partial: string;
67
+ value: string;
68
+ range?: Range;
47
69
  };
48
70
  export type ConditionBlockLocation = {
49
71
  type: 'condition-block';
50
72
  partial: string;
73
+ value: string;
74
+ range?: Range;
51
75
  };
52
76
  export type ConditionOperatorLocation = {
53
77
  type: 'condition-operator';
54
78
  partial: string;
79
+ value: string;
80
+ range?: Range;
55
81
  };
56
82
  export type ConditionKeyLocation = {
57
83
  type: 'condition-key';
58
84
  operator: string;
59
85
  partial: string;
86
+ value: string;
87
+ range?: Range;
60
88
  };
61
89
  export type ConditionValueLocation = {
62
90
  type: 'condition-value';
63
91
  operator: string;
64
92
  key: string;
65
93
  partial: string;
94
+ value: string;
95
+ range?: Range;
66
96
  };
67
97
  export type UnknownLocation = {
68
98
  type: 'unknown';
@@ -16,66 +16,103 @@ export function resolvePolicyLocation(context) {
16
16
  const statementKey = isHclBlock ? (snakeToPascal[keys[0]] ?? keys[0]) : keys[0];
17
17
  if (keys.length === 0 && context.role === 'key') {
18
18
  if (isHclBlock)
19
- return { type: 'statement-block', partial: context.partial };
20
- return { type: 'statement-key', partial: context.partial };
19
+ return { type: 'statement-block', partial: context.partial, value: context.value, range: context.range };
20
+ return { type: 'statement-key', partial: context.partial, value: context.value, range: context.range };
21
21
  }
22
22
  if (keys.length === 1 && context.role === 'value') {
23
23
  if (statementKey === 'Effect')
24
- return { type: 'effect-value', partial: context.partial };
24
+ return { type: 'effect-value', partial: context.partial, value: context.value, range: context.range };
25
25
  if (statementKey === 'Action' || statementKey === 'NotAction')
26
- return { type: 'action-value', partial: context.partial };
26
+ return { type: 'action-value', partial: context.partial, value: context.value, range: context.range };
27
27
  if (statementKey === 'Resource' || statementKey === 'NotResource')
28
- return { type: 'resource-value', partial: context.partial };
28
+ return { type: 'resource-value', partial: context.partial, value: context.value, range: context.range };
29
29
  if (statementKey === 'Principal' || statementKey === 'NotPrincipal')
30
- return { type: 'principal-value', partial: context.partial };
30
+ return { type: 'principal-value', partial: context.partial, value: context.value, range: context.range };
31
31
  if (statementKey === 'Condition')
32
- return { type: 'condition-operator', partial: context.partial };
32
+ return { type: 'condition-operator', partial: context.partial, value: context.value, range: context.range };
33
33
  }
34
34
  if (keys.length === 1 && context.role === 'key') {
35
35
  if (statementKey === 'Principal' || statementKey === 'NotPrincipal') {
36
36
  if (isHclBlock) {
37
- return { type: 'principal-block', partial: context.partial };
37
+ return { type: 'principal-block', partial: context.partial, value: context.value, range: context.range };
38
38
  }
39
- return { type: 'principal-type', partial: context.partial };
39
+ return { type: 'principal-type', partial: context.partial, value: context.value, range: context.range };
40
40
  }
41
41
  if (statementKey === 'Condition') {
42
42
  if (isHclBlock)
43
- return { type: 'condition-block', partial: context.partial };
44
- return { type: 'condition-operator', partial: context.partial };
43
+ return { type: 'condition-block', partial: context.partial, value: context.value, range: context.range };
44
+ return { type: 'condition-operator', partial: context.partial, value: context.value, range: context.range };
45
45
  }
46
46
  }
47
47
  if ((keys.length === 2 || keys.length === 3) && context.role === 'value') {
48
48
  if (statementKey === 'Principal' || statementKey === 'NotPrincipal') {
49
49
  if (isHclBlock && keys[1] === 'type') {
50
- return { type: 'principal-block-type', partial: context.partial };
50
+ return { type: 'principal-block-type', partial: context.partial, value: context.value, range: context.range };
51
51
  }
52
52
  if (isHclBlock && keys[1] === 'identifiers') {
53
- return { type: 'principal-block-identifier', principalType: keys[2] ?? null, partial: context.partial };
53
+ return {
54
+ type: 'principal-block-identifier',
55
+ principalType: keys[2] ?? null,
56
+ partial: context.partial,
57
+ value: context.value,
58
+ range: context.range,
59
+ };
54
60
  }
55
61
  if (keys.length === 2) {
56
- return { type: 'principal-typed-value', principalType: keys[1], partial: context.partial };
62
+ return {
63
+ type: 'principal-typed-value',
64
+ principalType: keys[1],
65
+ partial: context.partial,
66
+ value: context.value,
67
+ range: context.range,
68
+ };
57
69
  }
58
70
  }
59
71
  }
60
72
  if (keys.length === 2 && context.role === 'value') {
61
73
  if (statementKey === 'Condition' && isHclBlock && keys[1] === 'test') {
62
- return { type: 'condition-operator', partial: context.partial };
74
+ return { type: 'condition-operator', partial: context.partial, value: context.value, range: context.range };
63
75
  }
64
76
  if (statementKey === 'Condition' && isHclBlock && keys[1] === 'variable') {
65
- return { type: 'condition-key', operator: '', partial: context.partial };
77
+ return {
78
+ type: 'condition-key',
79
+ operator: '',
80
+ partial: context.partial,
81
+ value: context.value,
82
+ range: context.range,
83
+ };
66
84
  }
67
85
  if (statementKey === 'Condition' && !isHclBlock) {
68
- return { type: 'condition-key', operator: keys[1], partial: context.partial };
86
+ return {
87
+ type: 'condition-key',
88
+ operator: keys[1],
89
+ partial: context.partial,
90
+ value: context.value,
91
+ range: context.range,
92
+ };
69
93
  }
70
94
  }
71
95
  if (keys.length === 2 && context.role === 'key') {
72
96
  if (statementKey === 'Condition') {
73
- return { type: 'condition-key', operator: keys[1], partial: context.partial };
97
+ return {
98
+ type: 'condition-key',
99
+ operator: keys[1],
100
+ partial: context.partial,
101
+ value: context.value,
102
+ range: context.range,
103
+ };
74
104
  }
75
105
  }
76
106
  if (keys.length === 3 && context.role === 'value') {
77
107
  if (statementKey === 'Condition') {
78
- return { type: 'condition-value', operator: keys[1], key: keys[2], partial: context.partial };
108
+ return {
109
+ type: 'condition-value',
110
+ operator: keys[1],
111
+ key: keys[2],
112
+ partial: context.partial,
113
+ value: context.value,
114
+ range: context.range,
115
+ };
79
116
  }
80
117
  }
81
118
  return { type: 'unknown' };
@@ -1,8 +1,9 @@
1
- import type { Action, ConditionKey, GlobalConditionKey, ServiceData } from './types.ts';
1
+ import { type ArnParts } from '../arn.ts';
2
+ import type { Action, ConditionKey, GlobalConditionKey, ResourceDef, ServiceData } from './types.ts';
2
3
  export declare class ServiceReference {
3
4
  #private;
4
- static getServiceData(service: string): ServiceData;
5
- static getServicePrincipals(): string[];
5
+ static getServiceData(service: string): ServiceData | undefined;
6
+ static getServicePrincipals(): Array<string>;
6
7
  static getAllActions(): Array<string>;
7
8
  static getAllServices(): Array<string>;
8
9
  static getActionsForService(service: string): Array<Action>;
@@ -13,6 +14,7 @@ export declare class ServiceReference {
13
14
  static getGlobalConditionKeys(): Array<GlobalConditionKey>;
14
15
  static getAction(action: string): Action | undefined;
15
16
  static getConditionKey(service: string, keyName: string): ConditionKey | undefined;
17
+ static getResources(arn: ArnParts): ResourceDef[];
16
18
  static getResourcesForActions(actions: string[]): Map<string, {
17
19
  service: string;
18
20
  name: string;