@noctcore/lint-meta-rules 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -0
- package/dist/index.cjs +748 -0
- package/dist/index.d.cts +395 -0
- package/dist/index.d.ts +395 -0
- package/dist/index.js +706 -0
- package/docs/rules/agents-doc-presence.md +40 -0
- package/docs/rules/canonical-helpers-single-home.md +35 -0
- package/docs/rules/file-size-ratchet.md +72 -0
- package/docs/rules/layer-rank.md +44 -0
- package/docs/rules/no-cloned-component-folders.md +40 -0
- package/docs/rules/no-warn-severity.md +34 -0
- package/docs/rules/package-shape.md +49 -0
- package/docs/rules/test-runner-segregation.md +40 -0
- package/docs/rules/test-sibling-enforcement.md +35 -0
- package/docs/rules/test-workspace-enrollment.md +41 -0
- package/docs/rules/ui-primitive-shape.md +41 -0
- package/docs/rules/workspace-graph-parity.md +41 -0
- package/package.json +56 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
import { IMetaRule } from '@noctcore/harness';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Options for {@link createAgentsDocPresenceRule}.
|
|
5
|
+
*
|
|
6
|
+
* De-projected from nightcore, which hardcoded `AGENTS.md`, the root/apps/packages
|
|
7
|
+
* layout and a fixed leaf opt-out set. The doc filename, which dirs require it,
|
|
8
|
+
* and the opt-out list are all options.
|
|
9
|
+
*/
|
|
10
|
+
interface AgentsDocPresenceOptions {
|
|
11
|
+
/** The agent-contract filename required in each location. Default `'AGENTS.md'`. */
|
|
12
|
+
readonly docFile?: string;
|
|
13
|
+
/** Whether the repo root must carry the doc. Default `true`. */
|
|
14
|
+
readonly requireAtRoot?: boolean;
|
|
15
|
+
/** `package.json` globs for deployable surfaces (all require the doc). Default `['apps/*\/package.json']`. */
|
|
16
|
+
readonly surfaceGlobs?: readonly string[];
|
|
17
|
+
/** `package.json` globs for library packages (require the doc unless opted out). Default `['packages/*\/package.json']`. */
|
|
18
|
+
readonly packageGlobs?: readonly string[];
|
|
19
|
+
/** Package directories exempt from the requirement. Default `[]`. */
|
|
20
|
+
readonly optOut?: readonly string[];
|
|
21
|
+
/** Whether a violation fails CI. Default `true`. */
|
|
22
|
+
readonly ciCritical?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Agent-contract coverage. Every deployable surface and public boundary must
|
|
26
|
+
* ship the agent-contract doc so an agent editing it reads the guardrails first.
|
|
27
|
+
* Trivial leaf packages may be opted out; a NEW package must ship the doc by
|
|
28
|
+
* default.
|
|
29
|
+
*/
|
|
30
|
+
declare function createAgentsDocPresenceRule(options?: AgentsDocPresenceOptions): IMetaRule;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Options for {@link createCanonicalHelpersSingleHomeRule}.
|
|
34
|
+
*
|
|
35
|
+
* De-projected from nightcore, which hardcoded `apps/web/src/**\/*.utils.ts` and
|
|
36
|
+
* a `/lib/` exclusion. `include` selects the helper homes to compare;
|
|
37
|
+
* `excludeContains` drops paths containing any listed fragment.
|
|
38
|
+
*/
|
|
39
|
+
interface CanonicalHelpersSingleHomeOptions {
|
|
40
|
+
/** Globs of helper-home files to scan for duplicate exports. Default `['apps/web/src/**\/*.utils.ts']`. */
|
|
41
|
+
readonly include?: readonly string[];
|
|
42
|
+
/** Drop any matched path containing one of these fragments. Default `['/lib/']`. */
|
|
43
|
+
readonly excludeContains?: readonly string[];
|
|
44
|
+
/** Whether a violation fails CI. Default `true`. */
|
|
45
|
+
readonly ciCritical?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Pure helpers must live in one canonical home. When the helper-home pattern is
|
|
49
|
+
* adopted, a duplicate exported helper name (the same symbol exported from 2+
|
|
50
|
+
* different home files) is flagged so the helper stays consolidated. Strict, no
|
|
51
|
+
* baseline.
|
|
52
|
+
*/
|
|
53
|
+
declare function createCanonicalHelpersSingleHomeRule(options?: CanonicalHelpersSingleHomeOptions): IMetaRule;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Options for {@link createFileSizeRatchetRule}.
|
|
57
|
+
*
|
|
58
|
+
* This single factory subsumes BOTH of nightcore's file-size ratchet rules —
|
|
59
|
+
* `web-file-size-ratchet` (apps/web/src, .ts+.tsx) and `engine-file-size-ratchet`
|
|
60
|
+
* (packages/engine/src, .ts) — because they were byte-identical logic differing
|
|
61
|
+
* only in their scanned roots, extensions and exclusions. A consumer creates one
|
|
62
|
+
* instance per capped area. `id` names both the rule and its committed baseline
|
|
63
|
+
* file (`<baselineDir>/<id>.json`), so give each instance a distinct `id`.
|
|
64
|
+
*/
|
|
65
|
+
interface FileSizeRatchetOptions {
|
|
66
|
+
/** Rule id AND baseline file basename. Default `'file-size-ratchet'`. */
|
|
67
|
+
readonly id?: string;
|
|
68
|
+
/** Source roots to scan. Default `[]` (inert until configured), e.g. `['apps/web/src']`. */
|
|
69
|
+
readonly roots?: readonly string[];
|
|
70
|
+
/** File extensions to include. Default `['.ts', '.tsx']`. */
|
|
71
|
+
readonly extensions?: readonly string[];
|
|
72
|
+
/** The per-file line cap. Default `400`. */
|
|
73
|
+
readonly cap?: number;
|
|
74
|
+
/** A file is excluded if its path contains any of these. Default test/spec/story markers. */
|
|
75
|
+
readonly excludeContains?: readonly string[];
|
|
76
|
+
/** A file is excluded if its path starts with any of these (e.g. codegen dirs). Default `[]`. */
|
|
77
|
+
readonly excludePrefixes?: readonly string[];
|
|
78
|
+
/** A baseline entry that shrank below `frozen * tightenRatio` must be re-frozen. Default `0.85`. */
|
|
79
|
+
readonly tightenRatio?: number;
|
|
80
|
+
/** Where committed baselines live, relative to repo root. Default {@link DEFAULT_BASELINE_DIR}. */
|
|
81
|
+
readonly baselineDir?: string;
|
|
82
|
+
/** Whether a violation fails CI. Default `true`. */
|
|
83
|
+
readonly ciCritical?: boolean;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* File-size governance with a one-way ratchet. Today's over-cap offenders are
|
|
87
|
+
* frozen in a committed baseline; a NEW over-cap file, or a frozen one that
|
|
88
|
+
* GREW, fails. Legacy files may only shrink; new files may never join. The
|
|
89
|
+
* baseline additionally SELF-TIGHTENS: an entry whose file is gone, is now at or
|
|
90
|
+
* below the cap, or shrank far below its frozen value is itself a violation
|
|
91
|
+
* demanding a baseline update — so paydowns are captured and the frozen debt can
|
|
92
|
+
* only shrink.
|
|
93
|
+
*
|
|
94
|
+
* Measured in raw physical lines (`wc -l` semantics) so the number an author
|
|
95
|
+
* sees in the editor is the number the gate sees.
|
|
96
|
+
*/
|
|
97
|
+
declare function createFileSizeRatchetRule(options?: FileSizeRatchetOptions): IMetaRule;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Options for {@link createLayerRankRule}.
|
|
101
|
+
*
|
|
102
|
+
* De-projected from nightcore, which hardcoded a fixed rank table
|
|
103
|
+
* (contracts → shared → storage/skills → engine → surfaces) and the `@nightcore`
|
|
104
|
+
* scope. The `ranks` table, `scope`, and the surface tier are all options.
|
|
105
|
+
*
|
|
106
|
+
* `ranks` defaults to `{}`, which makes the rule INERT (no package is ranked, so
|
|
107
|
+
* nothing is forbidden) until a consumer supplies its own layering — the same
|
|
108
|
+
* "off until you opt in" discipline the ESLint monorepo rules use.
|
|
109
|
+
*/
|
|
110
|
+
interface LayerRankOptions {
|
|
111
|
+
/** npm scope of workspace packages. Default `'@nightcore'`. */
|
|
112
|
+
readonly scope?: string;
|
|
113
|
+
/** Layer package name → rank. Higher-ranked may import only strictly-lower. Default `{}`. */
|
|
114
|
+
readonly ranks?: Readonly<Record<string, number>>;
|
|
115
|
+
/** Path prefix marking a deployable surface. Default `'apps/'`. */
|
|
116
|
+
readonly surfacePrefix?: string;
|
|
117
|
+
/** Rank assigned to surface files. Omit to leave surfaces unranked (skipped). */
|
|
118
|
+
readonly surfaceRank?: number;
|
|
119
|
+
/** Regex (source) extracting the layer name from a file path. Default `'^packages/([^/]+)/'`. */
|
|
120
|
+
readonly packageDirPattern?: string;
|
|
121
|
+
/** Globs of source files to scan. Default packages + apps `src/**` `.ts`/`.tsx`. */
|
|
122
|
+
readonly sourceGlobs?: readonly string[];
|
|
123
|
+
/** Whether a violation fails CI. Default `true`. */
|
|
124
|
+
readonly ciCritical?: boolean;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Layer ranks encode a fixed dependency direction: a module may import only
|
|
128
|
+
* STRICTLY-lower-ranked `<scope>` packages; equal (sideways) or higher (upward)
|
|
129
|
+
* is forbidden. Unranked `<scope>` packages are leaf utilities outside the
|
|
130
|
+
* documented spine — an import of one is skipped, and a module living in one is
|
|
131
|
+
* skipped, so the rule never produces a false positive on a package whose tier
|
|
132
|
+
* is not fixed.
|
|
133
|
+
*/
|
|
134
|
+
declare function createLayerRankRule(options?: LayerRankOptions): IMetaRule;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Options for {@link createNoClonedComponentFoldersRule}.
|
|
138
|
+
*
|
|
139
|
+
* De-projected from nightcore, which hardcoded `apps/web/src/components`, the
|
|
140
|
+
* `ui`/`app` excluded features, and a fixed `ALLOWED_CLONES` allowlist. The
|
|
141
|
+
* components root, barrel marker, excluded features, allowlist and the
|
|
142
|
+
* shared-destination hint are all options.
|
|
143
|
+
*/
|
|
144
|
+
interface NoClonedComponentFoldersOptions {
|
|
145
|
+
/** Root under which `<feature>/<Component>/` folders live. Default `'apps/web/src/components'`. */
|
|
146
|
+
readonly componentsRoot?: string;
|
|
147
|
+
/** Barrel file that marks a component folder. Default `'index.ts'`. */
|
|
148
|
+
readonly barrelFile?: string;
|
|
149
|
+
/** Feature folders whose contents are not feature components. Default `['ui', 'app']`. */
|
|
150
|
+
readonly excludedFeatures?: readonly string[];
|
|
151
|
+
/** Component names allowed to be cloned across features (a shrinking allowlist). Default `[]`. */
|
|
152
|
+
readonly allowedClones?: readonly string[];
|
|
153
|
+
/** Where a shared surface should be hoisted, used in the message. Default `'components/ui'`. */
|
|
154
|
+
readonly sharedDest?: string;
|
|
155
|
+
/** Whether a violation fails CI. Default `true`. */
|
|
156
|
+
readonly ciCritical?: boolean;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Same-named component folders across features are how sibling drift happens: a
|
|
160
|
+
* component cloned into a second feature diverges silently. A shared surface
|
|
161
|
+
* belongs in the shared destination; a genuinely different one deserves a name
|
|
162
|
+
* that says so. The allowlist freezes today's clone groups and only shrinks —
|
|
163
|
+
* an allowlist entry with no remaining clone group is itself a violation.
|
|
164
|
+
*/
|
|
165
|
+
declare function createNoClonedComponentFoldersRule(options?: NoClonedComponentFoldersOptions): IMetaRule;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Options for {@link createNoWarnSeverityRule}.
|
|
169
|
+
*
|
|
170
|
+
* De-projected from nightcore, which hardcoded `eslint.config.mjs`: the set of
|
|
171
|
+
* flat-config files to scan is now the `configFiles` option (each is scanned if
|
|
172
|
+
* it exists), so the rule fits whatever flat-config filename a repo uses.
|
|
173
|
+
*/
|
|
174
|
+
interface NoWarnSeverityOptions {
|
|
175
|
+
/** Flat-config files to scan; each is read only if present. */
|
|
176
|
+
readonly configFiles?: readonly string[];
|
|
177
|
+
/** Whether a violation fails CI. Default `true`. */
|
|
178
|
+
readonly ciCritical?: boolean;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Severity is `error` or `off`, never `warn`. Agents iterate by reading CI
|
|
182
|
+
* failures; a warning is a silent miss an agent will not act on. This scans the
|
|
183
|
+
* flat-config text (line comments stripped) for any `'warn'` / `"warn"` literal.
|
|
184
|
+
*/
|
|
185
|
+
declare function createNoWarnSeverityRule(options?: NoWarnSeverityOptions): IMetaRule;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Options for {@link createPackageShapeRule}.
|
|
189
|
+
*
|
|
190
|
+
* De-projected from nightcore, which hardcoded the `@nightcore` scope, the
|
|
191
|
+
* `packages/*` vs `apps/*` split, the `src/index.ts` barrel and the `dist/`
|
|
192
|
+
* output marker. Every anchor is now an option. `libraryGlobs` packages get the
|
|
193
|
+
* full name + barrel + build-output checks; `appGlobs` packages (deployable
|
|
194
|
+
* surfaces) get the name check only.
|
|
195
|
+
*/
|
|
196
|
+
interface PackageShapeOptions {
|
|
197
|
+
/** npm scope every workspace is named under (`<scope>/<dir>`). Default `'@nightcore'`. */
|
|
198
|
+
readonly scope?: string;
|
|
199
|
+
/** `package.json` globs for library packages (full checks). Default `['packages/*\/package.json']`. */
|
|
200
|
+
readonly libraryGlobs?: readonly string[];
|
|
201
|
+
/** `package.json` globs for app/surface packages (name check only). Default `['apps/*\/package.json']`. */
|
|
202
|
+
readonly appGlobs?: readonly string[];
|
|
203
|
+
/** Directory → exact package name overrides for intentionally off-scope packages. Default `{}`. */
|
|
204
|
+
readonly externalNames?: Readonly<Record<string, string>>;
|
|
205
|
+
/** Barrel each library package must expose, relative to its dir. Default `'src/index.ts'`. */
|
|
206
|
+
readonly barrelPath?: string;
|
|
207
|
+
/** Substring the build-output fields must contain. Default `'dist/'`. */
|
|
208
|
+
readonly distMarker?: string;
|
|
209
|
+
/** `package.json` string fields that must point at built output. Default `['main','module','types']`. */
|
|
210
|
+
readonly distFields?: readonly string[];
|
|
211
|
+
/** Whether a violation fails CI. Default `true`. */
|
|
212
|
+
readonly ciCritical?: boolean;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Package-shape invariant. Every workspace is named `<scope>/<dir>` matching its
|
|
216
|
+
* folder. Library packages additionally expose a single barrel and point their
|
|
217
|
+
* `main`/`module`/`types`/`exports` at the built output. App packages are
|
|
218
|
+
* deployable surfaces — only the name match applies to them.
|
|
219
|
+
*/
|
|
220
|
+
declare function createPackageShapeRule(options?: PackageShapeOptions): IMetaRule;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Options for {@link createTestRunnerSegregationRule}.
|
|
224
|
+
*
|
|
225
|
+
* De-projected from nightcore, which hardcoded `bun:test` vs `vitest`, the
|
|
226
|
+
* `packages/*` + `apps/sidecar` bun set and the `apps/web` + `eslint-plugin`
|
|
227
|
+
* vitest set. The two runner import specifiers and the dir groups are options.
|
|
228
|
+
*/
|
|
229
|
+
interface TestRunnerSegregationOptions {
|
|
230
|
+
/** `package.json` globs whose dirs default to the bun runner. Default `['packages/*\/package.json']`. */
|
|
231
|
+
readonly bunPackageGlobs?: readonly string[];
|
|
232
|
+
/** Extra bun-runner directories beyond the globbed packages. Default `[]`. */
|
|
233
|
+
readonly bunExtraDirs?: readonly string[];
|
|
234
|
+
/** Directories that use the foreign (non-bun) runner. Default `[]`. */
|
|
235
|
+
readonly vitestDirs?: readonly string[];
|
|
236
|
+
/** The bun-side runner import specifier. Default `'bun:test'`. */
|
|
237
|
+
readonly bunRunnerImport?: string;
|
|
238
|
+
/** The foreign runner import specifier. Default `'vitest'`. */
|
|
239
|
+
readonly foreignRunnerImport?: string;
|
|
240
|
+
/** Whether a violation fails CI. Default `true`. */
|
|
241
|
+
readonly ciCritical?: boolean;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* The test runner is segregated by workspace and never mixed within a package.
|
|
245
|
+
* Bun-side test files must import the bun runner and never the foreign one;
|
|
246
|
+
* foreign-side test files must never import the bun runner (they may pull the
|
|
247
|
+
* foreign runner in transitively via shared test-utils, so a direct import is
|
|
248
|
+
* not required).
|
|
249
|
+
*/
|
|
250
|
+
declare function createTestRunnerSegregationRule(options?: TestRunnerSegregationOptions): IMetaRule;
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Options for {@link createTestSiblingEnforcementRule}.
|
|
254
|
+
*
|
|
255
|
+
* De-projected from nightcore, which hardcoded `apps/web/src/**\/*.utils.ts` and
|
|
256
|
+
* the `.utils.test.ts(x)` sibling shape. `include` selects which source files
|
|
257
|
+
* must be tested; `testExtensions` are the accepted colocated-test suffixes.
|
|
258
|
+
*/
|
|
259
|
+
interface TestSiblingEnforcementOptions {
|
|
260
|
+
/** Globs of source files that must ship a colocated test. Default `['apps/web/src/**\/*.utils.ts']`. */
|
|
261
|
+
readonly include?: readonly string[];
|
|
262
|
+
/** Accepted colocated-test extensions (replace the source `.ts`/`.tsx`). Default `['.test.ts', '.test.tsx']`. */
|
|
263
|
+
readonly testExtensions?: readonly string[];
|
|
264
|
+
/** Whether a violation fails CI. Default `true`. */
|
|
265
|
+
readonly ciCritical?: boolean;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Every source file matched by `include` must have a colocated sibling test.
|
|
269
|
+
* Modelled on nightcore's `.utils.ts → .utils.test.ts(x)` rule and generalized:
|
|
270
|
+
* for a matched file, the sibling is the same path with its `.ts`/`.tsx`
|
|
271
|
+
* extension replaced by each configured test extension. Strict (no baseline) —
|
|
272
|
+
* the pattern is opt-in via which files match `include`.
|
|
273
|
+
*/
|
|
274
|
+
declare function createTestSiblingEnforcementRule(options?: TestSiblingEnforcementOptions): IMetaRule;
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Options for {@link createTestWorkspaceEnrollmentRule}.
|
|
278
|
+
*
|
|
279
|
+
* De-projected from nightcore, which hardcoded the `test:node` script name, a
|
|
280
|
+
* `packages/*` + `apps/sidecar` dir list, and a vitest exclusion set. All are
|
|
281
|
+
* options.
|
|
282
|
+
*/
|
|
283
|
+
interface TestWorkspaceEnrollmentOptions {
|
|
284
|
+
/** The root-manifest script that must enumerate every tested package. Default `'test:node'`. */
|
|
285
|
+
readonly scriptName?: string;
|
|
286
|
+
/** The root manifest path. Default `'package.json'`. */
|
|
287
|
+
readonly manifestPath?: string;
|
|
288
|
+
/** `package.json` globs whose dirs are candidate test workspaces. Default `['packages/*\/package.json']`. */
|
|
289
|
+
readonly packageGlobs?: readonly string[];
|
|
290
|
+
/** Extra directories to check beyond the globbed packages. Default `[]`. */
|
|
291
|
+
readonly extraDirs?: readonly string[];
|
|
292
|
+
/** Directories tested by a different runner/script (excluded here). Default `[]`. */
|
|
293
|
+
readonly excludeDirs?: readonly string[];
|
|
294
|
+
/** Glob suffix (relative to a dir) that detects the presence of tests. Default `'**\/*.test.ts'`. */
|
|
295
|
+
readonly testGlobSuffix?: string;
|
|
296
|
+
/** Whether a violation fails CI. Default `true`. */
|
|
297
|
+
readonly ciCritical?: boolean;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* A test workspace that is not enumerated in the aggregate test script runs in
|
|
301
|
+
* no CI gate. This fails when any candidate package that HAS test files is
|
|
302
|
+
* missing from the configured `scriptName` command in the root manifest.
|
|
303
|
+
*/
|
|
304
|
+
declare function createTestWorkspaceEnrollmentRule(options?: TestWorkspaceEnrollmentOptions): IMetaRule;
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Options for {@link createUiPrimitiveShapeRule}.
|
|
308
|
+
*
|
|
309
|
+
* De-projected from nightcore, which hardcoded `apps/web/src/components/ui`, the
|
|
310
|
+
* `test`/`stories` roles and the `.tsx` extension. All are options.
|
|
311
|
+
*/
|
|
312
|
+
interface UiPrimitiveShapeOptions {
|
|
313
|
+
/** The primitives root. Default `'apps/web/src/components/ui'`. */
|
|
314
|
+
readonly uiRoot?: string;
|
|
315
|
+
/** Barrel file that marks a folder-primitive. Default `'index.ts'`. */
|
|
316
|
+
readonly barrelFile?: string;
|
|
317
|
+
/** Proof-of-behavior sibling roles a folder-primitive must ship. Default `['test', 'stories']`. */
|
|
318
|
+
readonly roles?: readonly string[];
|
|
319
|
+
/** Extension of primitive and proof files. Default `'.tsx'`. */
|
|
320
|
+
readonly extension?: string;
|
|
321
|
+
/** Whether a violation fails CI. Default `true`. */
|
|
322
|
+
readonly ciCritical?: boolean;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* The primitives root is the one folder exempt from folder-per-component: flat
|
|
326
|
+
* single files are allowed for presentational primitives. But once a primitive
|
|
327
|
+
* graduates to a folder (its own dir + barrel) it must ship the same
|
|
328
|
+
* proof-of-behavior siblings as any component: `<Name>.<role><ext>` for each
|
|
329
|
+
* role. Also flags the hybrid shape: a flat `<Name><ext>` at the root that
|
|
330
|
+
* already carries a sibling proof file — those belong inside `<Name>/`.
|
|
331
|
+
*/
|
|
332
|
+
declare function createUiPrimitiveShapeRule(options?: UiPrimitiveShapeOptions): IMetaRule;
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Options for {@link createWorkspaceGraphParityRule}.
|
|
336
|
+
*
|
|
337
|
+
* De-projected from nightcore, which hardcoded the `@nightcore` scope and a
|
|
338
|
+
* `src` source directory: both are options. All scope-sensitive regexes are
|
|
339
|
+
* rebuilt from the configured `scope`.
|
|
340
|
+
*/
|
|
341
|
+
interface WorkspaceGraphParityOptions {
|
|
342
|
+
/** npm scope of workspace packages. Default `'@nightcore'`. */
|
|
343
|
+
readonly scope?: string;
|
|
344
|
+
/** `package.json` globs to enforce parity for. Default packages + apps. */
|
|
345
|
+
readonly packageGlobs?: readonly string[];
|
|
346
|
+
/** Source directory (relative to each package) to scan for imports. Default `'src'`. */
|
|
347
|
+
readonly srcDir?: string;
|
|
348
|
+
/** Whether a violation fails CI. Default `true`. */
|
|
349
|
+
readonly ciCritical?: boolean;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Workspace dependency-graph parity. For each workspace package:
|
|
353
|
+
* (a) every `<scope>/<pkg>` imported in the source dir must be declared as a
|
|
354
|
+
* `workspace:*` dependency in package.json, and
|
|
355
|
+
* (b) its tsconfig.json `references` must mirror exactly those workspace deps.
|
|
356
|
+
* So a new cross-package edge can never be half-wired (imported but undeclared,
|
|
357
|
+
* or declared but missing from the TS project graph).
|
|
358
|
+
*/
|
|
359
|
+
declare function createWorkspaceGraphParityRule(options?: WorkspaceGraphParityOptions): IMetaRule;
|
|
360
|
+
|
|
361
|
+
/** Raw physical line count, `wc -l` semantics (a trailing newline adds no line). */
|
|
362
|
+
declare function countLines(text: string): number;
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Every rule factory keyed by its default rule id, for convenient iteration
|
|
366
|
+
* (e.g. registering all rules, or discovering the catalog). Each value is a
|
|
367
|
+
* factory callable with no arguments (all options default). The
|
|
368
|
+
* `file-size-ratchet` factory is keyed once here but is meant to be instantiated
|
|
369
|
+
* MULTIPLE times, once per capped area, each with its own `id`.
|
|
370
|
+
*
|
|
371
|
+
* A `RuleFactory` accepts an optional options object and returns an
|
|
372
|
+
* {@link IMetaRule}; the concrete options type is per-factory (see each
|
|
373
|
+
* `create*` export). `as const` preserves each factory's precise type at the
|
|
374
|
+
* call site while still allowing zero-argument iteration.
|
|
375
|
+
*/
|
|
376
|
+
declare const RULE_FACTORIES: {
|
|
377
|
+
readonly 'agents-doc-presence': typeof createAgentsDocPresenceRule;
|
|
378
|
+
readonly 'canonical-helpers-single-home': typeof createCanonicalHelpersSingleHomeRule;
|
|
379
|
+
readonly 'file-size-ratchet': typeof createFileSizeRatchetRule;
|
|
380
|
+
readonly 'layer-rank': typeof createLayerRankRule;
|
|
381
|
+
readonly 'no-cloned-component-folders': typeof createNoClonedComponentFoldersRule;
|
|
382
|
+
readonly 'no-warn-severity': typeof createNoWarnSeverityRule;
|
|
383
|
+
readonly 'package-shape': typeof createPackageShapeRule;
|
|
384
|
+
readonly 'test-runner-segregation': typeof createTestRunnerSegregationRule;
|
|
385
|
+
readonly 'test-sibling-enforcement': typeof createTestSiblingEnforcementRule;
|
|
386
|
+
readonly 'test-workspace-enrollment': typeof createTestWorkspaceEnrollmentRule;
|
|
387
|
+
readonly 'ui-primitive-shape': typeof createUiPrimitiveShapeRule;
|
|
388
|
+
readonly 'workspace-graph-parity': typeof createWorkspaceGraphParityRule;
|
|
389
|
+
};
|
|
390
|
+
/** The catalog rule ids (keys of {@link RULE_FACTORIES}). */
|
|
391
|
+
declare const RULE_IDS: (keyof typeof RULE_FACTORIES)[];
|
|
392
|
+
/** Instantiate every catalog rule with its default options. */
|
|
393
|
+
declare function createAllRules(): IMetaRule[];
|
|
394
|
+
|
|
395
|
+
export { type AgentsDocPresenceOptions, type CanonicalHelpersSingleHomeOptions, type FileSizeRatchetOptions, type LayerRankOptions, type NoClonedComponentFoldersOptions, type NoWarnSeverityOptions, type PackageShapeOptions, RULE_FACTORIES, RULE_IDS, type TestRunnerSegregationOptions, type TestSiblingEnforcementOptions, type TestWorkspaceEnrollmentOptions, type UiPrimitiveShapeOptions, type WorkspaceGraphParityOptions, countLines, createAgentsDocPresenceRule, createAllRules, createCanonicalHelpersSingleHomeRule, createFileSizeRatchetRule, createLayerRankRule, createNoClonedComponentFoldersRule, createNoWarnSeverityRule, createPackageShapeRule, createTestRunnerSegregationRule, createTestSiblingEnforcementRule, createTestWorkspaceEnrollmentRule, createUiPrimitiveShapeRule, createWorkspaceGraphParityRule };
|