iam-floyd 0.847.0 → 0.849.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.
Files changed (51) hide show
  1. package/.markdownlint-cli2.yaml +16 -0
  2. package/.prettierignore +5 -0
  3. package/.yamllint.yaml +13 -0
  4. package/AGENTS.md +64 -16
  5. package/README.md +170 -46
  6. package/doc8.ini +3 -0
  7. package/dotnet/src/IAM.Floyd/IAM.Floyd.csproj +36 -0
  8. package/dotnet/src/IAM.Floyd/Js.cs +272 -0
  9. package/dotnet/src/IAM.Floyd/Json.cs +151 -0
  10. package/eslint.config.mjs +123 -0
  11. package/go/iamfloyd/go.mod +3 -0
  12. package/go/iamfloyd/helpers.go +25 -0
  13. package/go/iamfloyd/internal/js/collections.go +219 -0
  14. package/go/iamfloyd/internal/js/json.go +95 -0
  15. package/go/iamfloyd/internal/js/strings.go +150 -0
  16. package/go/iamfloyd/internal/js/values.go +251 -0
  17. package/java/pom.xml +140 -0
  18. package/java/src/main/java/com/udondan/iamFloyd/Js.java +210 -0
  19. package/java/src/main/java/com/udondan/iamFloyd/Json.java +137 -0
  20. package/lib/collection/allowEc2InstanceDeleteByOwner.d.ts +2 -2
  21. package/lib/collection/allowEc2InstanceDeleteByOwner.js +3 -3
  22. package/lib/collection/index.d.ts +2 -1
  23. package/lib/shared/compact.d.ts +12 -0
  24. package/lib/shared/compact.js +121 -0
  25. package/lib/shared/policy-statement/1-base.d.ts +0 -6
  26. package/lib/shared/policy-statement/1-base.js +0 -7
  27. package/lib/shared/policy-statement/10-final.d.ts +0 -1
  28. package/lib/shared/policy-statement/10-final.js +24 -5
  29. package/lib/shared/policy-statement/2-conditions.d.ts +1 -11
  30. package/lib/shared/policy-statement/2-conditions.js +9 -70
  31. package/lib/shared/policy-statement/3-actions.d.ts +7 -9
  32. package/lib/shared/policy-statement/3-actions.js +61 -109
  33. package/lib/shared/policy-statement/4-resources.d.ts +4 -10
  34. package/lib/shared/policy-statement/4-resources.js +2 -44
  35. package/lib/shared/policy-statement/5-effect.d.ts +0 -6
  36. package/lib/shared/policy-statement/5-effect.js +0 -8
  37. package/lib/shared/policy-statement/8-principals.d.ts +0 -9
  38. package/lib/shared/policy-statement/8-principals.js +0 -23
  39. package/lint/checkstyle-suppressions.xml +16 -0
  40. package/lint/go.mod +28 -0
  41. package/lint/go.sum +45 -0
  42. package/lint/pom.xml +43 -0
  43. package/lint/requirements.txt +6 -0
  44. package/package.json +17 -27
  45. package/python/iam_floyd/__init__.py +42 -0
  46. package/python/iam_floyd/_js.py +104 -0
  47. package/python/iam_floyd/py.typed +0 -0
  48. package/python/pyproject.toml +39 -0
  49. package/ruff.toml +11 -0
  50. package/skills/iam-floyd-usage/SKILL.md +4 -3
  51. package/.eslintrc +0 -31
@@ -0,0 +1,272 @@
1
+ using System;
2
+ using System.Collections;
3
+ using System.Collections.Generic;
4
+ using System.Globalization;
5
+ using System.Text;
6
+ using System.Text.RegularExpressions;
7
+
8
+ namespace IAM.Floyd;
9
+
10
+ /// <summary>
11
+ /// The semantics of JavaScript that the transpiled code relies on.
12
+ /// </summary>
13
+ internal static class Js
14
+ {
15
+ /// <summary>
16
+ /// Whether a value is a number.
17
+ /// </summary>
18
+ public static bool IsNumber(object value)
19
+ {
20
+ return value is double || value is int || value is long || value is float
21
+ || value is short || value is byte || value is decimal;
22
+ }
23
+
24
+ /// <summary>
25
+ /// Array.isArray: whether a value is a sequence, other than a string or a dictionary.
26
+ /// </summary>
27
+ public static bool IsArray(object value)
28
+ {
29
+ return value is IEnumerable && !(value is string) && !(value is IDictionary);
30
+ }
31
+
32
+ /// <summary>
33
+ /// A sequence as list.
34
+ /// </summary>
35
+ public static List<object> ToList(object value)
36
+ {
37
+ var result = new List<object>();
38
+ foreach (var item in (IEnumerable)value)
39
+ {
40
+ result.Add(item);
41
+ }
42
+ return result;
43
+ }
44
+
45
+ /// <summary>
46
+ /// The result of the typeof operator of JavaScript.
47
+ /// </summary>
48
+ public static string Typeof(object value)
49
+ {
50
+ if (value == null)
51
+ {
52
+ return "undefined";
53
+ }
54
+ if (value is bool)
55
+ {
56
+ return "boolean";
57
+ }
58
+ if (IsNumber(value))
59
+ {
60
+ return "number";
61
+ }
62
+ if (value is string)
63
+ {
64
+ return "string";
65
+ }
66
+ return "object";
67
+ }
68
+
69
+ /// <summary>
70
+ /// A value as JavaScript converts it to a string.
71
+ /// </summary>
72
+ public static string ToString(object value)
73
+ {
74
+ switch (value)
75
+ {
76
+ case null:
77
+ return "undefined";
78
+ case string text:
79
+ return text;
80
+ case bool flag:
81
+ return flag ? "true" : "false";
82
+ case double number:
83
+ return Number(number);
84
+ case float number:
85
+ return Number(number);
86
+ case decimal number:
87
+ return Number((double)number);
88
+ case IFormattable formattable when IsNumber(value):
89
+ return formattable.ToString(null, CultureInfo.InvariantCulture);
90
+ case IEnumerable items when !(value is IDictionary):
91
+ var result = new StringBuilder();
92
+ var first = true;
93
+ foreach (var item in items)
94
+ {
95
+ if (!first)
96
+ {
97
+ result.Append(',');
98
+ }
99
+ first = false;
100
+ if (item != null)
101
+ {
102
+ result.Append(ToString(item));
103
+ }
104
+ }
105
+ return result.ToString();
106
+ }
107
+ return value.ToString();
108
+ }
109
+
110
+ /// <summary>
111
+ /// A number as JavaScript formats it: the shortest digits that round-trip.
112
+ /// </summary>
113
+ public static string Number(double value)
114
+ {
115
+ if (double.IsNaN(value))
116
+ {
117
+ return "NaN";
118
+ }
119
+ if (double.IsInfinity(value))
120
+ {
121
+ return value > 0 ? "Infinity" : "-Infinity";
122
+ }
123
+ if (value == 0)
124
+ {
125
+ return "0";
126
+ }
127
+ if (value < 0)
128
+ {
129
+ return "-" + Number(-value);
130
+ }
131
+ // the shortest representation that parses back to the same value, e.g. 1.5E-07
132
+ var shortest = value.ToString("R", CultureInfo.InvariantCulture);
133
+ var e = shortest.IndexOf('E');
134
+ var mantissa = e < 0 ? shortest : shortest.Substring(0, e);
135
+ var exponent = e < 0 ? 0 : int.Parse(shortest.Substring(e + 1), CultureInfo.InvariantCulture);
136
+ var point = mantissa.IndexOf('.');
137
+ var digits = point < 0 ? mantissa : mantissa.Remove(point, 1);
138
+ // n is the position of the decimal point relative to the first digit
139
+ var n = (point < 0 ? mantissa.Length : point) + exponent;
140
+ while (digits.Length > 1 && digits[0] == '0')
141
+ {
142
+ digits = digits.Substring(1);
143
+ n--;
144
+ }
145
+ // trailing zeros are not significant
146
+ while (digits.Length > 1 && digits[digits.Length - 1] == '0')
147
+ {
148
+ digits = digits.Substring(0, digits.Length - 1);
149
+ }
150
+ var k = digits.Length;
151
+ var result = new StringBuilder();
152
+ if (k <= n && n <= 21)
153
+ {
154
+ result.Append(digits).Append('0', n - k);
155
+ }
156
+ else if (0 < n && n <= 21)
157
+ {
158
+ result.Append(digits, 0, n).Append('.').Append(digits.Substring(n));
159
+ }
160
+ else if (-6 < n && n <= 0)
161
+ {
162
+ result.Append("0.").Append('0', -n).Append(digits);
163
+ }
164
+ else
165
+ {
166
+ result.Append(digits[0]);
167
+ if (k > 1)
168
+ {
169
+ result.Append('.').Append(digits.Substring(1));
170
+ }
171
+ result.Append('e').Append(n - 1 >= 0 ? "+" : "-")
172
+ .Append(Math.Abs(n - 1).ToString(CultureInfo.InvariantCulture));
173
+ }
174
+ return result.ToString();
175
+ }
176
+
177
+ /// <summary>
178
+ /// String.prototype.substring: the indexes are clamped, and swapped if start is after end.
179
+ /// </summary>
180
+ public static string Substring(string value, int start)
181
+ {
182
+ return Substring(value, start, value.Length);
183
+ }
184
+
185
+ /// <summary>
186
+ /// String.prototype.substring: the indexes are clamped, and swapped if start is after end.
187
+ /// </summary>
188
+ public static string Substring(string value, int start, int end)
189
+ {
190
+ start = Math.Max(0, Math.Min(start, value.Length));
191
+ end = Math.Max(0, Math.Min(end, value.Length));
192
+ return start <= end
193
+ ? value.Substring(start, end - start)
194
+ : value.Substring(end, start - end);
195
+ }
196
+
197
+ /// <summary>
198
+ /// Array.prototype.filter.
199
+ /// </summary>
200
+ public static List<T> Filter<T>(List<T> list, Func<T, int, bool> predicate)
201
+ {
202
+ var result = new List<T>();
203
+ for (var i = 0; i < list.Count; i++)
204
+ {
205
+ if (predicate(list[i], i))
206
+ {
207
+ result.Add(list[i]);
208
+ }
209
+ }
210
+ return result;
211
+ }
212
+
213
+ /// <summary>
214
+ /// Array.prototype.map.
215
+ /// </summary>
216
+ public static List<TResult> Map<T, TResult>(List<T> list, Func<T, int, TResult> fn)
217
+ {
218
+ var result = new List<TResult>();
219
+ for (var i = 0; i < list.Count; i++)
220
+ {
221
+ result.Add(fn(list[i], i));
222
+ }
223
+ return result;
224
+ }
225
+
226
+ /// <summary>
227
+ /// Array.prototype.sort without compare function: sorts strings by UTF-16 code units.
228
+ /// </summary>
229
+ public static List<string> Sort(List<string> list)
230
+ {
231
+ list.Sort(string.CompareOrdinal);
232
+ return list;
233
+ }
234
+
235
+ /// <summary>
236
+ /// Date.prototype.toISOString. Dates of an unspecified kind are in UTC.
237
+ /// </summary>
238
+ public static string ToISOString(DateTime value)
239
+ {
240
+ if (value.Kind == DateTimeKind.Local)
241
+ {
242
+ value = value.ToUniversalTime();
243
+ }
244
+ return value.ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'", CultureInfo.InvariantCulture);
245
+ }
246
+
247
+ /// <summary>
248
+ /// A regular expression like new RegExp(pattern, flags), with the flags i, m and s.
249
+ /// </summary>
250
+ public static Regex RegExp(string pattern, string flags)
251
+ {
252
+ var options = RegexOptions.None;
253
+ foreach (var flag in flags)
254
+ {
255
+ switch (flag)
256
+ {
257
+ case 'i':
258
+ options |= RegexOptions.IgnoreCase | RegexOptions.CultureInvariant;
259
+ break;
260
+ case 'm':
261
+ options |= RegexOptions.Multiline;
262
+ break;
263
+ case 's':
264
+ options |= RegexOptions.Singleline;
265
+ break;
266
+ default:
267
+ throw new ArgumentException("Unsupported regular expression flag: " + flag);
268
+ }
269
+ }
270
+ return new Regex(pattern, options);
271
+ }
272
+ }
@@ -0,0 +1,151 @@
1
+ using System;
2
+ using System.Collections;
3
+ using System.Globalization;
4
+ using System.Reflection;
5
+ using System.Text;
6
+
7
+ namespace IAM.Floyd;
8
+
9
+ /// <summary>
10
+ /// Serializes statements and their parts to JSON, as <c>JSON.stringify</c> of JavaScript.
11
+ /// </summary>
12
+ public static class Json
13
+ {
14
+ /// <summary>
15
+ /// The JSON of a value: dictionaries in the order of their keys, sequences, strings, numbers,
16
+ /// booleans, null, dates as ISO strings, and objects with a public <c>ToJSON()</c> method, such
17
+ /// as statements.
18
+ /// </summary>
19
+ /// <param name="value">The value</param>
20
+ /// <returns>The JSON, without whitespace</returns>
21
+ public static string Stringify(object value)
22
+ {
23
+ var result = new StringBuilder();
24
+ Write(result, value);
25
+ return result.ToString();
26
+ }
27
+
28
+ private static void Write(StringBuilder result, object value)
29
+ {
30
+ switch (value)
31
+ {
32
+ case null:
33
+ result.Append("null");
34
+ break;
35
+ case string text:
36
+ WriteString(result, text);
37
+ break;
38
+ case bool flag:
39
+ result.Append(flag ? "true" : "false");
40
+ break;
41
+ case double or float or decimal:
42
+ var number = Convert.ToDouble(value, CultureInfo.InvariantCulture);
43
+ result.Append(double.IsNaN(number) || double.IsInfinity(number) ? "null" : Js.Number(number));
44
+ break;
45
+ case IFormattable formattable when Js.IsNumber(value):
46
+ result.Append(formattable.ToString(null, CultureInfo.InvariantCulture));
47
+ break;
48
+ case DateTime date:
49
+ WriteString(result, Js.ToISOString(date));
50
+ break;
51
+ case IDictionary dictionary:
52
+ result.Append('{');
53
+ var first = true;
54
+ foreach (DictionaryEntry entry in dictionary)
55
+ {
56
+ if (!first)
57
+ {
58
+ result.Append(',');
59
+ }
60
+ first = false;
61
+ WriteString(result, Convert.ToString(entry.Key, CultureInfo.InvariantCulture));
62
+ result.Append(':');
63
+ Write(result, entry.Value);
64
+ }
65
+ result.Append('}');
66
+ break;
67
+ case IEnumerable items:
68
+ result.Append('[');
69
+ var firstItem = true;
70
+ foreach (var item in items)
71
+ {
72
+ if (!firstItem)
73
+ {
74
+ result.Append(',');
75
+ }
76
+ firstItem = false;
77
+ Write(result, item);
78
+ }
79
+ result.Append(']');
80
+ break;
81
+ default:
82
+ Write(result, ToJson(value));
83
+ break;
84
+ }
85
+ }
86
+
87
+ private static object ToJson(object value)
88
+ {
89
+ var method = value.GetType().GetMethod("ToJSON", Type.EmptyTypes);
90
+ if (method == null)
91
+ {
92
+ throw new ArgumentException("Cannot serialize " + value.GetType().FullName + " to JSON");
93
+ }
94
+ try
95
+ {
96
+ return method.Invoke(value, null);
97
+ }
98
+ catch (TargetInvocationException e) when (e.InnerException != null)
99
+ {
100
+ System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(e.InnerException).Throw();
101
+ throw;
102
+ }
103
+ }
104
+
105
+ private static void WriteString(StringBuilder result, string value)
106
+ {
107
+ result.Append('"');
108
+ for (var i = 0; i < value.Length; i++)
109
+ {
110
+ var c = value[i];
111
+ switch (c)
112
+ {
113
+ case '"':
114
+ result.Append("\\\"");
115
+ break;
116
+ case '\\':
117
+ result.Append("\\\\");
118
+ break;
119
+ case '\b':
120
+ result.Append("\\b");
121
+ break;
122
+ case '\f':
123
+ result.Append("\\f");
124
+ break;
125
+ case '\n':
126
+ result.Append("\\n");
127
+ break;
128
+ case '\r':
129
+ result.Append("\\r");
130
+ break;
131
+ case '\t':
132
+ result.Append("\\t");
133
+ break;
134
+ default:
135
+ var loneSurrogate = char.IsHighSurrogate(c)
136
+ ? i + 1 >= value.Length || !char.IsLowSurrogate(value[i + 1])
137
+ : char.IsLowSurrogate(c) && (i == 0 || !char.IsHighSurrogate(value[i - 1]));
138
+ if (c < 0x20 || loneSurrogate)
139
+ {
140
+ result.Append("\\u").Append(((int)c).ToString("x4", CultureInfo.InvariantCulture));
141
+ }
142
+ else
143
+ {
144
+ result.Append(c);
145
+ }
146
+ break;
147
+ }
148
+ }
149
+ result.Append('"');
150
+ }
151
+ }
@@ -0,0 +1,123 @@
1
+ import eslint from '@eslint/js';
2
+ import prettierRecommended from 'eslint-plugin-prettier/recommended';
3
+ import { defineConfig } from 'eslint/config';
4
+ import { readFileSync } from 'fs';
5
+ import globals from 'globals';
6
+ import tseslint from 'typescript-eslint';
7
+
8
+ // These files use the CDK variant, which only exists after `make cdk`. Before, they are linted without
9
+ // type information. After, all files are linted with tsconfig.lint-cdk.json, which resolves
10
+ // `cdk-iam-floyd` to lib/.
11
+ const cdkFiles = [
12
+ 'lib/**/*.CDK.ts',
13
+ 'lib/**/*-CDK.ts',
14
+ 'examples/**/*.cdk.ts',
15
+ 'test/cdk.ts',
16
+ 'test/jsii/consumer/**/*.ts',
17
+ ];
18
+ const isCdk =
19
+ JSON.parse(readFileSync('package.json', 'utf8')).name === 'cdk-iam-floyd';
20
+
21
+ export default defineConfig(
22
+ {
23
+ ignores: [
24
+ '**/node_modules/',
25
+ '**/cdk.out/',
26
+ '**/*.d.ts',
27
+ 'lib/**/*.js',
28
+ 'bin/**/*.js',
29
+ 'examples/**/*.js',
30
+ 'helper/**/*.js',
31
+ 'test/**/*.js',
32
+ 'tooter/**/*.js',
33
+ 'lib/generated/',
34
+ 'dist/',
35
+ 'java/target/',
36
+ 'docs/build/',
37
+ ],
38
+ },
39
+ {
40
+ files: ['**/*.ts'],
41
+ extends: [
42
+ eslint.configs.recommended,
43
+ tseslint.configs.recommendedTypeChecked,
44
+ tseslint.configs.stylisticTypeChecked,
45
+ ],
46
+ languageOptions: {
47
+ parserOptions: isCdk
48
+ ? { project: 'tsconfig.lint-cdk.json' }
49
+ : { projectService: true },
50
+ },
51
+ rules: {
52
+ '@typescript-eslint/no-unused-vars': [
53
+ 'error',
54
+ {
55
+ argsIgnorePattern: '^_',
56
+ varsIgnorePattern: '^_',
57
+ caughtErrorsIgnorePattern: '^_',
58
+ },
59
+ ],
60
+ '@typescript-eslint/no-deprecated': 'error',
61
+ '@typescript-eslint/naming-convention': [
62
+ 'error',
63
+ {
64
+ selector: 'default',
65
+ format: ['camelCase'],
66
+ leadingUnderscore: 'allow',
67
+ },
68
+ { selector: 'import', format: ['camelCase', 'PascalCase'] },
69
+ {
70
+ selector: 'variable',
71
+ modifiers: ['const'],
72
+ format: ['camelCase', 'PascalCase', 'UPPER_CASE'],
73
+ leadingUnderscore: 'allow',
74
+ },
75
+ { selector: 'typeLike', format: ['PascalCase'] },
76
+ { selector: 'enumMember', format: ['camelCase', 'PascalCase'] },
77
+ // Keys of objects are given by the format, like IAM policies or AWS APIs
78
+ { selector: 'objectLiteralProperty', format: null },
79
+ { selector: 'typeProperty', format: null },
80
+ ],
81
+ 'prefer-template': 'error',
82
+ // `@ts-expect-error` fails where the line is valid in the other variant
83
+ '@typescript-eslint/ban-ts-comment': [
84
+ 'error',
85
+ { 'ts-ignore': 'allow-with-description' },
86
+ ],
87
+ },
88
+ },
89
+ {
90
+ // The layers call methods of the base class of the variant, which the standalone variant
91
+ // doesn't have
92
+ files: ['lib/shared/policy-statement/*.ts'],
93
+ rules: {
94
+ '@typescript-eslint/no-explicit-any': 'off',
95
+ '@typescript-eslint/no-this-alias': 'off',
96
+ '@typescript-eslint/no-unsafe-assignment': 'off',
97
+ '@typescript-eslint/no-unsafe-call': 'off',
98
+ '@typescript-eslint/no-unsafe-member-access': 'off',
99
+ '@typescript-eslint/no-unsafe-return': 'off',
100
+ },
101
+ },
102
+ {
103
+ files: cdkFiles,
104
+ extends: isCdk ? [] : [tseslint.configs.disableTypeChecked],
105
+ },
106
+ {
107
+ files: ['**/*.js', '**/*.mjs'],
108
+ extends: [eslint.configs.recommended],
109
+ languageOptions: { globals: globals.node },
110
+ },
111
+ {
112
+ files: ['docs/source/_static/js/**/*.js'],
113
+ languageOptions: {
114
+ globals: { ...globals.browser, $: 'readonly' },
115
+ sourceType: 'script',
116
+ },
117
+ },
118
+ prettierRecommended,
119
+ {
120
+ // `make cdk` writes code that isn't formatted. The formatting is checked in the standalone variant.
121
+ rules: isCdk ? { 'prettier/prettier': 'off' } : {},
122
+ },
123
+ );
@@ -0,0 +1,3 @@
1
+ module udondan.github.io/iam-floyd/go/iamfloyd
2
+
3
+ go 1.21
@@ -0,0 +1,25 @@
1
+ package iamfloyd
2
+
3
+ // String returns a pointer to a string, for the parameters of the API
4
+ func String(value string) *string {
5
+ return &value
6
+ }
7
+
8
+ // Strings returns a pointer to a list of pointers to strings, for the parameters of the API
9
+ func Strings(values ...string) *[]*string {
10
+ list := make([]*string, len(values))
11
+ for i := range values {
12
+ list[i] = &values[i]
13
+ }
14
+ return &list
15
+ }
16
+
17
+ // Number returns a pointer to a number, for the parameters of the API
18
+ func Number(value float64) *float64 {
19
+ return &value
20
+ }
21
+
22
+ // Bool returns a pointer to a boolean, for the parameters of the API
23
+ func Bool(value bool) *bool {
24
+ return &value
25
+ }