@rexezuge/tooling 0.0.0-stage → 1.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.
Files changed (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +297 -2
  3. package/dist/eslint-boundaries.d.ts +75 -0
  4. package/dist/eslint-boundaries.d.ts.map +1 -0
  5. package/dist/eslint-boundaries.js +138 -0
  6. package/dist/eslint-boundaries.js.map +1 -0
  7. package/dist/eslint-rules.d.ts +41 -0
  8. package/dist/eslint-rules.d.ts.map +1 -0
  9. package/dist/eslint-rules.js +273 -0
  10. package/dist/eslint-rules.js.map +1 -0
  11. package/dist/eslint.d.ts +96 -0
  12. package/dist/eslint.d.ts.map +1 -0
  13. package/dist/eslint.js +189 -0
  14. package/dist/eslint.js.map +1 -0
  15. package/dist/functions/pages-proxy.d.ts +113 -0
  16. package/dist/functions/pages-proxy.d.ts.map +1 -0
  17. package/dist/functions/pages-proxy.js +131 -0
  18. package/dist/functions/pages-proxy.js.map +1 -0
  19. package/dist/index.d.ts +31 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +28 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/scripts/backup/d1-target.d.ts +35 -0
  24. package/dist/scripts/backup/d1-target.d.ts.map +1 -0
  25. package/dist/scripts/backup/d1-target.js +31 -0
  26. package/dist/scripts/backup/d1-target.js.map +1 -0
  27. package/dist/scripts/backup/destination-config.d.ts +61 -0
  28. package/dist/scripts/backup/destination-config.d.ts.map +1 -0
  29. package/dist/scripts/backup/destination-config.js +57 -0
  30. package/dist/scripts/backup/destination-config.js.map +1 -0
  31. package/dist/scripts/backup/encrypt-backup.d.ts +35 -0
  32. package/dist/scripts/backup/encrypt-backup.d.ts.map +1 -0
  33. package/dist/scripts/backup/encrypt-backup.js +98 -0
  34. package/dist/scripts/backup/encrypt-backup.js.map +1 -0
  35. package/dist/scripts/backup/naming.d.ts +44 -0
  36. package/dist/scripts/backup/naming.d.ts.map +1 -0
  37. package/dist/scripts/backup/naming.js +58 -0
  38. package/dist/scripts/backup/naming.js.map +1 -0
  39. package/dist/scripts/check-god-files.d.ts +164 -0
  40. package/dist/scripts/check-god-files.d.ts.map +1 -0
  41. package/dist/scripts/check-god-files.js +271 -0
  42. package/dist/scripts/check-god-files.js.map +1 -0
  43. package/dist/scripts/ensure-spa-shell-stub.d.ts +3 -0
  44. package/dist/scripts/ensure-spa-shell-stub.d.ts.map +1 -0
  45. package/dist/scripts/ensure-spa-shell-stub.js +30 -0
  46. package/dist/scripts/ensure-spa-shell-stub.js.map +1 -0
  47. package/dist/scripts/init-secrets.d.ts +63 -0
  48. package/dist/scripts/init-secrets.d.ts.map +1 -0
  49. package/dist/scripts/init-secrets.js +240 -0
  50. package/dist/scripts/init-secrets.js.map +1 -0
  51. package/dist/scripts/lib/cli-args.d.ts +78 -0
  52. package/dist/scripts/lib/cli-args.d.ts.map +1 -0
  53. package/dist/scripts/lib/cli-args.js +116 -0
  54. package/dist/scripts/lib/cli-args.js.map +1 -0
  55. package/dist/scripts/lib/github-actions.d.ts +26 -0
  56. package/dist/scripts/lib/github-actions.d.ts.map +1 -0
  57. package/dist/scripts/lib/github-actions.js +38 -0
  58. package/dist/scripts/lib/github-actions.js.map +1 -0
  59. package/dist/scripts/lib/wrangler-table.d.ts +46 -0
  60. package/dist/scripts/lib/wrangler-table.d.ts.map +1 -0
  61. package/dist/scripts/lib/wrangler-table.js +99 -0
  62. package/dist/scripts/lib/wrangler-table.js.map +1 -0
  63. package/dist/scripts/migrations-lock.d.ts +3 -0
  64. package/dist/scripts/migrations-lock.d.ts.map +1 -0
  65. package/dist/scripts/migrations-lock.js +46 -0
  66. package/dist/scripts/migrations-lock.js.map +1 -0
  67. package/dist/scripts/prepare-wrangler-config.d.ts +3 -0
  68. package/dist/scripts/prepare-wrangler-config.d.ts.map +1 -0
  69. package/dist/scripts/prepare-wrangler-config.js +50 -0
  70. package/dist/scripts/prepare-wrangler-config.js.map +1 -0
  71. package/dist/scripts/spa-shell.d.ts +41 -0
  72. package/dist/scripts/spa-shell.d.ts.map +1 -0
  73. package/dist/scripts/spa-shell.js +155 -0
  74. package/dist/scripts/spa-shell.js.map +1 -0
  75. package/dist/scripts/validate-locales.d.ts +26 -0
  76. package/dist/scripts/validate-locales.d.ts.map +1 -0
  77. package/dist/scripts/validate-locales.js +350 -0
  78. package/dist/scripts/validate-locales.js.map +1 -0
  79. package/dist/scripts/verify-migrations.d.ts +62 -0
  80. package/dist/scripts/verify-migrations.d.ts.map +1 -0
  81. package/dist/scripts/verify-migrations.js +302 -0
  82. package/dist/scripts/verify-migrations.js.map +1 -0
  83. package/dist/scripts/verify-spa-shell.d.ts +3 -0
  84. package/dist/scripts/verify-spa-shell.d.ts.map +1 -0
  85. package/dist/scripts/verify-spa-shell.js +53 -0
  86. package/dist/scripts/verify-spa-shell.js.map +1 -0
  87. package/dist/scripts/wrangler-config/cli.d.ts +22 -0
  88. package/dist/scripts/wrangler-config/cli.d.ts.map +1 -0
  89. package/dist/scripts/wrangler-config/cli.js +51 -0
  90. package/dist/scripts/wrangler-config/cli.js.map +1 -0
  91. package/dist/scripts/wrangler-config/patches.d.ts +51 -0
  92. package/dist/scripts/wrangler-config/patches.d.ts.map +1 -0
  93. package/dist/scripts/wrangler-config/patches.js +140 -0
  94. package/dist/scripts/wrangler-config/patches.js.map +1 -0
  95. package/dist/scripts/wrangler-config/resources.d.ts +70 -0
  96. package/dist/scripts/wrangler-config/resources.d.ts.map +1 -0
  97. package/dist/scripts/wrangler-config/resources.js +290 -0
  98. package/dist/scripts/wrangler-config/resources.js.map +1 -0
  99. package/dist/scripts/wrangler-config/types.d.ts +103 -0
  100. package/dist/scripts/wrangler-config/types.d.ts.map +1 -0
  101. package/dist/scripts/wrangler-config/types.js +49 -0
  102. package/dist/scripts/wrangler-config/types.js.map +1 -0
  103. package/dist/test/integration-migrations.d.ts +167 -0
  104. package/dist/test/integration-migrations.d.ts.map +1 -0
  105. package/dist/test/integration-migrations.js +171 -0
  106. package/dist/test/integration-migrations.js.map +1 -0
  107. package/dist/test/mocks/cloudflare-workers.d.ts +106 -0
  108. package/dist/test/mocks/cloudflare-workers.d.ts.map +1 -0
  109. package/dist/test/mocks/cloudflare-workers.js +90 -0
  110. package/dist/test/mocks/cloudflare-workers.js.map +1 -0
  111. package/dist/vite.d.ts +117 -0
  112. package/dist/vite.d.ts.map +1 -0
  113. package/dist/vite.js +125 -0
  114. package/dist/vite.js.map +1 -0
  115. package/dist/vitest-web.d.ts +73 -0
  116. package/dist/vitest-web.d.ts.map +1 -0
  117. package/dist/vitest-web.js +72 -0
  118. package/dist/vitest-web.js.map +1 -0
  119. package/dist/vitest.d.ts +92 -0
  120. package/dist/vitest.d.ts.map +1 -0
  121. package/dist/vitest.js +128 -0
  122. package/dist/vitest.js.map +1 -0
  123. package/package.json +58 -3
  124. package/src/eslint-boundaries.ts +169 -0
  125. package/src/eslint-rules.ts +276 -0
  126. package/src/eslint.test.ts +175 -0
  127. package/src/eslint.ts +257 -0
  128. package/src/functions/pages-proxy.test.ts +72 -0
  129. package/src/functions/pages-proxy.ts +187 -0
  130. package/src/github/actions/retry-step/action.yml +39 -0
  131. package/src/github/actions/setup-env/action.yml +20 -0
  132. package/src/github/dependabot.yml +30 -0
  133. package/src/github/workflows/backup-main.yml +46 -0
  134. package/src/github/workflows/continuous-deployment.yml +188 -0
  135. package/src/github/workflows/continuous-integration.yml +259 -0
  136. package/src/github/workflows/scheduled-version-update.yml +38 -0
  137. package/src/github/workflows/upstream-sync.yml +56 -0
  138. package/src/index.ts +42 -0
  139. package/src/scripts/backup/backup-rules.test.ts +105 -0
  140. package/src/scripts/backup/d1-target.ts +54 -0
  141. package/src/scripts/backup/destination-config.ts +92 -0
  142. package/src/scripts/backup/encrypt-backup.ts +107 -0
  143. package/src/scripts/backup/naming.ts +62 -0
  144. package/src/scripts/check-god-files.test.ts +131 -0
  145. package/src/scripts/check-god-files.ts +327 -0
  146. package/src/scripts/ensure-spa-shell-stub.ts +34 -0
  147. package/src/scripts/init-secrets.ts +265 -0
  148. package/src/scripts/lib/cli-args.ts +154 -0
  149. package/src/scripts/lib/github-actions.ts +41 -0
  150. package/src/scripts/lib/wrangler-table.ts +105 -0
  151. package/src/scripts/migrations-lock.ts +52 -0
  152. package/src/scripts/prepare-wrangler-config.ts +51 -0
  153. package/src/scripts/spa-shell.test.ts +91 -0
  154. package/src/scripts/spa-shell.ts +179 -0
  155. package/src/scripts/validate-locales.test.ts +89 -0
  156. package/src/scripts/validate-locales.ts +380 -0
  157. package/src/scripts/verify-migrations.test.ts +71 -0
  158. package/src/scripts/verify-migrations.ts +364 -0
  159. package/src/scripts/verify-spa-shell.ts +56 -0
  160. package/src/scripts/wrangler-config/cli.ts +51 -0
  161. package/src/scripts/wrangler-config/patches.ts +157 -0
  162. package/src/scripts/wrangler-config/resources.ts +330 -0
  163. package/src/scripts/wrangler-config/types.ts +113 -0
  164. package/src/test/integration-migrations.test.ts +169 -0
  165. package/src/test/integration-migrations.ts +267 -0
  166. package/src/test/mocks/cloudflare-workers.ts +115 -0
  167. package/src/vite.test.ts +83 -0
  168. package/src/vite.ts +202 -0
  169. package/src/vitest-web.ts +109 -0
  170. package/src/vitest.ts +185 -0
@@ -0,0 +1,273 @@
1
+ /**
2
+ * The rule-override blocks of the repo lint config.
3
+ *
4
+ * Extracted from `eslint.ts` with the boundary rules: each block is a plain
5
+ * rules object with the provenance comment that says *why* it is set to this
6
+ * value, because a per-rule decision with no reason attached is a decision the
7
+ * next reader re-litigates. `eslint.ts` composes these; this file is where a
8
+ * rule's story lives.
9
+ */
10
+ /**
11
+ * TypeScript rules, identical in all four source stacks.
12
+ */
13
+ export const TYPESCRIPT_RULES = {
14
+ '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
15
+ // Allow `void expr` for intentional fire-and-forget in Workers.
16
+ '@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }],
17
+ // Relax the unsafe-any rules to warn: the external API boundaries (Cloudflare
18
+ // bindings, provider SDKs) are typed `any` upstream, and the alternative is a
19
+ // config that cannot be adopted.
20
+ '@typescript-eslint/no-explicit-any': 'warn',
21
+ '@typescript-eslint/no-unsafe-assignment': 'warn',
22
+ '@typescript-eslint/no-unsafe-member-access': 'warn',
23
+ '@typescript-eslint/no-unsafe-call': 'warn',
24
+ '@typescript-eslint/no-unsafe-return': 'warn',
25
+ '@typescript-eslint/no-unsafe-argument': 'warn',
26
+ // JSX event handlers and hook callback objects commonly use async functions
27
+ // where void is expected.
28
+ '@typescript-eslint/no-misused-promises': ['error', { checksVoidReturn: { attributes: false, properties: false } }],
29
+ // An `async` function with no `await`: every handler and DAO method is
30
+ // `async` by shape so a future `await` does not change its signature.
31
+ '@typescript-eslint/require-await': 'off',
32
+ // `await` on a value the types say is not thenable, where the value is a
33
+ // `PromiseLike` from an interface declared that way.
34
+ '@typescript-eslint/await-thenable': 'off',
35
+ };
36
+ /**
37
+ * Unicorn and SonarJS rules carried from the source repos, each off for a
38
+ * stated reason.
39
+ *
40
+ * This is the family's "deliberately does not follow" block: every entry is
41
+ * off because complying would make the code worse for what the project is,
42
+ * and each is listed rather than dropped so the decision stays reviewable.
43
+ */
44
+ export const UNICORN_RULES = {
45
+ // Codebase uses ctx, req, res, env, err, util, db, dao, etc. — too invasive
46
+ // to rename.
47
+ 'unicorn/prevent-abbreviations': 'off',
48
+ // D1/DAO layer returns null; disabling this avoids mass rewrites.
49
+ 'unicorn/no-null': 'off',
50
+ // Monorepo uses CommonJS-compatible module style in some configs.
51
+ 'unicorn/prefer-module': 'off',
52
+ // Top-level await not available in all Workers entry points.
53
+ 'unicorn/prefer-top-level-await': 'off',
54
+ // Error subclassing via `new MyError()` is intentional in backend-errors.
55
+ 'unicorn/custom-error-definition': 'off',
56
+ // Allow process.exit in build/script files.
57
+ 'unicorn/no-process-exit': 'off',
58
+ // Array reduce is used intentionally in analytics/data transformation.
59
+ 'unicorn/no-array-reduce': 'off',
60
+ // Allow Number() — parseInt/parseFloat are used in some cases intentionally.
61
+ 'unicorn/prefer-number-properties': ['error', { checkInfinity: false }],
62
+ // Allow nested ternaries in JSX (React render patterns).
63
+ 'unicorn/no-nested-ternary': 'off',
64
+ // Allow Array.from — codebase uses it for iterables.
65
+ 'unicorn/prefer-spread': 'off',
66
+ // Entire codebase uses PascalCase for TS files; kebab-case would require
67
+ // mass renames.
68
+ 'unicorn/filename-case': 'off',
69
+ // Established names should not be force-renamed.
70
+ 'unicorn/name-replacements': 'off',
71
+ // Zod schema builder chains and other deep method chains are intentional.
72
+ 'unicorn/max-nested-calls': 'off',
73
+ // import.meta.dirname is not available in all test environments.
74
+ 'unicorn/prefer-import-meta-properties': 'off',
75
+ // Codebase uses `err` as catch parameter name throughout.
76
+ 'unicorn/catch-error-name': 'off',
77
+ // Established boolean param names (retryable, enabled, etc.).
78
+ 'unicorn/consistent-boolean-name': 'off',
79
+ // Uint8Array#toBase64 / fromBase64 are not in all Workers runtime versions.
80
+ 'unicorn/prefer-uint8array-base64': 'off',
81
+ // Class member ordering would require extensive restructuring.
82
+ 'unicorn/consistent-class-member-order': 'off',
83
+ // API response fields use verb prefixes by convention.
84
+ 'unicorn/no-non-function-verb-prefix': 'off',
85
+ // forEach is used intentionally throughout the provider and utility layers.
86
+ 'unicorn/no-for-each': 'off',
87
+ // .then() chains in DAO and provider layers are often intentional.
88
+ 'unicorn/prefer-await': 'warn',
89
+ // Callback references (e.g. .map(Number)) are sometimes intentional.
90
+ 'unicorn/no-array-callback-reference': 'warn',
91
+ // toSorted() is ES2023 and may not be in all tsconfig lib targets.
92
+ 'unicorn/no-array-sort': 'warn',
93
+ // Early-return guard clauses are the established style; the rule only
94
+ // rewrites the final guard of a ladder, which yields asymmetric mixed style
95
+ // and long inline ternaries. Off in Mail-Meow and Edge-Sonic; canonical here
96
+ // because it is the family's established style.
97
+ 'unicorn/prefer-ternary': 'off',
98
+ // `(await x).y` -> a named intermediate. Fires constantly in the tests,
99
+ // where destructuring beside the assertion it serves is clearer.
100
+ 'unicorn/no-await-expression-member': 'off',
101
+ // `Number(x)` over `+x`: the `+` form is used where an explicit typeof check
102
+ // has already narrowed the operand.
103
+ 'unicorn/prefer-number-coercion': 'off',
104
+ // Code-point iteration: the byte-level readers index deliberately, because
105
+ // the offset *is* what they are reading.
106
+ 'unicorn/prefer-code-point': 'off',
107
+ // `if (!x) return;` over a compound condition: one guard per line, each with
108
+ // its own comment, is what keeps endpoint guards readable.
109
+ 'unicorn/prefer-simple-condition-first': 'off',
110
+ // Module-scope `let` assigned from `beforeEach` in the test harnesses.
111
+ 'unicorn/no-top-level-assignment-in-function': 'off',
112
+ // Sequential `for...of` with `await` in the DAOs — D1's subrequest budget is
113
+ // the scarce resource.
114
+ 'unicorn/no-unreadable-for-of-expression': 'off',
115
+ // `Object.hasOwn` over `in`: used where a prototype-chain hit is harmless.
116
+ 'unicorn/no-computed-property-existence-check': 'off',
117
+ // A labeled `break` out of two loops.
118
+ 'unicorn/no-break-in-nested-loop': 'off',
119
+ // `this` outside a class body: the module-level cache singletons document
120
+ // their `this` contract in prose.
121
+ 'unicorn/no-this-outside-of-class': 'off',
122
+ // A class named inside its own static method.
123
+ 'unicorn/class-reference-in-static-methods': 'off',
124
+ // Assigning `globalThis.fetch` in a test — the only way to intercept the
125
+ // ambient fetch in Node without a module mock.
126
+ 'unicorn/no-global-object-property-assignment': 'off',
127
+ // `(a ? b : c) && d`: written longhand so each precedence decision is
128
+ // visible.
129
+ 'unicorn/prefer-logical-operator-over-ternary': 'off',
130
+ // `children[0]` in the XML helpers, which index a child list positionally.
131
+ 'unicorn/better-dom-traversing': 'off',
132
+ // `entries()` -> `keys()`/`values()`: the full entry is destructured.
133
+ 'unicorn/prefer-iterator-to-array': 'off',
134
+ // `.map(fn, thisArg)`: rejected on purpose.
135
+ 'unicorn/no-array-method-this-argument': 'off',
136
+ // A module-scope function that closes over nothing.
137
+ 'unicorn/consistent-function-scoping': 'off',
138
+ // `foo[0] === 'a' || foo[0] === 'b'` written longhand where the
139
+ // alternatives are not adjacent.
140
+ 'unicorn/prefer-includes-over-repeated-comparisons': 'off',
141
+ // A `type` alias over an inline union, where the name is what makes the
142
+ // signature and its doc comment readable.
143
+ 'sonarjs/use-type-alias': 'off',
144
+ // A short local alias for a type imported from a protocol package.
145
+ 'sonarjs/redundant-type-aliases': 'off',
146
+ // `type: value` narrowing the other way, where both spellings appear in the
147
+ // same schema and the code follows whichever the spec uses there.
148
+ 'sonarjs/no-nested-assignment': 'off',
149
+ // `Number.isInteger` plus a separate range check, where the bounds come from
150
+ // the caller's own options in one place.
151
+ 'unicorn/prefer-number-is-safe-integer': 'off',
152
+ // `\u{...}` over a `\xNN` escape: the table is written in the byte form the
153
+ // spec prints.
154
+ 'unicorn/prefer-unicode-code-point-escapes': 'off',
155
+ // `self.x = this.x` in an entry model: the alias makes the verbatim
156
+ // round-trip explicit.
157
+ 'unicorn/no-this-assignment': 'off',
158
+ // Building a `Set` at module scope from a constant list, for O(1) membership
159
+ // on a path that runs per parameter.
160
+ 'unicorn/no-top-level-side-effects': 'off',
161
+ // A conditional whose branches are identical, kept where the two branches
162
+ // are named separately to document that they are meant to diverge.
163
+ 'sonarjs/no-all-duplicated-branches': 'off',
164
+ // An `else` after a `return`: the flat form keeps the remaining cases at one
165
+ // indent level in the dispatch tables.
166
+ 'unicorn/prefer-else-if': 'off',
167
+ // A nested ternary in a sort comparator, where the three-way order is the
168
+ // point.
169
+ 'unicorn/prefer-minimal-ternary': 'off',
170
+ // `void promise` where initiating the call is the point and the rejection is
171
+ // handled at a named site elsewhere.
172
+ 'sonarjs/void-use': 'off',
173
+ // `x === undefined` reported as always-true/false. With
174
+ // `noUncheckedIndexedAccess` on, the guard is exactly right.
175
+ 'sonarjs/different-types-comparison': 'off',
176
+ // An accumulating loop with a sequential `await` in it, over D1 writes.
177
+ 'unicorn/prefer-array-from-async': 'off',
178
+ };
179
+ /**
180
+ * SonarJS rules the sources turned from errors into advisories, with the
181
+ * threshold raised to a value that has actually held.
182
+ */
183
+ export const SONARJS_RULES = {
184
+ // Raise duplicate-string threshold to avoid flagging intentional repeated
185
+ // literals like provider IDs.
186
+ 'sonarjs/no-duplicate-string': ['warn', { threshold: 5 }],
187
+ // Cognitive complexity — warn rather than error, so the ratchet can move
188
+ // without a red build. Raise the number only as files are decomposed.
189
+ 'sonarjs/cognitive-complexity': ['warn', 20],
190
+ // False positives: connection method names like 'imap-password' and field
191
+ // names like 'password_hash'.
192
+ 'sonarjs/no-hardcoded-passwords': 'off',
193
+ // Third-party deprecations are warnings, not errors.
194
+ 'sonarjs/deprecation': 'warn',
195
+ // Nested ternaries in complex data-mapping code.
196
+ 'sonarjs/no-nested-conditional': 'warn',
197
+ // React component props are commonly not marked Readonly<>.
198
+ 'sonarjs/prefer-read-only-props': 'warn',
199
+ // Static readonly properties require invasive refactoring.
200
+ 'sonarjs/public-static-readonly': 'warn',
201
+ // Nested template literals in SQL queries and prompt construction.
202
+ 'sonarjs/no-nested-template-literals': 'warn',
203
+ };
204
+ /**
205
+ * Test-suite overrides.
206
+ *
207
+ * `test/**` is deliberately *not* in the config's ignores list. Durable-DAV,
208
+ * AWS and Mail-Meow all ignored it, and ~200 KB of test code had accumulated
209
+ * violations that nothing reported. This block puts the suite back under the
210
+ * same rules as the rest of the workspace and switches off only the handful
211
+ * whose findings are structural artefacts of test code rather than defects.
212
+ * It does not disable correctness rules: the unused-variable, dead-store,
213
+ * regex and sorting findings in the suite are real and are fixed, not
214
+ * suppressed.
215
+ */
216
+ export const TEST_RULES = {
217
+ // `it('…', async () => …)` is the Vitest idiom.
218
+ '@typescript-eslint/no-misused-promises': ['error', { checksVoidReturn: { arguments: false, attributes: false } }],
219
+ // Unbound method is a common false positive in mock assertions like
220
+ // expect(fn).toHaveBeenCalledWith(...).
221
+ '@typescript-eslint/unbound-method': 'off',
222
+ // Test helpers and stubs routinely use async functions without await.
223
+ '@typescript-eslint/require-await': 'off',
224
+ // Redundant type constituents appear in typed mock stubs.
225
+ '@typescript-eslint/no-redundant-type-constituents': 'off',
226
+ // `as never` casts are the standard fake-DB double pattern in tests.
227
+ '@typescript-eslint/no-unnecessary-type-assertion': 'off',
228
+ // Promise.withResolvers() and function-scoping refactors are cosmetic.
229
+ 'unicorn/prefer-promise-with-resolvers': 'off',
230
+ 'unicorn/consistent-function-scoping': 'off',
231
+ // Fake-DB builders push-then-return and sort without comparators.
232
+ 'unicorn/no-return-array-push': 'off',
233
+ 'unicorn/require-array-sort-compare': 'off',
234
+ // Iterator-helper rewrites churn test fakes with no runtime benefit.
235
+ 'unicorn/prefer-iterator-helpers': 'off',
236
+ 'unicorn/prefer-iterator-to-array': 'off',
237
+ // String replacement with test-driven values is intentional in assertions.
238
+ 'unicorn/no-unsafe-string-replacement': 'off',
239
+ // Fake-D1 doubles await a DAO thunk and call straight onto the result.
240
+ 'unicorn/no-await-expression-member': 'off',
241
+ // `void promise` marks a deliberately unawaited promise in a test.
242
+ 'sonarjs/void-use': 'off',
243
+ // A test asserting request routing has to name `http://` hosts, and a proxy
244
+ // test has to name a loopback upstream. Both are the subject matter, not
245
+ // leaked configuration. `unicorn/prefer-https` must stay off here and this
246
+ // is not a style preference: it rewrites `http://` to `https://` *inside
247
+ // string literals*, and `--fix` applies it silently.
248
+ 'sonarjs/no-clear-text-protocols': 'off',
249
+ 'sonarjs/no-hardcoded-ip': 'off',
250
+ 'unicorn/prefer-https': 'off',
251
+ // sonarjs/assertions-in-tests fires false positives when test helpers handle
252
+ // assertions indirectly.
253
+ 'sonarjs/assertions-in-tests': 'off',
254
+ // sonarjs/no-extra-arguments fires incorrectly on Vitest mock overloads.
255
+ 'sonarjs/no-extra-arguments': 'off',
256
+ // Union/inline types in test fakes are more readable than aliases.
257
+ 'sonarjs/use-type-alias': 'off',
258
+ // Alphabetical-sort rule fights deterministic fixture ordering.
259
+ 'sonarjs/no-alphabetical-sort': 'off',
260
+ // Repeated string literals in fixtures/assertions are clearer inline.
261
+ 'sonarjs/no-duplicate-string': 'off',
262
+ // Fake-D1 doubles break out of a nested loop to model a statement miss.
263
+ 'unicorn/no-break-in-nested-loop': 'off',
264
+ // Fixtures are naturally built with sort()/for…of over composed expressions.
265
+ 'unicorn/no-array-sort': 'off',
266
+ 'unicorn/no-unreadable-for-of-expression': 'off',
267
+ 'unicorn/no-useless-template-literals': 'off',
268
+ 'unicorn/no-declarations-before-early-exit': 'off',
269
+ 'unicorn/prefer-includes-over-repeated-comparisons': 'off',
270
+ 'sonarjs/prefer-specific-assertions': 'off',
271
+ 'sonarjs/no-inverted-boolean-check': 'off',
272
+ };
273
+ //# sourceMappingURL=eslint-rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslint-rules.js","sourceRoot":"","sources":["../src/eslint-rules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * The converged ESLint flat config for a monorepo in the Rexezuge family.
3
+ *
4
+ * Provenance: the base is Durable-DAV's `eslint.config.mjs` (380+ lines, the most
5
+ * elaborate of the nine repos, with the layered `no-restricted-imports` boundary
6
+ * rules). Merged in from the other three stacks that share the same plugin set:
7
+ *
8
+ * - **Edge-Sonic** — `test/**` is *not* ignored (it is linted like everything else,
9
+ * with a narrow override block for Vitest idioms), and `unicorn/prefer-ternary`
10
+ * is off. Edge-Sonic is also the source for the dynamic-`import()` boundary
11
+ * guard and its `apps/web` layer block.
12
+ * - **Mail-Meow** — `prettier/prettier` is an **error**, not a warning.
13
+ * - **AWS-AccessBridge** — the `apps/api` DAO/service boundary uses
14
+ * `allowTypeImports` where the source repos do not. It is also the source for
15
+ * the anchored skip patterns and the symlink-safe walk that came out of its own
16
+ * backlog.
17
+ *
18
+ * Canonical decisions, and why each one:
19
+ *
20
+ * 1. **`prettier/prettier: 'error'`.** Three of the four source repos had it at
21
+ * `warn`, which under `eslint --quiet` is unenforceable — a gate nobody can see
22
+ * is a gate that has never run. Formatting drift is therefore a hard failure.
23
+ * 2. **The layered boundary rules are parameterized by `scope`.** Every source
24
+ * repo wrote the same seven blocks with a different npm scope hardcoded; the
25
+ * factory takes `scope` (`'@myapp'`) and generates the `@myapp/*` patterns.
26
+ * The table itself lives in {@link ./eslint-boundaries}.
27
+ * 3. **`test/**` is linted, not ignored.** Durable-DAV/AWS/Mail-Meow ignored it;
28
+ * Edge-Sonic does not, and records why: ~200 KB of test code had accumulated
29
+ * violations that nothing reported.
30
+ * 4. **`apps/web` is a layer in its own right**, banned from every `@scope/*`
31
+ * package. Edge-Sonic is the only source with that block; the others had none,
32
+ * which is how their layer table's "may import: the browser" was a convention
33
+ * rather than a gate. A backend package imported by the SPA compiles and then
34
+ * fails at bundle time, with the error pointing at the bundler.
35
+ * 5. **jsdom + node globals for web files.** The sources ran `globals.node` only;
36
+ * `apps/web` needs browser globals as well, and the vitest config for the SPA
37
+ * runs under jsdom, so the lint environment matches the test environment.
38
+ * 6. **`eslint-plugin-react-hooks` is NOT imported here.** The kit stays
39
+ * zero-dependency, and the plugin belongs to the app that has JSX. A consumer
40
+ * appends it — the README shows the four lines.
41
+ *
42
+ * The rule bodies live in {@link ./eslint-rules} and the boundary table in
43
+ * {@link ./eslint-boundaries}; this file is the assembly. A repo that needs a
44
+ * boundary the canonical table does not name passes `extraLayers` — see
45
+ * {@link RepoLintConfigOptions}.
46
+ */
47
+ import type { FlatConfig } from 'typescript-eslint';
48
+ import type { LayerBan } from './eslint-boundaries';
49
+ /**
50
+ * What `defineRepoLintConfig` accepts.
51
+ */
52
+ export interface RepoLintConfigOptions {
53
+ /**
54
+ * The consuming repo's npm scope, e.g. `'@myapp'`. Every `no-restricted-imports`
55
+ * pattern in the boundary rules is derived from it, so the same factory serves
56
+ * all nine repos.
57
+ */
58
+ readonly scope: string;
59
+ /**
60
+ * The workspace directories the layered boundary rules are scoped to, as repo-
61
+ * relative globs. Defaults to the canonical layout the nine repos share.
62
+ */
63
+ readonly projectDirs?: readonly string[];
64
+ /**
65
+ * Extra ignore globs, merged with the canonical set.
66
+ */
67
+ readonly extraIgnores?: readonly string[];
68
+ /**
69
+ * Where `projectService` resolves the tsconfig from. Defaults to the directory
70
+ * ESLint is invoked in, which is the repo root in every CI job.
71
+ */
72
+ readonly tsconfigRootDir?: string;
73
+ /**
74
+ * Extra boundary layers, appended to the canonical table.
75
+ *
76
+ * The escape valve for a repo whose layout has a boundary the canonical table
77
+ * does not name — AWS-AccessBridge's `apps/api/src/endpoints/**` rule ("route
78
+ * classes must not import DAOs directly") and its `aws4fetch` ban are the shape.
79
+ * Same {@link LayerBan} form, so `extraLayers` flows through the
80
+ * `no-restricted-imports` and the `no-restricted-syntax` guard alike.
81
+ */
82
+ readonly extraLayers?: readonly LayerBan[];
83
+ }
84
+ /**
85
+ * Build the repo's flat config.
86
+ *
87
+ * Consumed from the repo root as three lines:
88
+ *
89
+ * ```js
90
+ * // eslint.config.mjs
91
+ * import { defineRepoLintConfig } from '@rexezuge/tooling/eslint';
92
+ * export default defineRepoLintConfig({ scope: '@myapp' });
93
+ * ```
94
+ */
95
+ export declare function defineRepoLintConfig(options: RepoLintConfigOptions): FlatConfig.ConfigArray;
96
+ //# sourceMappingURL=eslint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslint.d.ts","sourceRoot":"","sources":["../src/eslint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AASH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC;;OAEG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC;;;;;;;;OAQG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;CAC5C;AAsCD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,UAAU,CAAC,WAAW,CAkH3F"}
package/dist/eslint.js ADDED
@@ -0,0 +1,189 @@
1
+ /**
2
+ * The converged ESLint flat config for a monorepo in the Rexezuge family.
3
+ *
4
+ * Provenance: the base is Durable-DAV's `eslint.config.mjs` (380+ lines, the most
5
+ * elaborate of the nine repos, with the layered `no-restricted-imports` boundary
6
+ * rules). Merged in from the other three stacks that share the same plugin set:
7
+ *
8
+ * - **Edge-Sonic** — `test/**` is *not* ignored (it is linted like everything else,
9
+ * with a narrow override block for Vitest idioms), and `unicorn/prefer-ternary`
10
+ * is off. Edge-Sonic is also the source for the dynamic-`import()` boundary
11
+ * guard and its `apps/web` layer block.
12
+ * - **Mail-Meow** — `prettier/prettier` is an **error**, not a warning.
13
+ * - **AWS-AccessBridge** — the `apps/api` DAO/service boundary uses
14
+ * `allowTypeImports` where the source repos do not. It is also the source for
15
+ * the anchored skip patterns and the symlink-safe walk that came out of its own
16
+ * backlog.
17
+ *
18
+ * Canonical decisions, and why each one:
19
+ *
20
+ * 1. **`prettier/prettier: 'error'`.** Three of the four source repos had it at
21
+ * `warn`, which under `eslint --quiet` is unenforceable — a gate nobody can see
22
+ * is a gate that has never run. Formatting drift is therefore a hard failure.
23
+ * 2. **The layered boundary rules are parameterized by `scope`.** Every source
24
+ * repo wrote the same seven blocks with a different npm scope hardcoded; the
25
+ * factory takes `scope` (`'@myapp'`) and generates the `@myapp/*` patterns.
26
+ * The table itself lives in {@link ./eslint-boundaries}.
27
+ * 3. **`test/**` is linted, not ignored.** Durable-DAV/AWS/Mail-Meow ignored it;
28
+ * Edge-Sonic does not, and records why: ~200 KB of test code had accumulated
29
+ * violations that nothing reported.
30
+ * 4. **`apps/web` is a layer in its own right**, banned from every `@scope/*`
31
+ * package. Edge-Sonic is the only source with that block; the others had none,
32
+ * which is how their layer table's "may import: the browser" was a convention
33
+ * rather than a gate. A backend package imported by the SPA compiles and then
34
+ * fails at bundle time, with the error pointing at the bundler.
35
+ * 5. **jsdom + node globals for web files.** The sources ran `globals.node` only;
36
+ * `apps/web` needs browser globals as well, and the vitest config for the SPA
37
+ * runs under jsdom, so the lint environment matches the test environment.
38
+ * 6. **`eslint-plugin-react-hooks` is NOT imported here.** The kit stays
39
+ * zero-dependency, and the plugin belongs to the app that has JSX. A consumer
40
+ * appends it — the README shows the four lines.
41
+ *
42
+ * The rule bodies live in {@link ./eslint-rules} and the boundary table in
43
+ * {@link ./eslint-boundaries}; this file is the assembly. A repo that needs a
44
+ * boundary the canonical table does not name passes `extraLayers` — see
45
+ * {@link RepoLintConfigOptions}.
46
+ */
47
+ import globals from 'globals';
48
+ import tseslint from 'typescript-eslint';
49
+ import unicorn from 'eslint-plugin-unicorn';
50
+ import { configs as sonarjsConfigs } from 'eslint-plugin-sonarjs';
51
+ import pluginRegexp from 'eslint-plugin-regexp';
52
+ import eslintConfigPrettier from 'eslint-config-prettier';
53
+ import prettier from 'eslint-plugin-prettier';
54
+ import { DEFAULT_PROJECT_DIRS, layerBans, restrictedDynamicImports, restrictedImports } from './eslint-boundaries';
55
+ import { SONARJS_RULES, TEST_RULES, TYPESCRIPT_RULES, UNICORN_RULES } from './eslint-rules';
56
+ /**
57
+ * Bridge a third-party preset into `tseslint.config()`.
58
+ *
59
+ * `sonarjs`' `recommended` preset is typed as a union that includes the legacy
60
+ * config shape, which `tseslint.config()` does not accept — but ESLint accepts it
61
+ * at runtime, which is the only thing that matters here. One checked assertion,
62
+ * rather than forking the plugin's own types.
63
+ */
64
+ function asConfig(config) {
65
+ return config;
66
+ }
67
+ /**
68
+ * Bridge a rule block onto `tseslint.config()`'s `rules` field.
69
+ *
70
+ * The blocks in `eslint-rules.ts` are written as ESLint expects them —
71
+ * `'off' | 'warn' | 'error' | [level, ...options]` — but spelled as data so a
72
+ * rule's reason comment sits beside the rule itself. ESLint's own `RuleEntry`
73
+ * union is narrower than the data shape, and widening every entry to that union
74
+ * would buy nothing; one assertion here, with the reason, is the cheaper and
75
+ * more honest of the two.
76
+ */
77
+ function asRules(block) {
78
+ return block;
79
+ }
80
+ /**
81
+ * Build the repo's flat config.
82
+ *
83
+ * Consumed from the repo root as three lines:
84
+ *
85
+ * ```js
86
+ * // eslint.config.mjs
87
+ * import { defineRepoLintConfig } from '@rexezuge/tooling/eslint';
88
+ * export default defineRepoLintConfig({ scope: '@myapp' });
89
+ * ```
90
+ */
91
+ export function defineRepoLintConfig(options) {
92
+ const { scope } = options;
93
+ const projectDirs = options.projectDirs ?? DEFAULT_PROJECT_DIRS;
94
+ const canonical = layerBans(scope).filter((layer) => projectDirs.some((dir) => layer.dir.startsWith(dir)));
95
+ const extra = options.extraLayers ?? [];
96
+ const bans = [...canonical, ...extra];
97
+ return tseslint.config({
98
+ ignores: [
99
+ 'eslint.config.mjs',
100
+ 'eslint.config.js',
101
+ 'scripts/**',
102
+ 'worker-configuration.d.ts',
103
+ 'local/**',
104
+ 'app/dist/**',
105
+ 'apps/web/dist/**',
106
+ 'apps/*/dist/**',
107
+ 'src/generated/**',
108
+ 'apps/api/src/generated/**',
109
+ 'coverage/**',
110
+ 'coverage-integration/**',
111
+ 'coverage-web/**',
112
+ 'node_modules/**',
113
+ ...(options.extraIgnores ?? []),
114
+ ],
115
+ },
116
+ // Base: globals for all JS/TS source files. Node is the floor because the
117
+ // scripts and the workers both run on it; the web block below adds browser
118
+ // globals rather than replacing them, so a shared file that touches both
119
+ // (there are several in `shared/`) still lints.
120
+ {
121
+ files: ['**/*.{js,mjs,cjs,ts,mts,cts,tsx,jsx}'],
122
+ languageOptions: {
123
+ globals: globals.node,
124
+ },
125
+ },
126
+ // Type-aware TS rules, scoped to TS files only.
127
+ {
128
+ files: ['**/*.{ts,mts,cts,tsx}'],
129
+ extends: tseslint.configs.recommendedTypeChecked,
130
+ languageOptions: {
131
+ parserOptions: {
132
+ projectService: true,
133
+ tsconfigRootDir: options.tsconfigRootDir ?? process.cwd(),
134
+ },
135
+ },
136
+ },
137
+ // --- typescript-eslint overrides (identical in all four source stacks) ---
138
+ {
139
+ files: ['**/*.{ts,mts,cts,tsx}'],
140
+ rules: asRules(TYPESCRIPT_RULES),
141
+ },
142
+ // --- Unicorn: modern JS/TS quality rules ---
143
+ asConfig(unicorn.configs['flat/recommended']), {
144
+ rules: asRules(UNICORN_RULES),
145
+ },
146
+ // --- SonarJS: code smell and bug detection ---
147
+ asConfig(sonarjsConfigs.recommended), {
148
+ rules: asRules(SONARJS_RULES),
149
+ },
150
+ // --- Regexp: static analysis for regular expressions ---
151
+ asConfig(pluginRegexp.configs['flat/recommended']),
152
+ // --- Prettier: formatting drift is a hard error ---
153
+ //
154
+ // Mail-Meow's decision, adopted repo-wide because the alternative is
155
+ // unenforceable: `pnpm run lint` is `eslint --fix --quiet` in three of the
156
+ // four source repos, and `--quiet` discards every warning, so a
157
+ // `prettier/prettier` *warning* is a silent no-op. 242 files were in that
158
+ // state in Edge-Sonic: the gate had never run.
159
+ asConfig(eslintConfigPrettier), {
160
+ plugins: { prettier },
161
+ rules: {
162
+ 'prettier/prettier': 'error',
163
+ },
164
+ },
165
+ // --- Import direction guardrails (parameterized by scope) ---
166
+ ...restrictedImports(bans), ...restrictedDynamicImports(bans),
167
+ // --- Web: browser globals, matching the jsdom test environment ---
168
+ //
169
+ // The sources linted `apps/web` under `globals.node` only, so `window`,
170
+ // `document` and `localStorage` read as undefined globals. The vitest web
171
+ // config runs those suites under jsdom; the lint environment should agree
172
+ // with the environment the code is executed in, or the rule is reporting
173
+ // something untrue about how the file behaves.
174
+ {
175
+ files: ['apps/web/**/*.{ts,tsx,js,jsx,mts,cts,mjs,cjs}'],
176
+ languageOptions: {
177
+ globals: { ...globals.node, ...globals.browser },
178
+ },
179
+ },
180
+ // --- Test suite ---
181
+ //
182
+ // `test/**` is deliberately NOT in the ignores list above. See TEST_RULES
183
+ // for the override block and the reasoning behind it.
184
+ {
185
+ files: ['test/**/*.{ts,tsx,mts,cts}', '**/*.test.{ts,tsx,mts,cts}', '**/*.spec.{ts,tsx,mts,cts}'],
186
+ rules: asRules(TEST_RULES),
187
+ });
188
+ }
189
+ //# sourceMappingURL=eslint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslint.js","sourceRoot":"","sources":["../src/eslint.ts"],"names":[],"mappings":"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"}