@trebired/code-discipline 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/CHANGELOG.md +20 -0
- package/LICENSE +661 -0
- package/README.md +241 -0
- package/dist/checks/index.d.ts +4 -0
- package/dist/checks/index.d.ts.map +1 -0
- package/dist/checks/index.js +22 -0
- package/dist/checks/index.js.map +1 -0
- package/dist/checks/rules/folderize-compound-files.d.ts +5 -0
- package/dist/checks/rules/folderize-compound-files.d.ts.map +1 -0
- package/dist/checks/rules/folderize-compound-files.js +37 -0
- package/dist/checks/rules/folderize-compound-files.js.map +1 -0
- package/dist/checks/rules/max-file-lines.d.ts +5 -0
- package/dist/checks/rules/max-file-lines.d.ts.map +1 -0
- package/dist/checks/rules/max-file-lines.js +30 -0
- package/dist/checks/rules/max-file-lines.js.map +1 -0
- package/dist/checks/types.d.ts +64 -0
- package/dist/checks/types.d.ts.map +1 -0
- package/dist/checks/types.js +2 -0
- package/dist/checks/types.js.map +1 -0
- package/dist/cli/run-cli.d.ts +13 -0
- package/dist/cli/run-cli.d.ts.map +1 -0
- package/dist/cli/run-cli.js +104 -0
- package/dist/cli/run-cli.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +10 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +49 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/normalize-check-options.d.ts +4 -0
- package/dist/config/normalize-check-options.d.ts.map +1 -0
- package/dist/config/normalize-check-options.js +14 -0
- package/dist/config/normalize-check-options.js.map +1 -0
- package/dist/config/normalize-rule-options.d.ts +14 -0
- package/dist/config/normalize-rule-options.d.ts.map +1 -0
- package/dist/config/normalize-rule-options.js +51 -0
- package/dist/config/normalize-rule-options.js.map +1 -0
- package/dist/config/normalize-source-options.d.ts +16 -0
- package/dist/config/normalize-source-options.d.ts.map +1 -0
- package/dist/config/normalize-source-options.js +24 -0
- package/dist/config/normalize-source-options.js.map +1 -0
- package/dist/config/normalize-sync-imports-options.d.ts +4 -0
- package/dist/config/normalize-sync-imports-options.d.ts.map +1 -0
- package/dist/config/normalize-sync-imports-options.js +34 -0
- package/dist/config/normalize-sync-imports-options.js.map +1 -0
- package/dist/imports/aliases.d.ts +9 -0
- package/dist/imports/aliases.d.ts.map +1 -0
- package/dist/imports/aliases.js +150 -0
- package/dist/imports/aliases.js.map +1 -0
- package/dist/imports/resolve.d.ts +7 -0
- package/dist/imports/resolve.d.ts.map +1 -0
- package/dist/imports/resolve.js +49 -0
- package/dist/imports/resolve.js.map +1 -0
- package/dist/imports/rewrite.d.ts +5 -0
- package/dist/imports/rewrite.d.ts.map +1 -0
- package/dist/imports/rewrite.js +139 -0
- package/dist/imports/rewrite.js.map +1 -0
- package/dist/imports/scan.d.ts +4 -0
- package/dist/imports/scan.d.ts.map +1 -0
- package/dist/imports/scan.js +44 -0
- package/dist/imports/scan.js.map +1 -0
- package/dist/imports/strategies.d.ts +7 -0
- package/dist/imports/strategies.d.ts.map +1 -0
- package/dist/imports/strategies.js +55 -0
- package/dist/imports/strategies.js.map +1 -0
- package/dist/imports/sync-imports.d.ts +4 -0
- package/dist/imports/sync-imports.d.ts.map +1 -0
- package/dist/imports/sync-imports.js +41 -0
- package/dist/imports/sync-imports.js.map +1 -0
- package/dist/imports/types.d.ts +104 -0
- package/dist/imports/types.d.ts.map +1 -0
- package/dist/imports/types.js +2 -0
- package/dist/imports/types.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/shared/constants.d.ts +18 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +18 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/errors.d.ts +34 -0
- package/dist/shared/errors.d.ts.map +1 -0
- package/dist/shared/errors.js +64 -0
- package/dist/shared/errors.js.map +1 -0
- package/dist/shared/logging-types.d.ts +18 -0
- package/dist/shared/logging-types.d.ts.map +1 -0
- package/dist/shared/logging-types.js +2 -0
- package/dist/shared/logging-types.js.map +1 -0
- package/dist/shared/logging.d.ts +5 -0
- package/dist/shared/logging.d.ts.map +1 -0
- package/dist/shared/logging.js +99 -0
- package/dist/shared/logging.js.map +1 -0
- package/dist/shared/utils.d.ts +24 -0
- package/dist/shared/utils.d.ts.map +1 -0
- package/dist/shared/utils.js +127 -0
- package/dist/shared/utils.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# @trebired/code-discipline
|
|
2
|
+
|
|
3
|
+
Configurable codebase discipline checks and import syncing for Bun and Node.js projects.
|
|
4
|
+
|
|
5
|
+
`@trebired/code-discipline` scans a configured source tree, runs project-level discipline rules, and can also keep TypeScript path aliases plus source imports aligned in one package.
|
|
6
|
+
|
|
7
|
+
The package is intentionally focused. It helps with repository structure rules, file-shape rules, and import hygiene. It does not try to be a full linter, formatter, or build system.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
Runtime support: Bun 1+ and Node.js 18+.
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install @trebired/code-discipline
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { checkCodeDiscipline } from "@trebired/code-discipline";
|
|
21
|
+
|
|
22
|
+
const result = await checkCodeDiscipline({
|
|
23
|
+
projectRoot: "/repo",
|
|
24
|
+
sourceRoot: "src",
|
|
25
|
+
rules: {
|
|
26
|
+
maxFileLines: {
|
|
27
|
+
enabled: true,
|
|
28
|
+
max: 500,
|
|
29
|
+
},
|
|
30
|
+
folderizeCompoundFiles: {
|
|
31
|
+
enabled: true,
|
|
32
|
+
suffixes: ["start", "service"],
|
|
33
|
+
separators: ["_", "-"],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (!result.ok) {
|
|
39
|
+
console.error(result.violations);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The first public slice is intentionally small:
|
|
45
|
+
|
|
46
|
+
- `checkCodeDiscipline()`
|
|
47
|
+
- `syncImports()`
|
|
48
|
+
- `defineCodeDisciplineConfig()`
|
|
49
|
+
- `loadCodeDisciplineConfig()`
|
|
50
|
+
|
|
51
|
+
If you want repo-driven usage instead of embedding the API directly, use the CLI with a top-level config file:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
code-discipline check
|
|
55
|
+
code-discipline sync
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## What This Package Checks
|
|
59
|
+
|
|
60
|
+
The first discipline layer is intentionally narrow:
|
|
61
|
+
|
|
62
|
+
- `maxFileLines`
|
|
63
|
+
- `folderizeCompoundFiles`
|
|
64
|
+
|
|
65
|
+
`maxFileLines` reports files whose physical line count exceeds a configured threshold.
|
|
66
|
+
|
|
67
|
+
`folderizeCompoundFiles` reports names such as `user_start.ts` or `user-start.ts` that could be grouped into a more structured path such as `user/start.ts`.
|
|
68
|
+
|
|
69
|
+
Example:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { checkCodeDiscipline } from "@trebired/code-discipline";
|
|
73
|
+
|
|
74
|
+
const result = await checkCodeDiscipline({
|
|
75
|
+
projectRoot: "/repo",
|
|
76
|
+
rules: {
|
|
77
|
+
maxFileLines: {
|
|
78
|
+
enabled: true,
|
|
79
|
+
max: 500,
|
|
80
|
+
severity: "error",
|
|
81
|
+
},
|
|
82
|
+
folderizeCompoundFiles: {
|
|
83
|
+
enabled: true,
|
|
84
|
+
suffixes: ["start"],
|
|
85
|
+
separators: ["_", "-"],
|
|
86
|
+
severity: "warn",
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The result shape stays simple:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
{
|
|
96
|
+
ok: boolean;
|
|
97
|
+
warnings: number;
|
|
98
|
+
errors: number;
|
|
99
|
+
violations: Array<{
|
|
100
|
+
rule: "max-file-lines" | "folderize-compound-files";
|
|
101
|
+
severity: "warn" | "error";
|
|
102
|
+
filePath: string;
|
|
103
|
+
message: string;
|
|
104
|
+
details: Record<string, unknown>;
|
|
105
|
+
suggestedPath?: string;
|
|
106
|
+
}>;
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Checks are read-only. They report problems and let the caller decide whether to fail startup, fail CI, or only warn.
|
|
111
|
+
|
|
112
|
+
## CLI And Config
|
|
113
|
+
|
|
114
|
+
The CLI is meant for repository-owned discipline rules:
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
code-discipline check
|
|
118
|
+
code-discipline sync
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Both commands accept `--config <path>`. When that flag is omitted, the CLI looks for `code-discipline.config.json` in the current working directory.
|
|
122
|
+
|
|
123
|
+
Example config:
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"sourceRoot": "src",
|
|
128
|
+
"rules": {
|
|
129
|
+
"maxFileLines": {
|
|
130
|
+
"enabled": true,
|
|
131
|
+
"max": 500
|
|
132
|
+
},
|
|
133
|
+
"folderizeCompoundFiles": {
|
|
134
|
+
"enabled": true,
|
|
135
|
+
"suffixes": ["start", "service"],
|
|
136
|
+
"separators": ["_", "-"]
|
|
137
|
+
},
|
|
138
|
+
"syncImports": {
|
|
139
|
+
"alias": {
|
|
140
|
+
"strategy": "relative-path-slug"
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`check` is read-only. It reports violations and exits non-zero when any error-severity rule fails.
|
|
148
|
+
|
|
149
|
+
`sync` is the mutating import-alignment command. It updates `compilerOptions.paths` and rewrites eligible source imports.
|
|
150
|
+
|
|
151
|
+
In practice:
|
|
152
|
+
|
|
153
|
+
- use JSON config plus the CLI when the rules belong to the repo
|
|
154
|
+
- use the API when another tool wants to control configuration or reporting dynamically
|
|
155
|
+
|
|
156
|
+
## Import Sync
|
|
157
|
+
|
|
158
|
+
`syncImports()` remains a first-class part of the package. It scans source files, generates aliases, preserves still-valid alias ids, writes stable `compilerOptions.paths` output, and rewrites eligible relative imports to those aliases.
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
import { syncImports } from "@trebired/code-discipline";
|
|
162
|
+
|
|
163
|
+
const result = await syncImports({
|
|
164
|
+
projectRoot: "/repo",
|
|
165
|
+
sourceRoot: "src",
|
|
166
|
+
tsconfigPath: "/repo/tsconfig.json",
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Default behavior:
|
|
171
|
+
|
|
172
|
+
- `sourceRoot: "src"`
|
|
173
|
+
- `tsconfigPath: "<projectRoot>/tsconfig.json"`
|
|
174
|
+
- `sourceExtensions: [".ts", ".tsx", ".js", ".jsx"]`
|
|
175
|
+
- `excludeDirs: ["node_modules", "dist", ".vite"]`
|
|
176
|
+
- `imports.rewrite: true`
|
|
177
|
+
- `imports.keepRelative: ["./"]`
|
|
178
|
+
- `alias.prefix: "#"`
|
|
179
|
+
- `alias.strategy: "random"`
|
|
180
|
+
- `alias.randomLength: 12`
|
|
181
|
+
|
|
182
|
+
By default, same-directory imports such as `./local` stay relative. Imports that walk upward, such as `../shared/util`, are eligible for rewrite when they resolve to a file under the configured source root.
|
|
183
|
+
|
|
184
|
+
Alias strategies:
|
|
185
|
+
|
|
186
|
+
- `"random"`
|
|
187
|
+
- `"relative-path-slug"`
|
|
188
|
+
- `"relative-path-hash"`
|
|
189
|
+
- custom function
|
|
190
|
+
|
|
191
|
+
Example custom strategy:
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
await syncImports({
|
|
195
|
+
projectRoot: "/repo",
|
|
196
|
+
alias: {
|
|
197
|
+
strategy(input) {
|
|
198
|
+
return `@${input.relativeFromSourceRoot.replace(/\//g, "__")}`;
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
If a custom strategy returns an invalid id or a duplicate id, the package fails clearly instead of guessing a fallback.
|
|
205
|
+
|
|
206
|
+
## Why This Package
|
|
207
|
+
|
|
208
|
+
Many repository rules are awkward in a single-file linter pass because they are really about the shape of a source tree, not only one file at a time.
|
|
209
|
+
|
|
210
|
+
This package is a better fit when you want checks such as:
|
|
211
|
+
|
|
212
|
+
- file-size limits across a configured source root
|
|
213
|
+
- filename patterns that imply a cleaner folder layout
|
|
214
|
+
- path alias synchronization across many files
|
|
215
|
+
- startup, CI, or pre-build gates based on repository conventions
|
|
216
|
+
|
|
217
|
+
It is intentionally repo-oriented. The package does one lane of work: codebase discipline plus import alignment.
|
|
218
|
+
|
|
219
|
+
## Current API
|
|
220
|
+
|
|
221
|
+
- `checkCodeDiscipline()`
|
|
222
|
+
- `defineCodeDisciplineConfig()`
|
|
223
|
+
- `loadCodeDisciplineConfig()`
|
|
224
|
+
- `syncImports()`
|
|
225
|
+
- `scanSourceFiles()`
|
|
226
|
+
- `syncTsconfigAliases()`
|
|
227
|
+
- `rewriteSourceImports()`
|
|
228
|
+
- `resolveRelativeImport()`
|
|
229
|
+
- `createRandomAlias()`
|
|
230
|
+
- `createRelativePathHashAlias()`
|
|
231
|
+
- `createRelativePathSlugAlias()`
|
|
232
|
+
|
|
233
|
+
The package also exports the public TypeScript types for options, results, violations, alias strategies, keep-relative callbacks, log events, and source scan rows.
|
|
234
|
+
|
|
235
|
+
## What This Package Does Not Do
|
|
236
|
+
|
|
237
|
+
- it does not build or compile TypeScript
|
|
238
|
+
- it does not move files automatically for folderization violations
|
|
239
|
+
- it does not rewrite emitted build output
|
|
240
|
+
- it does not depend on ESLint
|
|
241
|
+
- it does not assume a framework-specific runtime layout
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/checks/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAIxF,iBAAe,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAiB1G;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { normalizeCheckCodeDisciplineOptions } from "../config/normalize-check-options.js";
|
|
2
|
+
import { scanSourceFiles } from "../imports/scan.js";
|
|
3
|
+
import { runFolderizeCompoundFilesRule } from "./rules/folderize-compound-files.js";
|
|
4
|
+
import { runMaxFileLinesRule } from "./rules/max-file-lines.js";
|
|
5
|
+
async function checkCodeDiscipline(options) {
|
|
6
|
+
const normalized = await normalizeCheckCodeDisciplineOptions(options);
|
|
7
|
+
const sourceFiles = await scanSourceFiles(normalized);
|
|
8
|
+
const maxFileViolations = await runMaxFileLinesRule(sourceFiles, normalized);
|
|
9
|
+
const folderizeViolations = runFolderizeCompoundFilesRule(sourceFiles, normalized);
|
|
10
|
+
const violations = [...maxFileViolations, ...folderizeViolations]
|
|
11
|
+
.sort((left, right) => left.filePath.localeCompare(right.filePath) || left.rule.localeCompare(right.rule));
|
|
12
|
+
const warnings = violations.filter((violation) => violation.severity === "warn").length;
|
|
13
|
+
const errors = violations.length - warnings;
|
|
14
|
+
return {
|
|
15
|
+
ok: errors === 0,
|
|
16
|
+
warnings,
|
|
17
|
+
errors,
|
|
18
|
+
violations,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export { checkCodeDiscipline };
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/checks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mCAAmC,EAAE,MAAM,sCAAsC,CAAC;AAC3F,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,EAAE,6BAA6B,EAAE,MAAM,qCAAqC,CAAC;AACpF,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAEhE,KAAK,UAAU,mBAAmB,CAAC,OAAmC;IACpE,MAAM,UAAU,GAAG,MAAM,mCAAmC,CAAC,OAAO,CAAC,CAAC;IACtE,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,iBAAiB,GAAG,MAAM,mBAAmB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IAC7E,MAAM,mBAAmB,GAAG,6BAA6B,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IAEnF,MAAM,UAAU,GAAG,CAAC,GAAG,iBAAiB,EAAE,GAAG,mBAAmB,CAAC;SAC9D,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7G,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IACxF,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,GAAG,QAAQ,CAAC;IAE5C,OAAO;QACL,EAAE,EAAE,MAAM,KAAK,CAAC;QAChB,QAAQ;QACR,MAAM;QACN,UAAU;KACX,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CodeDisciplineViolation, NormalizedCheckCodeDisciplineOptions } from "../types.js";
|
|
2
|
+
import type { ScannedSourceFile } from "../../imports/types.js";
|
|
3
|
+
declare function runFolderizeCompoundFilesRule(sourceFiles: ScannedSourceFile[], options: NormalizedCheckCodeDisciplineOptions): CodeDisciplineViolation[];
|
|
4
|
+
export { runFolderizeCompoundFilesRule };
|
|
5
|
+
//# sourceMappingURL=folderize-compound-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"folderize-compound-files.d.ts","sourceRoot":"","sources":["../../../src/checks/rules/folderize-compound-files.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,oCAAoC,EAAE,MAAM,aAAa,CAAC;AACjG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AA0ChE,iBAAS,6BAA6B,CACpC,WAAW,EAAE,iBAAiB,EAAE,EAChC,OAAO,EAAE,oCAAoC,GAC5C,uBAAuB,EAAE,CAI3B;AAED,OAAO,EAAE,6BAA6B,EAAE,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
function matchFolderizedFile(file, options) {
|
|
3
|
+
if (!options.rules.folderizeCompoundFiles.enabled)
|
|
4
|
+
return null;
|
|
5
|
+
const basename = path.basename(file.relativeFromSourceRoot, file.extension);
|
|
6
|
+
for (const separator of options.rules.folderizeCompoundFiles.separators) {
|
|
7
|
+
for (const suffix of options.rules.folderizeCompoundFiles.suffixes) {
|
|
8
|
+
const token = `${separator}${suffix}`;
|
|
9
|
+
if (!basename.endsWith(token))
|
|
10
|
+
continue;
|
|
11
|
+
const stem = basename.slice(0, basename.length - token.length);
|
|
12
|
+
if (!stem)
|
|
13
|
+
continue;
|
|
14
|
+
const suggestedPath = path.posix.join(path.posix.dirname(file.relativeFromProjectRoot), stem, `${suffix}${file.extension}`);
|
|
15
|
+
return {
|
|
16
|
+
rule: "folderize-compound-files",
|
|
17
|
+
severity: options.rules.folderizeCompoundFiles.severity,
|
|
18
|
+
filePath: file.relativeFromProjectRoot,
|
|
19
|
+
message: `file can be grouped under ${suggestedPath}`,
|
|
20
|
+
suggestedPath,
|
|
21
|
+
details: {
|
|
22
|
+
separator,
|
|
23
|
+
suffix,
|
|
24
|
+
stem,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
function runFolderizeCompoundFilesRule(sourceFiles, options) {
|
|
32
|
+
return sourceFiles
|
|
33
|
+
.map((file) => matchFolderizedFile(file, options))
|
|
34
|
+
.filter(Boolean);
|
|
35
|
+
}
|
|
36
|
+
export { runFolderizeCompoundFilesRule };
|
|
37
|
+
//# sourceMappingURL=folderize-compound-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"folderize-compound-files.js","sourceRoot":"","sources":["../../../src/checks/rules/folderize-compound-files.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAK7B,SAAS,mBAAmB,CAC1B,IAAuB,EACvB,OAA6C;IAE7C,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE/D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,sBAAsB,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAE5E,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,UAAU,EAAE,CAAC;QACxE,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,QAAQ,EAAE,CAAC;YACnE,MAAM,KAAK,GAAG,GAAG,SAAS,GAAG,MAAM,EAAE,CAAC;YACtC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,SAAS;YAExC,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;YAC/D,IAAI,CAAC,IAAI;gBAAE,SAAS;YAEpB,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,uBAAuB,CAAC,EAChD,IAAI,EACJ,GAAG,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAC7B,CAAC;YAEF,OAAO;gBACL,IAAI,EAAE,0BAA0B;gBAChC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,QAAQ;gBACvD,QAAQ,EAAE,IAAI,CAAC,uBAAuB;gBACtC,OAAO,EAAE,6BAA6B,aAAa,EAAE;gBACrD,aAAa;gBACb,OAAO,EAAE;oBACP,SAAS;oBACT,MAAM;oBACN,IAAI;iBACL;aACF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,6BAA6B,CACpC,WAAgC,EAChC,OAA6C;IAE7C,OAAO,WAAW;SACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;SACjD,MAAM,CAAC,OAAO,CAA8B,CAAC;AAClD,CAAC;AAED,OAAO,EAAE,6BAA6B,EAAE,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CodeDisciplineViolation, NormalizedCheckCodeDisciplineOptions } from "../types.js";
|
|
2
|
+
import type { ScannedSourceFile } from "../../imports/types.js";
|
|
3
|
+
declare function runMaxFileLinesRule(sourceFiles: ScannedSourceFile[], options: NormalizedCheckCodeDisciplineOptions): Promise<CodeDisciplineViolation[]>;
|
|
4
|
+
export { runMaxFileLinesRule };
|
|
5
|
+
//# sourceMappingURL=max-file-lines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"max-file-lines.d.ts","sourceRoot":"","sources":["../../../src/checks/rules/max-file-lines.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,oCAAoC,EAAE,MAAM,aAAa,CAAC;AACjG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAOhE,iBAAe,mBAAmB,CAChC,WAAW,EAAE,iBAAiB,EAAE,EAChC,OAAO,EAAE,oCAAoC,GAC5C,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAwBpC;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
function countLines(text) {
|
|
3
|
+
if (text.length === 0)
|
|
4
|
+
return 0;
|
|
5
|
+
return text.split(/\r?\n/).length;
|
|
6
|
+
}
|
|
7
|
+
async function runMaxFileLinesRule(sourceFiles, options) {
|
|
8
|
+
if (!options.rules.maxFileLines.enabled)
|
|
9
|
+
return [];
|
|
10
|
+
const violations = [];
|
|
11
|
+
for (const file of sourceFiles) {
|
|
12
|
+
const text = await fs.readFile(file.absolutePath, "utf8");
|
|
13
|
+
const lineCount = countLines(text);
|
|
14
|
+
if (lineCount <= options.rules.maxFileLines.max)
|
|
15
|
+
continue;
|
|
16
|
+
violations.push({
|
|
17
|
+
rule: "max-file-lines",
|
|
18
|
+
severity: options.rules.maxFileLines.severity,
|
|
19
|
+
filePath: file.relativeFromProjectRoot,
|
|
20
|
+
message: `file has ${lineCount} lines and exceeds the limit of ${options.rules.maxFileLines.max}`,
|
|
21
|
+
details: {
|
|
22
|
+
lineCount,
|
|
23
|
+
max: options.rules.maxFileLines.max,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return violations;
|
|
28
|
+
}
|
|
29
|
+
export { runMaxFileLinesRule };
|
|
30
|
+
//# sourceMappingURL=max-file-lines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"max-file-lines.js","sourceRoot":"","sources":["../../../src/checks/rules/max-file-lines.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAKlC,SAAS,UAAU,CAAC,IAAY;IAC9B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAChC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;AACpC,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,WAAgC,EAChC,OAA6C;IAE7C,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IAEnD,MAAM,UAAU,GAA8B,EAAE,CAAC;IAEjD,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAC1D,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAEnC,IAAI,SAAS,IAAI,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG;YAAE,SAAS;QAE1D,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,gBAAgB;YACtB,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ;YAC7C,QAAQ,EAAE,IAAI,CAAC,uBAAuB;YACtC,OAAO,EAAE,YAAY,SAAS,mCAAmC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE;YACjG,OAAO,EAAE;gBACP,SAAS;gBACT,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG;aACpC;SACF,CAAC,CAAC;IACL,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { SourceScanOptions, SyncImportsOptions } from "../imports/types.js";
|
|
2
|
+
type CodeDisciplineRuleSeverity = "warn" | "error";
|
|
3
|
+
type SyncImportsRuleOptions = Omit<SyncImportsOptions, "projectRoot"> & {
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
};
|
|
6
|
+
type MaxFileLinesRuleOptions = {
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
max?: number;
|
|
9
|
+
severity?: CodeDisciplineRuleSeverity;
|
|
10
|
+
};
|
|
11
|
+
type FolderizeCompoundFilesRuleOptions = {
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
separators?: string[];
|
|
14
|
+
suffixes?: string[];
|
|
15
|
+
severity?: CodeDisciplineRuleSeverity;
|
|
16
|
+
};
|
|
17
|
+
type CodeDisciplineRules = {
|
|
18
|
+
maxFileLines?: MaxFileLinesRuleOptions;
|
|
19
|
+
folderizeCompoundFiles?: FolderizeCompoundFilesRuleOptions;
|
|
20
|
+
syncImports?: SyncImportsRuleOptions;
|
|
21
|
+
};
|
|
22
|
+
type CheckCodeDisciplineOptions = {
|
|
23
|
+
projectRoot: string;
|
|
24
|
+
sourceRoot?: string;
|
|
25
|
+
sourceExtensions?: string[];
|
|
26
|
+
excludeDirs?: string[];
|
|
27
|
+
rules?: CodeDisciplineRules;
|
|
28
|
+
};
|
|
29
|
+
type CodeDisciplineConfig = Omit<CheckCodeDisciplineOptions, "projectRoot">;
|
|
30
|
+
type NormalizedMaxFileLinesRule = {
|
|
31
|
+
enabled: boolean;
|
|
32
|
+
max: number;
|
|
33
|
+
severity: CodeDisciplineRuleSeverity;
|
|
34
|
+
};
|
|
35
|
+
type NormalizedFolderizeCompoundFilesRule = {
|
|
36
|
+
enabled: boolean;
|
|
37
|
+
separators: string[];
|
|
38
|
+
suffixes: string[];
|
|
39
|
+
severity: CodeDisciplineRuleSeverity;
|
|
40
|
+
};
|
|
41
|
+
type NormalizedCheckCodeDisciplineOptions = SourceScanOptions & {
|
|
42
|
+
sourceRootRelative: string;
|
|
43
|
+
rules: {
|
|
44
|
+
maxFileLines: NormalizedMaxFileLinesRule;
|
|
45
|
+
folderizeCompoundFiles: NormalizedFolderizeCompoundFilesRule;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
type CodeDisciplineRuleName = "max-file-lines" | "folderize-compound-files";
|
|
49
|
+
type CodeDisciplineViolation = {
|
|
50
|
+
rule: CodeDisciplineRuleName;
|
|
51
|
+
severity: CodeDisciplineRuleSeverity;
|
|
52
|
+
filePath: string;
|
|
53
|
+
message: string;
|
|
54
|
+
details: Record<string, unknown>;
|
|
55
|
+
suggestedPath?: string;
|
|
56
|
+
};
|
|
57
|
+
type CheckCodeDisciplineResult = {
|
|
58
|
+
ok: boolean;
|
|
59
|
+
warnings: number;
|
|
60
|
+
errors: number;
|
|
61
|
+
violations: CodeDisciplineViolation[];
|
|
62
|
+
};
|
|
63
|
+
export type { CheckCodeDisciplineOptions, CheckCodeDisciplineResult, CodeDisciplineConfig, CodeDisciplineRuleName, CodeDisciplineRuleSeverity, CodeDisciplineRules, CodeDisciplineViolation, FolderizeCompoundFilesRuleOptions, MaxFileLinesRuleOptions, NormalizedCheckCodeDisciplineOptions, NormalizedFolderizeCompoundFilesRule, NormalizedMaxFileLinesRule, SyncImportsRuleOptions, };
|
|
64
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/checks/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEjF,KAAK,0BAA0B,GAAG,MAAM,GAAG,OAAO,CAAC;AAEnD,KAAK,sBAAsB,GAAG,IAAI,CAAC,kBAAkB,EAAE,aAAa,CAAC,GAAG;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,KAAK,uBAAuB,GAAG;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,0BAA0B,CAAC;CACvC,CAAC;AAEF,KAAK,iCAAiC,GAAG;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,0BAA0B,CAAC;CACvC,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,YAAY,CAAC,EAAE,uBAAuB,CAAC;IACvC,sBAAsB,CAAC,EAAE,iCAAiC,CAAC;IAC3D,WAAW,CAAC,EAAE,sBAAsB,CAAC;CACtC,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,mBAAmB,CAAC;CAC7B,CAAC;AAEF,KAAK,oBAAoB,GAAG,IAAI,CAAC,0BAA0B,EAAE,aAAa,CAAC,CAAC;AAE5E,KAAK,0BAA0B,GAAG;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,0BAA0B,CAAC;CACtC,CAAC;AAEF,KAAK,oCAAoC,GAAG;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,0BAA0B,CAAC;CACtC,CAAC;AAEF,KAAK,oCAAoC,GAAG,iBAAiB,GAAG;IAC9D,kBAAkB,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE;QACL,YAAY,EAAE,0BAA0B,CAAC;QACzC,sBAAsB,EAAE,oCAAoC,CAAC;KAC9D,CAAC;CACH,CAAC;AAEF,KAAK,sBAAsB,GAAG,gBAAgB,GAAG,0BAA0B,CAAC;AAE5E,KAAK,uBAAuB,GAAG;IAC7B,IAAI,EAAE,sBAAsB,CAAC;IAC7B,QAAQ,EAAE,0BAA0B,CAAC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,uBAAuB,EAAE,CAAC;CACvC,CAAC;AAEF,YAAY,EACV,0BAA0B,EAC1B,yBAAyB,EACzB,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,mBAAmB,EACnB,uBAAuB,EACvB,iCAAiC,EACjC,uBAAuB,EACvB,oCAAoC,EACpC,oCAAoC,EACpC,0BAA0B,EAC1B,sBAAsB,GACvB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/checks/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
type CliRunOptions = {
|
|
3
|
+
cwd?: string;
|
|
4
|
+
stdout?: (text: string) => void;
|
|
5
|
+
stderr?: (text: string) => void;
|
|
6
|
+
};
|
|
7
|
+
type CliRunResult = {
|
|
8
|
+
exitCode: number;
|
|
9
|
+
};
|
|
10
|
+
declare function runCli(argv: string[], options?: CliRunOptions): Promise<CliRunResult>;
|
|
11
|
+
export { runCli };
|
|
12
|
+
export type { CliRunOptions, CliRunResult };
|
|
13
|
+
//# sourceMappingURL=run-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-cli.d.ts","sourceRoot":"","sources":["../../src/cli/run-cli.ts"],"names":[],"mappings":";AAUA,KAAK,aAAa,GAAG;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAyDF,iBAAe,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAuDxF;AAQD,OAAO,EAAE,MAAM,EAAE,CAAC;AAClB,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
import { checkCodeDiscipline } from "../checks/index.js";
|
|
4
|
+
import { loadCodeDisciplineConfig } from "../config/index.js";
|
|
5
|
+
import { syncImports } from "../imports/sync-imports.js";
|
|
6
|
+
function renderHelp() {
|
|
7
|
+
return [
|
|
8
|
+
"Usage: code-discipline <command> [--config <path>]",
|
|
9
|
+
"",
|
|
10
|
+
"Commands:",
|
|
11
|
+
" check run configured discipline checks",
|
|
12
|
+
" sync sync tsconfig aliases and rewrite imports",
|
|
13
|
+
"",
|
|
14
|
+
].join("\n");
|
|
15
|
+
}
|
|
16
|
+
function parseArgs(args) {
|
|
17
|
+
let configPath;
|
|
18
|
+
const extra = [];
|
|
19
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
20
|
+
const arg = args[index];
|
|
21
|
+
if (arg === "--config") {
|
|
22
|
+
const value = args[index + 1];
|
|
23
|
+
if (!value) {
|
|
24
|
+
throw new Error("Missing value for --config");
|
|
25
|
+
}
|
|
26
|
+
configPath = value;
|
|
27
|
+
index += 1;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
extra.push(arg);
|
|
31
|
+
}
|
|
32
|
+
return { configPath, extra };
|
|
33
|
+
}
|
|
34
|
+
function buildSyncImportsOptions(projectRoot, config) {
|
|
35
|
+
const { enabled: _enabled, ...syncRule } = config.rules?.syncImports ?? {};
|
|
36
|
+
return {
|
|
37
|
+
projectRoot,
|
|
38
|
+
sourceRoot: syncRule.sourceRoot ?? config.sourceRoot,
|
|
39
|
+
tsconfigPath: syncRule.tsconfigPath,
|
|
40
|
+
sourceExtensions: syncRule.sourceExtensions ?? config.sourceExtensions,
|
|
41
|
+
excludeDirs: syncRule.excludeDirs ?? config.excludeDirs,
|
|
42
|
+
alias: syncRule.alias,
|
|
43
|
+
imports: syncRule.imports,
|
|
44
|
+
logging: syncRule.logging,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function formatViolation(violation) {
|
|
48
|
+
const suggested = violation.suggestedPath ? ` suggested=${violation.suggestedPath}` : "";
|
|
49
|
+
return `${violation.severity.toUpperCase()} ${violation.rule} ${violation.filePath} ${violation.message}${suggested}`;
|
|
50
|
+
}
|
|
51
|
+
async function runCli(argv, options = {}) {
|
|
52
|
+
const cwd = options.cwd ?? process.cwd();
|
|
53
|
+
const stdout = options.stdout ?? ((text) => process.stdout.write(text));
|
|
54
|
+
const stderr = options.stderr ?? ((text) => process.stderr.write(text));
|
|
55
|
+
const [command, ...rest] = argv;
|
|
56
|
+
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
57
|
+
stdout(renderHelp());
|
|
58
|
+
return { exitCode: 0 };
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const parsed = parseArgs(rest);
|
|
62
|
+
if (parsed.extra.length > 0) {
|
|
63
|
+
throw new Error(`Unexpected arguments: ${parsed.extra.join(" ")}`);
|
|
64
|
+
}
|
|
65
|
+
const { config } = await loadCodeDisciplineConfig(cwd, parsed.configPath);
|
|
66
|
+
if (command === "check") {
|
|
67
|
+
const result = await checkCodeDiscipline({
|
|
68
|
+
projectRoot: cwd,
|
|
69
|
+
sourceRoot: config.sourceRoot,
|
|
70
|
+
sourceExtensions: config.sourceExtensions,
|
|
71
|
+
excludeDirs: config.excludeDirs,
|
|
72
|
+
rules: config.rules,
|
|
73
|
+
});
|
|
74
|
+
if (result.violations.length === 0) {
|
|
75
|
+
stdout("No discipline violations found.\n");
|
|
76
|
+
return { exitCode: 0 };
|
|
77
|
+
}
|
|
78
|
+
for (const violation of result.violations) {
|
|
79
|
+
stdout(`${formatViolation(violation)}\n`);
|
|
80
|
+
}
|
|
81
|
+
stdout(`Summary: ${result.errors} errors, ${result.warnings} warnings.\n`);
|
|
82
|
+
return { exitCode: result.ok ? 0 : 1 };
|
|
83
|
+
}
|
|
84
|
+
if (command === "sync") {
|
|
85
|
+
const result = await syncImports(buildSyncImportsOptions(cwd, config));
|
|
86
|
+
stdout(`${JSON.stringify(result)}\n`);
|
|
87
|
+
return { exitCode: 0 };
|
|
88
|
+
}
|
|
89
|
+
stderr(`Unknown command: ${command}\n`);
|
|
90
|
+
stderr(renderHelp());
|
|
91
|
+
return { exitCode: 1 };
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
stderr(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
95
|
+
return { exitCode: 1 };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const entryPath = process.argv[1] ? pathToFileURL(process.argv[1]).href : null;
|
|
99
|
+
if (entryPath && import.meta.url === entryPath) {
|
|
100
|
+
const result = await runCli(process.argv.slice(2));
|
|
101
|
+
process.exitCode = result.exitCode;
|
|
102
|
+
}
|
|
103
|
+
export { runCli };
|
|
104
|
+
//# sourceMappingURL=run-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-cli.js","sourceRoot":"","sources":["../../src/cli/run-cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAazD,SAAS,UAAU;IACjB,OAAO;QACL,oDAAoD;QACpD,EAAE;QACF,WAAW;QACX,kDAAkD;QAClD,2DAA2D;QAC3D,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,SAAS,SAAS,CAAC,IAAc;IAC/B,IAAI,UAA8B,CAAC;IACnC,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAExB,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAC9B,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAChD,CAAC;YAED,UAAU,GAAG,KAAK,CAAC;YACnB,KAAK,IAAI,CAAC,CAAC;YACX,SAAS;QACX,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAC/B,CAAC;AAED,SAAS,uBAAuB,CAAC,WAAmB,EAAE,MAA4B;IAChF,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE,WAAW,IAAI,EAAE,CAAC;IAE3E,OAAO;QACL,WAAW;QACX,UAAU,EAAE,QAAQ,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU;QACpD,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB,IAAI,MAAM,CAAC,gBAAgB;QACtE,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW;QACvD,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,OAAO,EAAE,QAAQ,CAAC,OAAO;KAC1B,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,SAAgF;IACvG,MAAM,SAAS,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,cAAc,SAAS,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACzF,OAAO,GAAG,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC,QAAQ,IAAI,SAAS,CAAC,OAAO,GAAG,SAAS,EAAE,CAAC;AACxH,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAc,EAAE,UAAyB,EAAE;IAC/D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACzC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAChF,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAEhC,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAC/E,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QACrB,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAE/B,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,yBAAyB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,wBAAwB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;QAE1E,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC;gBACvC,WAAW,EAAE,GAAG;gBAChB,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;gBACzC,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,KAAK,EAAE,MAAM,CAAC,KAAK;aACpB,CAAC,CAAC;YAEH,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACnC,MAAM,CAAC,mCAAmC,CAAC,CAAC;gBAC5C,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;YACzB,CAAC;YAED,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;gBAC1C,MAAM,CAAC,GAAG,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAC5C,CAAC;YAED,MAAM,CAAC,YAAY,MAAM,CAAC,MAAM,YAAY,MAAM,CAAC,QAAQ,cAAc,CAAC,CAAC;YAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,CAAC;QAED,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;YACvE,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACtC,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACzB,CAAC;QAED,MAAM,CAAC,oBAAoB,OAAO,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QACrB,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAED,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/E,IAAI,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;IAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AACrC,CAAC;AAED,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAQ1C,OAAO,EAAE,MAAM,EAAE,CAAC;AAClB,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
import { runCli } from "./cli/run-cli.js";
|
|
4
|
+
const entryPath = process.argv[1] ? pathToFileURL(process.argv[1]).href : null;
|
|
5
|
+
if (entryPath && import.meta.url === entryPath) {
|
|
6
|
+
const result = await runCli(process.argv.slice(2));
|
|
7
|
+
process.exitCode = result.exitCode;
|
|
8
|
+
}
|
|
9
|
+
export { runCli };
|
|
10
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/E,IAAI,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;IAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AACrC,CAAC;AAED,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CodeDisciplineConfig } from "../checks/types.js";
|
|
2
|
+
type LoadedCodeDisciplineConfig = {
|
|
3
|
+
config: CodeDisciplineConfig;
|
|
4
|
+
configPath: string | null;
|
|
5
|
+
};
|
|
6
|
+
declare function defineCodeDisciplineConfig(config: CodeDisciplineConfig): CodeDisciplineConfig;
|
|
7
|
+
declare function loadCodeDisciplineConfig(projectRoot: string, configPath?: string): Promise<LoadedCodeDisciplineConfig>;
|
|
8
|
+
export { defineCodeDisciplineConfig, loadCodeDisciplineConfig };
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAK/D,KAAK,0BAA0B,GAAG;IAChC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,iBAAS,0BAA0B,CAAC,MAAM,EAAE,oBAAoB,GAAG,oBAAoB,CAEtF;AAsBD,iBAAe,wBAAwB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAwBrH;AAED,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,CAAC"}
|