@rexezuge/tooling 1.0.0 → 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.
@@ -0,0 +1,75 @@
1
+ import type tseslint from 'typescript-eslint';
2
+ /**
3
+ * The layer table behind the repo lint config's import boundaries.
4
+ *
5
+ * Provenance: the seven `no-restricted-imports` blocks in Durable-DAV's
6
+ * `eslint.config.mjs`, with `@durable-dav/` replaced by the caller's scope.
7
+ * Extracted from `eslint.ts` so the boundary rules — the part a repo actually
8
+ * argues about — are their own module rather than the tail of a 640-line
9
+ * config file.
10
+ *
11
+ * The table is data rather than inline blocks so the dynamic-`import()` guard
12
+ * is generated from the same list: a rule that derived its banned set from
13
+ * another rule's configuration would be a second source of truth for the layer
14
+ * table, and that table is what the docs describe.
15
+ */
16
+ /**
17
+ * The directories the boundary rules cover, in the canonical layout.
18
+ *
19
+ * Kept here, beside the table it scopes: `defineRepoLintConfig` filters the
20
+ * canonical layers by `projectDirs`, and a reader of the layer table should not
21
+ * have to open the config assembly to learn which directories it covers.
22
+ */
23
+ export declare const DEFAULT_PROJECT_DIRS: readonly string[];
24
+ /**
25
+ * One layer's ban list, as the repo-relative package suffixes it may not import.
26
+ *
27
+ * Converged from the four source stacks. `backend-data` and `backend-services`
28
+ * appear in all four; `webdav`/`dav-store` are Durable-DAV's, `provider-clients`
29
+ * is Mail-Meow's and AWS's. A layer only bans what exists in its repo, so the
30
+ * union is safe: a repo without `provider-clients` simply never imports it.
31
+ */
32
+ export interface LayerBan {
33
+ /** Directory the rule is scoped to. */
34
+ readonly dir: string;
35
+ /** Package suffixes (relative to `scope`) that may not be imported from here. */
36
+ readonly ban: readonly string[];
37
+ /** Message shown when the rule fires. */
38
+ readonly message: string;
39
+ /** Type-only imports are allowed, for the DAO boundary in `apps/api`. */
40
+ readonly allowTypeImports?: boolean;
41
+ }
42
+ /**
43
+ * The layer table, parameterized by `scope`.
44
+ */
45
+ export declare function layerBans(scope: string): readonly LayerBan[];
46
+ /**
47
+ * One argument to `tseslint.config()`, named here so the boundary builders
48
+ * return the assembled type rather than a lookalike the assembly then has to
49
+ * be argued into accepting.
50
+ */
51
+ type ConfigInput = Parameters<typeof tseslint.config>[number];
52
+ /**
53
+ * The `no-restricted-imports` entries for one layer.
54
+ *
55
+ * Written as `group` patterns rather than exact `paths`, so `@myapp/backend-data`
56
+ * and `@myapp/backend-data/dao` are both caught by one entry. `allowTypeImports`
57
+ * is passed through only where the source repos set it, because `apps/api`
58
+ * legitimately types its filters and models against DAO shapes.
59
+ */
60
+ export declare function restrictedImports(bans: readonly LayerBan[]): ConfigInput[];
61
+ /**
62
+ * The dynamic-`import()` guard, generated from the same table.
63
+ *
64
+ * `no-restricted-imports` reads `ImportDeclaration` nodes only; a dynamic
65
+ * `import()` is an `ImportExpression`, and this ESLint version does not report it
66
+ * under that rule at all. Edge-Sonic verified this rather than assumed it — a
67
+ * static import of a restricted specifier from the same file is an `error`, and
68
+ * the identical specifier reached through `await import(...)` is silent. That
69
+ * hole was load-bearing there: the credential path reached a banned module
70
+ * through it. `no-restricted-syntax` sees `ImportExpression`, so the boundary is
71
+ * stated a second way.
72
+ */
73
+ export declare function restrictedDynamicImports(bans: readonly LayerBan[]): ConfigInput[];
74
+ export {};
75
+ //# sourceMappingURL=eslint-boundaries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslint-boundaries.d.ts","sourceRoot":"","sources":["../src/eslint-boundaries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAC;AAE9C;;;;;;;;;;;;;GAaG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EASjD,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,uCAAuC;IACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,yCAAyC;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,QAAQ,EAAE,CAmD5D;AAED;;;;GAIG;AACH,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9D;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,GAAG,WAAW,EAAE,CAgB1E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,GAAG,WAAW,EAAE,CAajF"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * The layer table behind the repo lint config's import boundaries.
3
+ *
4
+ * Provenance: the seven `no-restricted-imports` blocks in Durable-DAV's
5
+ * `eslint.config.mjs`, with `@durable-dav/` replaced by the caller's scope.
6
+ * Extracted from `eslint.ts` so the boundary rules — the part a repo actually
7
+ * argues about — are their own module rather than the tail of a 640-line
8
+ * config file.
9
+ *
10
+ * The table is data rather than inline blocks so the dynamic-`import()` guard
11
+ * is generated from the same list: a rule that derived its banned set from
12
+ * another rule's configuration would be a second source of truth for the layer
13
+ * table, and that table is what the docs describe.
14
+ */
15
+ /**
16
+ * The directories the boundary rules cover, in the canonical layout.
17
+ *
18
+ * Kept here, beside the table it scopes: `defineRepoLintConfig` filters the
19
+ * canonical layers by `projectDirs`, and a reader of the layer table should not
20
+ * have to open the config assembly to learn which directories it covers.
21
+ */
22
+ export const DEFAULT_PROJECT_DIRS = [
23
+ 'packages/shared',
24
+ 'packages/backend-errors',
25
+ 'packages/backend-runtime',
26
+ 'packages/backend-data',
27
+ 'packages/backend-services',
28
+ 'apps/api',
29
+ 'apps/background',
30
+ 'apps/web',
31
+ ];
32
+ /**
33
+ * The layer table, parameterized by `scope`.
34
+ */
35
+ export function layerBans(scope) {
36
+ const at = (name) => `${scope}/${name}`;
37
+ return [
38
+ {
39
+ dir: 'packages/shared',
40
+ ban: [at('*')],
41
+ message: `${scope} packages must not import from other ${scope} packages — this is a zero-dependency base layer`,
42
+ },
43
+ {
44
+ dir: 'packages/backend-errors',
45
+ ban: [at('*')],
46
+ message: `${scope} packages must not import from other ${scope} packages — this is a zero-dependency base layer`,
47
+ },
48
+ {
49
+ dir: 'packages/backend-runtime',
50
+ ban: [at('backend-data'), at('webdav'), at('backend-services'), at('api'), at('background')],
51
+ message: 'backend-runtime must not import from a higher layer',
52
+ },
53
+ {
54
+ dir: 'packages/backend-data',
55
+ ban: [at('backend-runtime'), at('webdav'), at('backend-services'), at('api'), at('background')],
56
+ message: 'backend-data must not import from a higher layer',
57
+ },
58
+ {
59
+ dir: 'packages/backend-services',
60
+ ban: [at('api'), at('background')],
61
+ message: 'backend-services must not import from apps',
62
+ },
63
+ {
64
+ dir: 'apps/api',
65
+ ban: [at('backend-data/dao'), at('backend-data')],
66
+ allowTypeImports: true,
67
+ message: 'apps/api must not import DAOs or backend-data values directly; use backend-services instead',
68
+ },
69
+ {
70
+ dir: 'apps/background',
71
+ ban: [at('api')],
72
+ message: 'apps/background must not import from apps/api',
73
+ },
74
+ // The browser half, and the only layer that bans the namespace wholesale
75
+ // rather than a list of siblings: a backend package imported by the SPA
76
+ // typechecks and then fails at bundle time, with the error pointing at the
77
+ // bundler rather than at the boundary. Edge-Sonic is the source; the others had
78
+ // no block for it at all, which is how their layer table's "may import: the
79
+ // browser" was a convention instead of a gate.
80
+ {
81
+ dir: 'apps/web',
82
+ ban: [at('*')],
83
+ message: `${at('apps/web')} ships zero backend dependencies — this module is the SPA's own copy`,
84
+ },
85
+ ];
86
+ }
87
+ /**
88
+ * The `no-restricted-imports` entries for one layer.
89
+ *
90
+ * Written as `group` patterns rather than exact `paths`, so `@myapp/backend-data`
91
+ * and `@myapp/backend-data/dao` are both caught by one entry. `allowTypeImports`
92
+ * is passed through only where the source repos set it, because `apps/api`
93
+ * legitimately types its filters and models against DAO shapes.
94
+ */
95
+ export function restrictedImports(bans) {
96
+ return bans.map(({ dir, ban, message, allowTypeImports }) => ({
97
+ files: [`${dir}/**/*.{ts,js,mts,cts,mjs,cjs}`],
98
+ rules: {
99
+ 'no-restricted-imports': [
100
+ 'error',
101
+ {
102
+ patterns: ban.map((group) => ({
103
+ group: [group, `${group}/*`],
104
+ message,
105
+ ...(allowTypeImports === true && { allowTypeImports: true }),
106
+ })),
107
+ },
108
+ ],
109
+ },
110
+ }));
111
+ }
112
+ /**
113
+ * The dynamic-`import()` guard, generated from the same table.
114
+ *
115
+ * `no-restricted-imports` reads `ImportDeclaration` nodes only; a dynamic
116
+ * `import()` is an `ImportExpression`, and this ESLint version does not report it
117
+ * under that rule at all. Edge-Sonic verified this rather than assumed it — a
118
+ * static import of a restricted specifier from the same file is an `error`, and
119
+ * the identical specifier reached through `await import(...)` is silent. That
120
+ * hole was load-bearing there: the credential path reached a banned module
121
+ * through it. `no-restricted-syntax` sees `ImportExpression`, so the boundary is
122
+ * stated a second way.
123
+ */
124
+ export function restrictedDynamicImports(bans) {
125
+ return bans.map(({ dir, ban, message }) => ({
126
+ files: [`${dir}/**/*.{ts,js,mts,cts,mjs,cjs}`],
127
+ rules: {
128
+ 'no-restricted-syntax': [
129
+ 'error',
130
+ ...ban.map((specifier) => ({
131
+ selector: `ImportExpression[source.type='Literal'][source.value=/^${specifier.replaceAll('/', '\\/')}/]`,
132
+ message: `A dynamic import() is not covered by no-restricted-imports, so this layer reaches \`${specifier}\` through the one syntax that gate does not see. Both say no: ${message}`,
133
+ })),
134
+ ],
135
+ },
136
+ }));
137
+ }
138
+ //# sourceMappingURL=eslint-boundaries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslint-boundaries.js","sourceRoot":"","sources":["../src/eslint-boundaries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
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 declare const TYPESCRIPT_RULES: Readonly<Record<string, unknown>>;
14
+ /**
15
+ * Unicorn and SonarJS rules carried from the source repos, each off for a
16
+ * stated reason.
17
+ *
18
+ * This is the family's "deliberately does not follow" block: every entry is
19
+ * off because complying would make the code worse for what the project is,
20
+ * and each is listed rather than dropped so the decision stays reviewable.
21
+ */
22
+ export declare const UNICORN_RULES: Readonly<Record<string, unknown>>;
23
+ /**
24
+ * SonarJS rules the sources turned from errors into advisories, with the
25
+ * threshold raised to a value that has actually held.
26
+ */
27
+ export declare const SONARJS_RULES: Readonly<Record<string, unknown>>;
28
+ /**
29
+ * Test-suite overrides.
30
+ *
31
+ * `test/**` is deliberately *not* in the config's ignores list. Durable-DAV,
32
+ * AWS and Mail-Meow all ignored it, and ~200 KB of test code had accumulated
33
+ * violations that nothing reported. This block puts the suite back under the
34
+ * same rules as the rest of the workspace and switches off only the handful
35
+ * whose findings are structural artefacts of test code rather than defects.
36
+ * It does not disable correctness rules: the unused-variable, dead-store,
37
+ * regex and sorting findings in the suite are real and are fixed, not
38
+ * suppressed.
39
+ */
40
+ export declare const TEST_RULES: Readonly<Record<string, unknown>>;
41
+ //# sourceMappingURL=eslint-rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslint-rules.d.ts","sourceRoot":"","sources":["../src/eslint-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsB9D,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsI3D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoB3D,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwDxD,CAAC"}
@@ -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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"}
package/dist/eslint.d.ts CHANGED
@@ -6,23 +6,14 @@
6
6
  * rules). Merged in from the other three stacks that share the same plugin set:
7
7
  *
8
8
  * - **Edge-Sonic** — `test/**` is *not* ignored (it is linted like everything else,
9
- * with a narrow override block for Vitest idioms), and
10
- * `unicorn/prefer-ternary` is off. Edge-Sonic's per-rule "deliberately does not
11
- * follow" block is carried over verbatim in spirit: each entry is off because
12
- * complying would make the code worse for what the project is, and each is
13
- * listed rather than dropped so the decision stays reviewable.
14
- * - **Mail-Meow** — `prettier/prettier` is an **error**, not a warning.
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.
15
12
  * - **Mail-Meow** — `prettier/prettier` is an **error**, not a warning.
16
13
  * - **AWS-AccessBridge** — the `apps/api` DAO/service boundary uses
17
- * `allowTypeImports` where the source repos do. It is also the source for the
18
- * anchored skip patterns and the symlink-safe walk that came out of its own backlog.
19
- * - **Edge-Sonic** — `test/**` is *not* ignored (it is linted like everything else,
20
- * with a narrow override block for Vitest idioms), `unicorn/prefer-ternary` is off
21
- * with a documented reason, and the `import()` hole in `no-restricted-imports` is
22
- * covered by a matching `no-restricted-syntax` rule. Edge-Sonic's per-rule
23
- * "deliberately does not follow" block is carried over verbatim in spirit: each
24
- * entry is off because complying would make the code worse for what the project
25
- * is, and each is listed rather than dropped so the decision stays reviewable.
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.
26
17
  *
27
18
  * Canonical decisions, and why each one:
28
19
  *
@@ -32,6 +23,7 @@
32
23
  * 2. **The layered boundary rules are parameterized by `scope`.** Every source
33
24
  * repo wrote the same seven blocks with a different npm scope hardcoded; the
34
25
  * factory takes `scope` (`'@myapp'`) and generates the `@myapp/*` patterns.
26
+ * The table itself lives in {@link ./eslint-boundaries}.
35
27
  * 3. **`test/**` is linted, not ignored.** Durable-DAV/AWS/Mail-Meow ignored it;
36
28
  * Edge-Sonic does not, and records why: ~200 KB of test code had accumulated
37
29
  * violations that nothing reported.
@@ -47,11 +39,13 @@
47
39
  * zero-dependency, and the plugin belongs to the app that has JSX. A consumer
48
40
  * appends it — the README shows the four lines.
49
41
  *
50
- * The consumer's repo-level `eslint.config.mjs` becomes four lines, and a repo that
51
- * needs a boundary the canonical table does not name passes `extraLayers` — see
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
52
45
  * {@link RepoLintConfigOptions}.
53
46
  */
54
47
  import type { FlatConfig } from 'typescript-eslint';
48
+ import type { LayerBan } from './eslint-boundaries';
55
49
  /**
56
50
  * What `defineRepoLintConfig` accepts.
57
51
  */
@@ -87,24 +81,6 @@ export interface RepoLintConfigOptions {
87
81
  */
88
82
  readonly extraLayers?: readonly LayerBan[];
89
83
  }
90
- /**
91
- * One layer's ban list, as the repo-relative package suffixes it may not import.
92
- *
93
- * Converged from the four source stacks. `backend-data` and `backend-services`
94
- * appear in all four; `webdav`/`dav-store` are Durable-DAV's, `provider-clients`
95
- * is Mail-Meow's and AWS's. A layer only bans what exists in its repo, so the
96
- * union is safe: a repo without `provider-clients` simply never imports it.
97
- */
98
- export interface LayerBan {
99
- /** Directory the rule is scoped to. */
100
- readonly dir: string;
101
- /** Package suffixes (relative to `scope`) that may not be imported from here. */
102
- readonly ban: readonly string[];
103
- /** Message shown when the rule fires. */
104
- readonly message: string;
105
- /** Type-only imports are allowed, for the DAO boundary in `apps/api`. */
106
- readonly allowTypeImports?: boolean;
107
- }
108
84
  /**
109
85
  * Build the repo's flat config.
110
86
  *
@@ -1 +1 @@
1
- {"version":3,"file":"eslint.d.ts","sourceRoot":"","sources":["../src/eslint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AASH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;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;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,uCAAuC;IACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,yCAAyC;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACrC;AAyHD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,UAAU,CAAC,WAAW,CAmW3F"}
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"}