workspace-conformance 0.0.0 → 1.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/LICENSE +21 -0
- package/README.md +250 -0
- package/dist/cli.js +1914 -0
- package/dist/index.cjs +1965 -0
- package/dist/index.d.cts +723 -0
- package/dist/index.d.ts +723 -0
- package/dist/index.js +1929 -0
- package/package.json +97 -2
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,723 @@
|
|
|
1
|
+
import { ConfigFileOptions, LayoutConfig, RankSkipOptions, Section } from "@exadev/config";
|
|
2
|
+
import { IViolation } from "dependency-cruiser";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { CompilerOptions } from "ts-morph";
|
|
5
|
+
//#region src/check.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* A position in a file, both numbers counted from 1.
|
|
8
|
+
*/
|
|
9
|
+
interface SourceLocation {
|
|
10
|
+
readonly line: number;
|
|
11
|
+
readonly column: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* One way the workspace fails a check.
|
|
15
|
+
*/
|
|
16
|
+
interface Violation {
|
|
17
|
+
/**
|
|
18
|
+
* Stable identifier of the rule that was broken, `<check name>/<reason>`. Callers may match on it; the message may change.
|
|
19
|
+
*/
|
|
20
|
+
readonly code: string;
|
|
21
|
+
readonly message: string;
|
|
22
|
+
/**
|
|
23
|
+
* The file the violation is about, relative to the directory the checks ran in, with `/` separators. For a violation about a file that should exist and does not, the file that is missing or the file that requires it.
|
|
24
|
+
*/
|
|
25
|
+
readonly file: string;
|
|
26
|
+
readonly location?: SourceLocation;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* What every check receives.
|
|
30
|
+
*/
|
|
31
|
+
interface CheckContext<Options> {
|
|
32
|
+
/**
|
|
33
|
+
* The directory the checks run in; every path option is relative to it.
|
|
34
|
+
*/
|
|
35
|
+
readonly cwd: string;
|
|
36
|
+
readonly options: Options;
|
|
37
|
+
/**
|
|
38
|
+
* How config files that a check evaluates itself (the commitlint and release configs of `commit-types`) are loaded. Only `alias` and `fsCache` apply to evaluating a file; `trust` and `merge` are for `extends`. No transpile cache is written when omitted.
|
|
39
|
+
*/
|
|
40
|
+
readonly configFiles?: ConfigFileOptions;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* What a check that reads the workspace layout receives.
|
|
44
|
+
*/
|
|
45
|
+
interface LayoutCheckContext<Options> extends CheckContext<Options> {
|
|
46
|
+
readonly layout: LayoutConfig;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A check: reads the workspace and returns everything it finds wrong, in a stable order. It throws `ConformanceError` when it cannot run.
|
|
50
|
+
*/
|
|
51
|
+
type CheckFunction<Options> = (context: CheckContext<Options>) => Promise<readonly Violation[]>;
|
|
52
|
+
/**
|
|
53
|
+
* A check that also needs the resolved workspace layout.
|
|
54
|
+
*/
|
|
55
|
+
type LayoutCheckFunction<Options> = (context: LayoutCheckContext<Options>) => Promise<readonly Violation[]>;
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/migrations/adapters.d.ts
|
|
58
|
+
/**
|
|
59
|
+
* Which of several things in a deploy tool's config the generator's output belongs to.
|
|
60
|
+
*/
|
|
61
|
+
interface DeploySelector {
|
|
62
|
+
/**
|
|
63
|
+
* The binding of the database, when the config declares more than one.
|
|
64
|
+
*/
|
|
65
|
+
readonly database?: string;
|
|
66
|
+
/**
|
|
67
|
+
* The named environment whose settings apply instead of the top-level ones.
|
|
68
|
+
*/
|
|
69
|
+
readonly environment?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* What a deploy tool's config says about the directory it applies migrations from.
|
|
73
|
+
*/
|
|
74
|
+
type DeployDirectory = {
|
|
75
|
+
readonly directory: string;
|
|
76
|
+
readonly none?: never;
|
|
77
|
+
} | {
|
|
78
|
+
readonly none: string;
|
|
79
|
+
readonly directory?: never;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* A schema generator, for the cross-check between where it writes migrations and where the deploy tool applies them from. The data of a config file is already read; an adapter only knows where in it the directory is.
|
|
83
|
+
*/
|
|
84
|
+
interface GeneratorAdapter {
|
|
85
|
+
/**
|
|
86
|
+
* The names the config file may have, by precedence. The extension decides how the file is read.
|
|
87
|
+
*/
|
|
88
|
+
readonly configFiles: readonly [string, ...string[]];
|
|
89
|
+
/**
|
|
90
|
+
* Matches a shell command that applies migrations with the generator itself, bypassing the deploy tool.
|
|
91
|
+
*/
|
|
92
|
+
readonly applyCommand: RegExp;
|
|
93
|
+
/**
|
|
94
|
+
* The command as it is written, for messages.
|
|
95
|
+
*/
|
|
96
|
+
readonly applyCommandName: string;
|
|
97
|
+
/**
|
|
98
|
+
* The directory the generator writes migrations to, as the config writes it (relative to the config file's directory) or the generator's default when the config sets none. Throws `ConformanceError` when the config is not of a shape the adapter can read.
|
|
99
|
+
*/
|
|
100
|
+
readonly outputDirectory: (config: unknown, file: string) => string;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A deploy tool that applies migrations from a directory.
|
|
104
|
+
*/
|
|
105
|
+
interface DeployToolAdapter {
|
|
106
|
+
/**
|
|
107
|
+
* The names the config file may have, by precedence. The extension decides how the file is read.
|
|
108
|
+
*/
|
|
109
|
+
readonly configFiles: readonly [string, ...string[]];
|
|
110
|
+
/**
|
|
111
|
+
* The directory the tool applies migrations from, as the config writes it (relative to the config file's directory) or the tool's default when the config sets none. Throws `ConformanceError` when the config is not of a shape the adapter can read or `selector` is needed and absent.
|
|
112
|
+
*/
|
|
113
|
+
readonly migrationsDirectory: (config: unknown, file: string, selector: DeploySelector) => DeployDirectory;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The generators that have an adapter.
|
|
117
|
+
*/
|
|
118
|
+
declare const generatorNames: readonly ["drizzle-kit"];
|
|
119
|
+
/**
|
|
120
|
+
* The deploy tools that have an adapter.
|
|
121
|
+
*/
|
|
122
|
+
declare const deployToolNames: readonly ["wrangler"];
|
|
123
|
+
type GeneratorName = (typeof generatorNames)[number];
|
|
124
|
+
type DeployToolName = (typeof deployToolNames)[number];
|
|
125
|
+
export declare const generators: Readonly<Record<GeneratorName, GeneratorAdapter>>;
|
|
126
|
+
export declare const deployTools: Readonly<Record<DeployToolName, DeployToolAdapter>>;
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region src/options.d.ts
|
|
129
|
+
/**
|
|
130
|
+
* Options of the `aggregate-mappers` check: every aggregate type a contract exports has a mapper file in the place the template names.
|
|
131
|
+
*/
|
|
132
|
+
interface AggregateMappersOptions {
|
|
133
|
+
/**
|
|
134
|
+
* Globs of the contract files, relative to the directory the checks run in. Every exported interface and type alias in them is an aggregate.
|
|
135
|
+
*/
|
|
136
|
+
readonly contracts: readonly string[];
|
|
137
|
+
/**
|
|
138
|
+
* Where the mapper of an aggregate lives. Placeholders: `{name}` (the aggregate's name), `{dir}` (the contract file's directory), `{file}` (the contract file) and, when `adapters` is set, `{adapter}` (one matched adapter directory). Relative to the directory the checks run in; `..` segments are resolved.
|
|
139
|
+
*/
|
|
140
|
+
readonly mapper: string;
|
|
141
|
+
/**
|
|
142
|
+
* A glob template for the adapter directories, with the same `{dir}` and `{file}` placeholders. When set, every aggregate needs a mapper in every matched adapter, and a template that matches no directory is itself a violation.
|
|
143
|
+
*/
|
|
144
|
+
readonly adapters?: string;
|
|
145
|
+
/**
|
|
146
|
+
* Names of exported types that are not aggregates and need no mapper.
|
|
147
|
+
*/
|
|
148
|
+
readonly exclude?: readonly string[];
|
|
149
|
+
/**
|
|
150
|
+
* The tsconfig that supplies compiler options and module resolution, relative to the directory the checks run in; `tsconfig.json` when omitted. Its `include` is not used: only the contract files and what they import are loaded.
|
|
151
|
+
*/
|
|
152
|
+
readonly tsConfig?: string;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Options of the `command-types` check: every command type a file exports is derived from a schema.
|
|
156
|
+
*/
|
|
157
|
+
interface CommandTypesOptions {
|
|
158
|
+
/**
|
|
159
|
+
* Globs of the files that declare commands, relative to the directory the checks run in. Every exported interface and type alias in them is a command.
|
|
160
|
+
*/
|
|
161
|
+
readonly commands: readonly string[];
|
|
162
|
+
/**
|
|
163
|
+
* Names of exported types that are not commands, such as a union of all of them.
|
|
164
|
+
*/
|
|
165
|
+
readonly exclude?: readonly string[];
|
|
166
|
+
/**
|
|
167
|
+
* The last name of the generic that turns a schema into its type, such as `infer` in `z.infer<typeof schema>`. `infer`, `input`, `output`, `TypeOf`, `InferInput` and `InferOutput` when omitted.
|
|
168
|
+
*/
|
|
169
|
+
readonly inferences?: readonly string[];
|
|
170
|
+
/**
|
|
171
|
+
* The tsconfig that supplies compiler options and module resolution; `tsconfig.json` when omitted.
|
|
172
|
+
*/
|
|
173
|
+
readonly tsConfig?: string;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Options shared by the checks that cruise the workspace's import graph.
|
|
177
|
+
*/
|
|
178
|
+
interface ImportGraphOptions {
|
|
179
|
+
/**
|
|
180
|
+
* Regular expressions, as source text, for paths relative to the workspace root that are left out of the graph. Anything matching one is neither a dependant nor a dependency. Installed dependencies (`node_modules`) when omitted.
|
|
181
|
+
*/
|
|
182
|
+
readonly exclude?: readonly string[];
|
|
183
|
+
/**
|
|
184
|
+
* Regular expressions, as source text, for paths relative to the workspace root whose files can be imported but whose own imports are not followed, so build output is a target of imports and never a dependant. `dist` directories when omitted.
|
|
185
|
+
*/
|
|
186
|
+
readonly doNotFollow?: readonly string[];
|
|
187
|
+
/**
|
|
188
|
+
* A tsconfig, relative to the directory the checks run in, for path aliases and other module resolution the imports depend on.
|
|
189
|
+
*/
|
|
190
|
+
readonly tsConfig?: string;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Options of the `instruction-symlinks` check: agent instruction files are git symlinks to the README next to them.
|
|
194
|
+
*/
|
|
195
|
+
interface InstructionSymlinksOptions {
|
|
196
|
+
/**
|
|
197
|
+
* The instruction file names. `AGENTS.md` and `CLAUDE.md` when omitted.
|
|
198
|
+
*/
|
|
199
|
+
readonly files?: readonly string[];
|
|
200
|
+
/**
|
|
201
|
+
* Globs of the directories that hold them, relative to the directory the checks run in. The directory itself (`.`) when omitted.
|
|
202
|
+
*/
|
|
203
|
+
readonly directories?: readonly string[];
|
|
204
|
+
/**
|
|
205
|
+
* What each file links to, relative to the file. `README.md` when omitted.
|
|
206
|
+
*/
|
|
207
|
+
readonly target?: string;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Options of the `single-storybook` check.
|
|
211
|
+
*/
|
|
212
|
+
interface SingleStorybookOptions {
|
|
213
|
+
/**
|
|
214
|
+
* The only directory that may hold a `.storybook` directory, relative to the directory the checks run in. The directory itself (`.`) when omitted.
|
|
215
|
+
*/
|
|
216
|
+
readonly location?: string;
|
|
217
|
+
/**
|
|
218
|
+
* Globs of paths that are not searched, such as directories of test fixtures that hold a Storybook on purpose.
|
|
219
|
+
*/
|
|
220
|
+
readonly exclude?: readonly string[];
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Options of the `commit-types` check: the commit types commitlint accepts match the release rules and changelog sections of the release config.
|
|
224
|
+
*/
|
|
225
|
+
interface CommitTypesOptions {
|
|
226
|
+
/**
|
|
227
|
+
* The commitlint config file, relative to the directory the checks run in. `commitlint.config.ts` when omitted.
|
|
228
|
+
*/
|
|
229
|
+
readonly commitlint?: string;
|
|
230
|
+
/**
|
|
231
|
+
* The semantic-release config file. `release.config.ts` when omitted.
|
|
232
|
+
*/
|
|
233
|
+
readonly release?: string;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Options of the `dockerfile-package-manager` check: a package manager version pinned in a Dockerfile is the one `packageManager` names.
|
|
237
|
+
*/
|
|
238
|
+
interface DockerfilePackageManagerOptions {
|
|
239
|
+
/**
|
|
240
|
+
* Globs of the Dockerfiles, relative to the directory the checks run in. `Dockerfile`, `Dockerfile.*` and `*.Dockerfile` at any depth when omitted.
|
|
241
|
+
*/
|
|
242
|
+
readonly dockerfiles?: readonly string[];
|
|
243
|
+
/**
|
|
244
|
+
* Globs of paths that are not searched, such as directories of test fixtures.
|
|
245
|
+
*/
|
|
246
|
+
readonly exclude?: readonly string[];
|
|
247
|
+
/**
|
|
248
|
+
* The package.json that holds the `packageManager` field. `package.json` when omitted.
|
|
249
|
+
*/
|
|
250
|
+
readonly packageJson?: string;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Options of the `migrations-directory` check: the directory a schema generator writes migrations to is the one the deploy tool applies them from, and no script applies them with the generator.
|
|
254
|
+
*/
|
|
255
|
+
interface MigrationsDirectoryOptions {
|
|
256
|
+
/**
|
|
257
|
+
* The schema generator, which has an adapter that knows its config file and where in it the output directory is.
|
|
258
|
+
*/
|
|
259
|
+
readonly generator: GeneratorName;
|
|
260
|
+
/**
|
|
261
|
+
* The deploy tool, which has an adapter that knows its config file and where in it the migrations directory is.
|
|
262
|
+
*/
|
|
263
|
+
readonly deployTool: DeployToolName;
|
|
264
|
+
/**
|
|
265
|
+
* The generator's config file, relative to the directory the checks run in. The first of the adapter's default file names that exists when omitted.
|
|
266
|
+
*/
|
|
267
|
+
readonly generatorConfig?: string;
|
|
268
|
+
/**
|
|
269
|
+
* The deploy tool's config file. The first of the adapter's default file names that exists when omitted.
|
|
270
|
+
*/
|
|
271
|
+
readonly deployConfig?: string;
|
|
272
|
+
/**
|
|
273
|
+
* The binding of the database the generator writes migrations for. Needed when the deploy config declares more than one; the only one is used when omitted.
|
|
274
|
+
*/
|
|
275
|
+
readonly database?: string;
|
|
276
|
+
/**
|
|
277
|
+
* The named environment of the deploy config to read instead of its top-level settings.
|
|
278
|
+
*/
|
|
279
|
+
readonly environment?: string;
|
|
280
|
+
/**
|
|
281
|
+
* Globs of the `package.json` files whose scripts are searched for the generator's apply command. Every `package.json` at any depth when omitted.
|
|
282
|
+
*/
|
|
283
|
+
readonly packageJsons?: readonly string[];
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* The options of every check, by check name.
|
|
287
|
+
*/
|
|
288
|
+
interface CheckOptionsByName {
|
|
289
|
+
readonly "aggregate-mappers": AggregateMappersOptions;
|
|
290
|
+
readonly "command-types": CommandTypesOptions;
|
|
291
|
+
readonly "import-uphill": ImportGraphOptions;
|
|
292
|
+
readonly "import-rank-skip": ImportGraphOptions;
|
|
293
|
+
readonly "import-cross-slice": ImportGraphOptions;
|
|
294
|
+
readonly "import-isolated-groups": ImportGraphOptions;
|
|
295
|
+
readonly "import-cycles": ImportGraphOptions;
|
|
296
|
+
readonly "instruction-symlinks": InstructionSymlinksOptions;
|
|
297
|
+
readonly "single-storybook": SingleStorybookOptions;
|
|
298
|
+
readonly "commit-types": CommitTypesOptions;
|
|
299
|
+
readonly "dockerfile-package-manager": DockerfilePackageManagerOptions;
|
|
300
|
+
readonly "migrations-directory": MigrationsDirectoryOptions;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* The name of a check.
|
|
304
|
+
*/
|
|
305
|
+
type CheckName = keyof CheckOptionsByName;
|
|
306
|
+
//#endregion
|
|
307
|
+
//#region src/checks/aggregate-mappers.d.ts
|
|
308
|
+
/**
|
|
309
|
+
* Every exported interface and type alias of a contract file is an aggregate and has a mapper file where the template puts it, in each adapter directory when `adapters` is set.
|
|
310
|
+
*
|
|
311
|
+
* It looks for the file, not for what is in it, and it counts a type as exported when the contract re-exports it.
|
|
312
|
+
*/
|
|
313
|
+
export declare const aggregateMappers: CheckFunction<AggregateMappersOptions>;
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region src/checks/command-types.d.ts
|
|
316
|
+
/**
|
|
317
|
+
* The last names of the generics that turn a schema into its type, used when the options name none: `z.infer`, `z.input`, `z.output`, `z.TypeOf` and Valibot's `InferInput` and `InferOutput`.
|
|
318
|
+
*/
|
|
319
|
+
export declare const DEFAULT_INFERENCES: readonly string[];
|
|
320
|
+
/**
|
|
321
|
+
* Every exported interface and type alias of a command file is derived from a schema: an alias of `infer<typeof schema>` (or another generic in `inferences`) where the type of `schema` is a Standard Schema. Interfaces and other aliases are hand-written, and so are aliases of something that is not a schema.
|
|
322
|
+
*
|
|
323
|
+
* The schema is recognised by type, so it may be imported from another file or renamed; it does not need to come from Zod. A union of the commands is not a command: list its name in `exclude`.
|
|
324
|
+
*/
|
|
325
|
+
export declare const commandTypes: CheckFunction<CommandTypesOptions>;
|
|
326
|
+
//#endregion
|
|
327
|
+
//#region src/checks/commit-types.d.ts
|
|
328
|
+
/**
|
|
329
|
+
* The commit types the conventional presets know, which is the `type-enum` of `@commitlint/config-conventional` and the type list the conventional changelog presets label. Their release behaviour is the preset's own, so a preset type needs no release rule or changelog section to be accounted for; a type outside this list does.
|
|
330
|
+
*/
|
|
331
|
+
export declare const PRESET_COMMIT_TYPES: readonly string[];
|
|
332
|
+
/**
|
|
333
|
+
* The commit types commitlint accepts are accounted for in the release config. A type no preset knows must have a release rule and, when the config lists changelog sections (`presetConfig.types` of the release notes generator), a section, or it can be committed and never released or shown; a release rule or changelog section for a type commitlint rejects can never apply. Types are enumerated only by a `type-enum` rule of the form `[level, 'always', [types]]`; a `'never'` rule forbids the types it lists and enumerates none, and a rule that is off (level 0) accepts every type. A preset type may be left out of either list: leaving out a type that does not release is how a release rule list is normally written.
|
|
334
|
+
*
|
|
335
|
+
* It compares only what is written. The check has nothing to say when the commit types are the preset's and every listed type is one of them. A commitlint config that does not set `type-enum` while the release config lists a type no preset knows is a violation, since the commit types cannot then be read. Both configs are evaluated, so a list may be derived from one shared constant.
|
|
336
|
+
*/
|
|
337
|
+
export declare const commitTypes: CheckFunction<CommitTypesOptions>;
|
|
338
|
+
//#endregion
|
|
339
|
+
//#region src/checks/dockerfile-package-manager.d.ts
|
|
340
|
+
/**
|
|
341
|
+
* Every pin of the package manager that `packageManager` names, in each Dockerfile, is the version `packageManager` names, with any `+sha` integrity suffix ignored on both sides. Pins of other package managers are not the workspace's package manager and are left alone.
|
|
342
|
+
*
|
|
343
|
+
* It reads `<manager>@<version>` as written on a line that is not a comment. A version that refers to a variable is compared with the value the file gives that variable by an `ARG` or `ENV` before the pin (the latest such value, whichever build stage it was in); one whose variable has no value in the file is not compared, since the build supplies it.
|
|
344
|
+
*/
|
|
345
|
+
export declare const dockerfilePackageManager: CheckFunction<DockerfilePackageManagerOptions>;
|
|
346
|
+
//#endregion
|
|
347
|
+
//#region src/workspace/packages.d.ts
|
|
348
|
+
/**
|
|
349
|
+
* A package directory found under the workspace root, before the layout classifies it.
|
|
350
|
+
*/
|
|
351
|
+
interface DiscoveredPackage {
|
|
352
|
+
/**
|
|
353
|
+
* Relative to the workspace root, with `/` separators.
|
|
354
|
+
*/
|
|
355
|
+
readonly dir: string;
|
|
356
|
+
/**
|
|
357
|
+
* The manifest's `name`; a manifest may omit it.
|
|
358
|
+
*/
|
|
359
|
+
readonly name: string | undefined;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* A workspace package as the layout sees it.
|
|
363
|
+
*/
|
|
364
|
+
interface WorkspacePackage extends DiscoveredPackage {
|
|
365
|
+
/**
|
|
366
|
+
* The name of the group whose root is the longest prefix of the package directory.
|
|
367
|
+
*/
|
|
368
|
+
readonly group: string;
|
|
369
|
+
/**
|
|
370
|
+
* The rank from `nameRanks`, else the group's rank, else `defaultRank`; `undefined` when none of them applies.
|
|
371
|
+
*/
|
|
372
|
+
readonly rank: number | undefined;
|
|
373
|
+
/**
|
|
374
|
+
* The slice the group's `slice` rule derives; `undefined` for a group without one and for a package that yields none.
|
|
375
|
+
*/
|
|
376
|
+
readonly slice: string | undefined;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Classify discovered packages by the layout: group, rank and slice. Pure.
|
|
380
|
+
*
|
|
381
|
+
* A package no group owns is a configuration error, because every check would otherwise skip it without saying so. Nested package directories are one too: the checks attribute a file to the package whose directory is its prefix, which is ambiguous for a package inside another. A `namePrefix` slice takes the longest slice value that a `segment` group produced and that prefixes the package's unscoped name; a package without a name has no such slice.
|
|
382
|
+
*/
|
|
383
|
+
export declare function classifyPackages(discovered: readonly DiscoveredPackage[], layout: LayoutConfig): readonly WorkspacePackage[];
|
|
384
|
+
//#endregion
|
|
385
|
+
//#region src/workspace/rules.d.ts
|
|
386
|
+
/**
|
|
387
|
+
* A forbidden-dependency rule in the shape dependency-cruiser takes: a dependency from a file matching `from` to a file matching `to` is a violation.
|
|
388
|
+
*/
|
|
389
|
+
interface ImportRule {
|
|
390
|
+
readonly name: string;
|
|
391
|
+
readonly severity: "error";
|
|
392
|
+
readonly comment: string;
|
|
393
|
+
readonly from: {
|
|
394
|
+
readonly path?: string;
|
|
395
|
+
};
|
|
396
|
+
readonly to: {
|
|
397
|
+
readonly path?: string;
|
|
398
|
+
readonly circular?: boolean;
|
|
399
|
+
readonly couldNotResolve?: boolean;
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* A regular expression, as source text, matching every file inside any of the packages. The trailing `/` keeps `packages/a` from matching `packages/ab`.
|
|
404
|
+
*/
|
|
405
|
+
export declare function packagesPattern(packages: readonly WorkspacePackage[]): string;
|
|
406
|
+
/**
|
|
407
|
+
* One rule per rank that has a higher rank above it: files of a package at that rank may not import a package at a strictly higher rank. A rule compares no numbers, so the ordering is expanded into path alternations here. Each rule comes with a `-by-name` rule for imports that do not resolve to a file.
|
|
408
|
+
*/
|
|
409
|
+
export declare function uphillRules(packages: readonly WorkspacePackage[]): readonly ImportRule[];
|
|
410
|
+
/**
|
|
411
|
+
* One rule per rank with a package more than `rankSkip.maxDistance` ranks below it that is not an exempt rank.
|
|
412
|
+
*/
|
|
413
|
+
export declare function rankSkipRules(packages: readonly WorkspacePackage[], rankSkip: RankSkipOptions): readonly ImportRule[];
|
|
414
|
+
/**
|
|
415
|
+
* One rule per slice: a package in it may not import a package that has a different slice. A package without a slice is in none and is never restricted.
|
|
416
|
+
*/
|
|
417
|
+
export declare function crossSliceRules(packages: readonly WorkspacePackage[]): readonly ImportRule[];
|
|
418
|
+
/**
|
|
419
|
+
* Two rules per isolated pair, one for each direction.
|
|
420
|
+
*/
|
|
421
|
+
export declare function isolatedGroupRules(packages: readonly WorkspacePackage[], isolatedGroups: NonNullable<LayoutConfig["isolatedGroups"]>): readonly ImportRule[];
|
|
422
|
+
/**
|
|
423
|
+
* The rule that forbids any import cycle among the packages' files.
|
|
424
|
+
*/
|
|
425
|
+
export declare function cycleRule(): ImportRule;
|
|
426
|
+
//#endregion
|
|
427
|
+
//#region src/checks/import-graph.d.ts
|
|
428
|
+
/**
|
|
429
|
+
* What a check's report may need to know about the workspace the graph was cruised over.
|
|
430
|
+
*/
|
|
431
|
+
interface ImportScope {
|
|
432
|
+
readonly cwd: string;
|
|
433
|
+
/**
|
|
434
|
+
* The workspace root; finding paths are relative to it.
|
|
435
|
+
*/
|
|
436
|
+
readonly root: string;
|
|
437
|
+
readonly packages: readonly WorkspacePackage[];
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* How an import check takes part in a shared cruise: the rules it adds and how it reads its own findings. Findings are routed to a check by the names of the rules it generated, so those names must differ from every other check's.
|
|
441
|
+
*/
|
|
442
|
+
interface ImportCheckSpec {
|
|
443
|
+
/**
|
|
444
|
+
* The check's name; the violation code is `<name>/<reason>`.
|
|
445
|
+
*/
|
|
446
|
+
readonly name: string;
|
|
447
|
+
/**
|
|
448
|
+
* The forbidden rules for the workspace's packages. Throws `ConformanceError` when the layout does not configure what the check needs.
|
|
449
|
+
*/
|
|
450
|
+
readonly rules: (packages: readonly WorkspacePackage[], layout: LayoutConfig) => readonly ImportRule[];
|
|
451
|
+
/**
|
|
452
|
+
* The violations for the findings of this check's rules, in a stable order.
|
|
453
|
+
*/
|
|
454
|
+
readonly report: (findings: readonly IViolation[], scope: ImportScope) => readonly Violation[];
|
|
455
|
+
}
|
|
456
|
+
//#endregion
|
|
457
|
+
//#region src/checks/import-cross-slice.d.ts
|
|
458
|
+
/**
|
|
459
|
+
* A package imports a package in a different slice.
|
|
460
|
+
*/
|
|
461
|
+
export declare const importCrossSlice: LayoutCheckFunction<ImportGraphOptions>;
|
|
462
|
+
//#endregion
|
|
463
|
+
//#region src/checks/import-cycles.d.ts
|
|
464
|
+
/**
|
|
465
|
+
* Files of the workspace's packages import each other in a cycle, and so do packages that import each other by a name that resolves to no file. Each cycle is reported once, at its first file (or, for packages, the file of the first import), starting from its smallest path.
|
|
466
|
+
*
|
|
467
|
+
* Cycles among packages are found only when every import in the ring is by a name that resolves to no file. A ring that mixes such imports with imports that do resolve to files has no complete path through either graph and is not seen.
|
|
468
|
+
*/
|
|
469
|
+
export declare const importCycles: LayoutCheckFunction<ImportGraphOptions>;
|
|
470
|
+
//#endregion
|
|
471
|
+
//#region src/checks/import-isolated-groups.d.ts
|
|
472
|
+
/**
|
|
473
|
+
* A package imports a package in a group the layout isolates from its own.
|
|
474
|
+
*/
|
|
475
|
+
export declare const importIsolatedGroups: LayoutCheckFunction<ImportGraphOptions>;
|
|
476
|
+
//#endregion
|
|
477
|
+
//#region src/checks/import-rank-skip.d.ts
|
|
478
|
+
/**
|
|
479
|
+
* A package imports a package more than `rankSkip.maxDistance` ranks below it that is not in `rankSkip.exemptRanks`.
|
|
480
|
+
*/
|
|
481
|
+
export declare const importRankSkip: LayoutCheckFunction<ImportGraphOptions>;
|
|
482
|
+
//#endregion
|
|
483
|
+
//#region src/checks/import-uphill.d.ts
|
|
484
|
+
/**
|
|
485
|
+
* A package imports a package of a strictly higher rank: dependencies run downhill only.
|
|
486
|
+
*/
|
|
487
|
+
export declare const importUphill: LayoutCheckFunction<ImportGraphOptions>;
|
|
488
|
+
//#endregion
|
|
489
|
+
//#region src/checks/instruction-symlinks.d.ts
|
|
490
|
+
/**
|
|
491
|
+
* Each agent instruction file is tracked by git as a symbolic link (mode 120000) whose target is the README beside it, so the two cannot diverge. The link may be written in any form that resolves there (`./README.md`), and may lead through other tracked links, as in `CLAUDE.md` to `AGENTS.md` to `README.md`. It reads the index, not the working tree, so a checkout with `core.symlinks` false, where a link is written out as a plain file, is judged by what is committed.
|
|
492
|
+
*/
|
|
493
|
+
export declare const instructionSymlinks: CheckFunction<InstructionSymlinksOptions>;
|
|
494
|
+
//#endregion
|
|
495
|
+
//#region src/checks/migrations-directory.d.ts
|
|
496
|
+
/**
|
|
497
|
+
* The directory a schema generator writes migrations to is the one the deploy tool applies them from, and no script applies them with the generator instead of the deploy tool. The generator and the deploy tool are named in the options and each has an adapter that knows its config file names and where in them the directory is; both directories are resolved against the directory of the file that sets them.
|
|
498
|
+
*
|
|
499
|
+
* The config files are read as data: JSON, JSONC and TOML are parsed, and a module (a generator's TypeScript config) is evaluated, so it must be trusted.
|
|
500
|
+
*/
|
|
501
|
+
export declare const migrationsDirectory: CheckFunction<MigrationsDirectoryOptions>;
|
|
502
|
+
//#endregion
|
|
503
|
+
//#region src/checks/single-storybook.d.ts
|
|
504
|
+
/**
|
|
505
|
+
* At most one Storybook exists, in the permitted directory (the workspace root unless the options say otherwise), and none in a package such as a UI package. A Storybook is a `.storybook` directory.
|
|
506
|
+
*/
|
|
507
|
+
export declare const singleStorybook: CheckFunction<SingleStorybookOptions>;
|
|
508
|
+
//#endregion
|
|
509
|
+
//#region src/config.d.ts
|
|
510
|
+
/**
|
|
511
|
+
* The `checks` map of the `conformance` section: a check runs when its name is present with an options object (`{}` for the defaults), and `false` turns it off, which lets a config that extends another switch one of its checks off.
|
|
512
|
+
*/
|
|
513
|
+
type ChecksConfig = { readonly [Name in CheckName]?: false | CheckOptionsByName[Name]; };
|
|
514
|
+
/**
|
|
515
|
+
* The `conformance` section: which checks are enabled and their options.
|
|
516
|
+
*/
|
|
517
|
+
interface ConformanceConfig {
|
|
518
|
+
readonly checks: ChecksConfig;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* The Standard Schema for {@link ConformanceConfig}. It rejects unknown keys at every level, so a misspelt check name or option fails when the section loads.
|
|
522
|
+
*/
|
|
523
|
+
export declare const conformanceSchema: z.ZodType<ConformanceConfig, ConformanceConfig>;
|
|
524
|
+
/**
|
|
525
|
+
* The `conformance` section. Pass it to `withSections` beside `layoutSection` when authoring `exadev.config.ts`.
|
|
526
|
+
*/
|
|
527
|
+
export declare const conformanceSection: Section<"conformance", z.ZodType<ConformanceConfig, ConformanceConfig>>;
|
|
528
|
+
//#endregion
|
|
529
|
+
//#region src/errors.d.ts
|
|
530
|
+
/**
|
|
531
|
+
* A problem with how the tool was used or configured rather than a finding about the workspace: an unknown or disabled check, a missing or invalid section, a layout that cannot be resolved, a repository that is not a git checkout. The command line reports it and exits 2.
|
|
532
|
+
*/
|
|
533
|
+
export declare class ConformanceError extends Error {
|
|
534
|
+
constructor(message: string, options?: ErrorOptions);
|
|
535
|
+
}
|
|
536
|
+
//#endregion
|
|
537
|
+
//#region src/registry.d.ts
|
|
538
|
+
/**
|
|
539
|
+
* What a check needs to run once the configuration is loaded.
|
|
540
|
+
*/
|
|
541
|
+
interface RunInput {
|
|
542
|
+
readonly cwd: string;
|
|
543
|
+
readonly checks: ChecksConfig;
|
|
544
|
+
readonly layout: LayoutConfig | undefined;
|
|
545
|
+
readonly configFiles: ConfigFileOptions | undefined;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* What every registered check has, whichever way it runs.
|
|
549
|
+
*/
|
|
550
|
+
interface RegisteredCheckBase<Name extends CheckName> {
|
|
551
|
+
readonly name: Name;
|
|
552
|
+
readonly description: string;
|
|
553
|
+
/**
|
|
554
|
+
* Whether the check reads the workspace layout, and so needs the `layout` section.
|
|
555
|
+
*/
|
|
556
|
+
readonly requiresLayout: boolean;
|
|
557
|
+
/**
|
|
558
|
+
* Whether the `checks` map turns this check on.
|
|
559
|
+
*/
|
|
560
|
+
readonly isEnabled: (checks: ChecksConfig) => boolean;
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* A check that runs on its own.
|
|
564
|
+
*/
|
|
565
|
+
interface StandaloneCheck<Name extends CheckName> extends RegisteredCheckBase<Name> {
|
|
566
|
+
readonly run: (input: RunInput) => Promise<readonly Violation[]>;
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* An import check. It has no `run` of its own: it always joins a cruise shared with the other import checks of the run, so there is one path from the registry to dependency-cruiser.
|
|
570
|
+
*/
|
|
571
|
+
interface ImportGraphCheck<Name extends CheckName> extends RegisteredCheckBase<Name> {
|
|
572
|
+
readonly importGraph: {
|
|
573
|
+
readonly spec: ImportCheckSpec;
|
|
574
|
+
readonly optionsOf: (checks: ChecksConfig) => ImportGraphOptions | undefined;
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* A check bound to its place in the `checks` map.
|
|
579
|
+
*/
|
|
580
|
+
type RegisteredCheck<Name extends CheckName> = StandaloneCheck<Name> | ImportGraphCheck<Name>;
|
|
581
|
+
/**
|
|
582
|
+
* Every check, by name, in the order they run. The key is the name used in the `checks` map, on the command line and in violation codes.
|
|
583
|
+
*/
|
|
584
|
+
export declare const registry: { readonly [Name in CheckName]: RegisteredCheck<Name>; };
|
|
585
|
+
/**
|
|
586
|
+
* The names of all checks, in the order they run.
|
|
587
|
+
*/
|
|
588
|
+
export declare const checkNames: readonly CheckName[];
|
|
589
|
+
/**
|
|
590
|
+
* Whether `name` is the name of a check.
|
|
591
|
+
*/
|
|
592
|
+
export declare function isCheckName(name: string): name is CheckName;
|
|
593
|
+
//#endregion
|
|
594
|
+
//#region src/run-checks.d.ts
|
|
595
|
+
/**
|
|
596
|
+
* The process exit codes of the command line: nothing found, something found, or the checks could not run.
|
|
597
|
+
*/
|
|
598
|
+
export declare const EXIT_CODES: {
|
|
599
|
+
readonly clean: 0;
|
|
600
|
+
readonly violations: 1;
|
|
601
|
+
readonly failed: 2;
|
|
602
|
+
};
|
|
603
|
+
/**
|
|
604
|
+
* Options of {@link runChecks}.
|
|
605
|
+
*/
|
|
606
|
+
interface RunChecksOptions {
|
|
607
|
+
/**
|
|
608
|
+
* The directory that holds the config files and that every path option is relative to.
|
|
609
|
+
*/
|
|
610
|
+
readonly cwd: string;
|
|
611
|
+
/**
|
|
612
|
+
* Run only these checks. Each must be enabled. Every enabled check runs when omitted.
|
|
613
|
+
*/
|
|
614
|
+
readonly checks?: readonly CheckName[];
|
|
615
|
+
/**
|
|
616
|
+
* The `conformance` section, instead of loading it from `cwd`. It is validated against the section's schema.
|
|
617
|
+
*/
|
|
618
|
+
readonly config?: ConformanceConfig;
|
|
619
|
+
/**
|
|
620
|
+
* The `layout` section, instead of loading it from `cwd`. It is validated against the section's schema. Read only by the checks that need it.
|
|
621
|
+
*/
|
|
622
|
+
readonly layout?: LayoutConfig;
|
|
623
|
+
/**
|
|
624
|
+
* How config files are loaded: the sections loaded from `cwd` and the config files a check evaluates itself, such as the commitlint and release configs of `commit-types`. Only `alias` and `fsCache` apply to the latter.
|
|
625
|
+
*/
|
|
626
|
+
readonly configFiles?: ConfigFileOptions;
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* The violations of one check.
|
|
630
|
+
*/
|
|
631
|
+
interface CheckResult {
|
|
632
|
+
readonly check: CheckName;
|
|
633
|
+
readonly violations: readonly Violation[];
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* The outcome of running checks.
|
|
637
|
+
*/
|
|
638
|
+
interface RunResult {
|
|
639
|
+
/**
|
|
640
|
+
* One entry per check that ran, in the order they ran.
|
|
641
|
+
*/
|
|
642
|
+
readonly results: readonly CheckResult[];
|
|
643
|
+
/**
|
|
644
|
+
* Every violation of every check, by check.
|
|
645
|
+
*/
|
|
646
|
+
readonly violations: readonly Violation[];
|
|
647
|
+
/**
|
|
648
|
+
* {@link EXIT_CODES}`.clean` when there are no violations, else {@link EXIT_CODES}`.violations`.
|
|
649
|
+
*/
|
|
650
|
+
readonly exitCode: typeof EXIT_CODES.clean | typeof EXIT_CODES.violations;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Run the enabled checks, or the enabled ones among `checks`, and return what they found. Sections not supplied in the options are loaded from `cwd` with `@exadev/config`.
|
|
654
|
+
*
|
|
655
|
+
* Violations do not throw. It throws `ConformanceError` when the checks cannot run (nothing enabled, a requested check disabled, a section missing) and `ConfigValidationError` when a section fails its schema, whether it was loaded from `cwd` or passed in.
|
|
656
|
+
*/
|
|
657
|
+
export declare function runChecks(options: RunChecksOptions): Promise<RunResult>;
|
|
658
|
+
//#endregion
|
|
659
|
+
//#region src/type-level.d.ts
|
|
660
|
+
/**
|
|
661
|
+
* A compiler error found in an in-memory file.
|
|
662
|
+
*/
|
|
663
|
+
interface TypeErrorReport {
|
|
664
|
+
readonly file: string;
|
|
665
|
+
readonly line: number;
|
|
666
|
+
/**
|
|
667
|
+
* The TypeScript diagnostic code, such as 2741 for a property missing from an object literal.
|
|
668
|
+
*/
|
|
669
|
+
readonly code: number;
|
|
670
|
+
readonly message: string;
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* The outcome of removing one case from a handler map.
|
|
674
|
+
*/
|
|
675
|
+
interface CaseRemoval {
|
|
676
|
+
readonly case: string;
|
|
677
|
+
/**
|
|
678
|
+
* What the compiler reports once the case is gone; never empty in a proof that held.
|
|
679
|
+
*/
|
|
680
|
+
readonly errors: readonly TypeErrorReport[];
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* What {@link proveExhaustive} established: the map type-checks as written, and every case it was asked about breaks the type check when removed.
|
|
684
|
+
*/
|
|
685
|
+
interface ExhaustivenessProof {
|
|
686
|
+
readonly removals: readonly CaseRemoval[];
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Raised when a handler map is not exhaustive as claimed, or when the map cannot be found.
|
|
690
|
+
*/
|
|
691
|
+
export declare class ExhaustivenessError extends Error {
|
|
692
|
+
constructor(message: string);
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Compile the files in memory and return every error the type checker reports. Names are paths in the in-memory file system, so one file can import another with a relative path.
|
|
696
|
+
*/
|
|
697
|
+
export declare function typeErrors(files: Readonly<Record<string, string>>, options?: CompilerOptions): readonly TypeErrorReport[];
|
|
698
|
+
/**
|
|
699
|
+
* The names of the cases of the handler map `map`, an object literal assigned to a variable of that name in `source`.
|
|
700
|
+
*/
|
|
701
|
+
export declare function handlerCases(source: string, map: string): readonly string[];
|
|
702
|
+
/**
|
|
703
|
+
* `source` with the case `key` deleted from the handler map `map`.
|
|
704
|
+
*/
|
|
705
|
+
export declare function removeCase(source: string, map: string, key: string): string;
|
|
706
|
+
/**
|
|
707
|
+
* Prove that the handler map `map` in `files[file]` is checked for exhaustiveness by the compiler: the files type-check as written, and deleting any one case (each in `cases`, else every case of the map) makes them fail. Throws {@link ExhaustivenessError} otherwise.
|
|
708
|
+
*
|
|
709
|
+
* Write the handler map's type so the compiler demands every case, for example a mapped type over the union of command types, and call this from an ordinary test:
|
|
710
|
+
*
|
|
711
|
+
* ```ts
|
|
712
|
+
* proveExhaustive({ files: { 'handlers.ts': source }, file: 'handlers.ts', map: 'handlers' });
|
|
713
|
+
* ```
|
|
714
|
+
*/
|
|
715
|
+
export declare function proveExhaustive(input: {
|
|
716
|
+
readonly files: Readonly<Record<string, string>>;
|
|
717
|
+
readonly file: string;
|
|
718
|
+
readonly map: string;
|
|
719
|
+
readonly cases?: readonly string[];
|
|
720
|
+
readonly compilerOptions?: CompilerOptions;
|
|
721
|
+
}): ExhaustivenessProof;
|
|
722
|
+
//#endregion
|
|
723
|
+
export type { AggregateMappersOptions, CaseRemoval, CheckContext, CheckFunction, CheckName, CheckOptionsByName, CheckResult, ChecksConfig, CommandTypesOptions, CommitTypesOptions, ConformanceConfig, DeployDirectory, DeploySelector, DeployToolAdapter, DeployToolName, DiscoveredPackage, DockerfilePackageManagerOptions, ExhaustivenessProof, GeneratorAdapter, GeneratorName, ImportGraphOptions, InstructionSymlinksOptions, LayoutCheckContext, LayoutCheckFunction, MigrationsDirectoryOptions, RegisteredCheck, RunChecksOptions, RunResult, SingleStorybookOptions, SourceLocation, TypeErrorReport, Violation, WorkspacePackage };
|