@standards-kit/conform 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/dist/artifactregistry-QQWBMEQN.js +38 -0
- package/dist/artifactregistry-QQWBMEQN.js.map +1 -0
- package/dist/chunk-J5S6GRGW.js +314 -0
- package/dist/chunk-J5S6GRGW.js.map +1 -0
- package/dist/chunk-KHO6NIAI.js +1367 -0
- package/dist/chunk-KHO6NIAI.js.map +1 -0
- package/dist/chunk-M7G73Q6P.js +662 -0
- package/dist/chunk-M7G73Q6P.js.map +1 -0
- package/dist/chunk-P7TIZJ4C.js +85 -0
- package/dist/chunk-P7TIZJ4C.js.map +1 -0
- package/dist/chunk-RXA4FO7L.js +279 -0
- package/dist/chunk-RXA4FO7L.js.map +1 -0
- package/dist/cli.js +7432 -0
- package/dist/cli.js.map +1 -0
- package/dist/cloudrun-O36R23SH.js +31 -0
- package/dist/cloudrun-O36R23SH.js.map +1 -0
- package/dist/cloudwatch-KSZ4A256.js +56 -0
- package/dist/cloudwatch-KSZ4A256.js.map +1 -0
- package/dist/dynamodb-5KVESCVJ.js +51 -0
- package/dist/dynamodb-5KVESCVJ.js.map +1 -0
- package/dist/ec2-HKPE6GZV.js +151 -0
- package/dist/ec2-HKPE6GZV.js.map +1 -0
- package/dist/ecs-OS3NJZTA.js +141 -0
- package/dist/ecs-OS3NJZTA.js.map +1 -0
- package/dist/elasticache-7TCRHYYM.js +151 -0
- package/dist/elasticache-7TCRHYYM.js.map +1 -0
- package/dist/elb-PEDLXW5R.js +151 -0
- package/dist/elb-PEDLXW5R.js.map +1 -0
- package/dist/generate-D4MFMOHP.js +28 -0
- package/dist/generate-D4MFMOHP.js.map +1 -0
- package/dist/iam-7H5HFWVQ.js +96 -0
- package/dist/iam-7H5HFWVQ.js.map +1 -0
- package/dist/iam-DJI64AGK.js +39 -0
- package/dist/iam-DJI64AGK.js.map +1 -0
- package/dist/index.js +7980 -0
- package/dist/index.js.map +1 -0
- package/dist/infra-UXM5XQX3.js +566 -0
- package/dist/infra-UXM5XQX3.js.map +1 -0
- package/dist/lambda-NFB5UILT.js +60 -0
- package/dist/lambda-NFB5UILT.js.map +1 -0
- package/dist/manifest-7AIL2FK2.js +23 -0
- package/dist/manifest-7AIL2FK2.js.map +1 -0
- package/dist/mcp-O5O7XVFG.js +204 -0
- package/dist/mcp-O5O7XVFG.js.map +1 -0
- package/dist/rds-KLG5O5SI.js +151 -0
- package/dist/rds-KLG5O5SI.js.map +1 -0
- package/dist/registry-V65CC7IN.js +15 -0
- package/dist/registry-V65CC7IN.js.map +1 -0
- package/dist/s3-2DH7PRVR.js +49 -0
- package/dist/s3-2DH7PRVR.js.map +1 -0
- package/dist/scan-EELS42BP.js +593 -0
- package/dist/scan-EELS42BP.js.map +1 -0
- package/dist/secretmanager-RDL62EFW.js +31 -0
- package/dist/secretmanager-RDL62EFW.js.map +1 -0
- package/dist/secretsmanager-MOOIHLAO.js +50 -0
- package/dist/secretsmanager-MOOIHLAO.js.map +1 -0
- package/dist/sns-Y36LVTWA.js +50 -0
- package/dist/sns-Y36LVTWA.js.map +1 -0
- package/dist/sqs-RRS3GRHK.js +61 -0
- package/dist/sqs-RRS3GRHK.js.map +1 -0
- package/dist/src-KZRTG3EU.js +45 -0
- package/dist/src-KZRTG3EU.js.map +1 -0
- package/dist/standards-RXK5G4IG.js +37 -0
- package/dist/standards-RXK5G4IG.js.map +1 -0
- package/dist/sync-RLYBGYNY.js +877 -0
- package/dist/sync-RLYBGYNY.js.map +1 -0
- package/dist/validate-AABLVQJS.js +327 -0
- package/dist/validate-AABLVQJS.js.map +1 -0
- package/dist/validator-6PL5I5EC.js +156 -0
- package/dist/validator-6PL5I5EC.js.map +1 -0
- package/package.json +91 -0
|
@@ -0,0 +1,1367 @@
|
|
|
1
|
+
// ../core/src/registry.ts
|
|
2
|
+
import * as fs2 from "fs";
|
|
3
|
+
import * as os from "os";
|
|
4
|
+
import * as path2 from "path";
|
|
5
|
+
import * as toml from "@iarna/toml";
|
|
6
|
+
import { execa } from "execa";
|
|
7
|
+
|
|
8
|
+
// ../core/src/loader.ts
|
|
9
|
+
import * as fs from "fs";
|
|
10
|
+
import * as path from "path";
|
|
11
|
+
import TOML from "@iarna/toml";
|
|
12
|
+
|
|
13
|
+
// ../core/src/schema.ts
|
|
14
|
+
import { minimatch } from "minimatch";
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
function countUnclosedDelimiters(pattern) {
|
|
17
|
+
let brackets = 0;
|
|
18
|
+
let braces = 0;
|
|
19
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
20
|
+
if (pattern[i] === "\\" && i + 1 < pattern.length) {
|
|
21
|
+
i++;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
switch (pattern[i]) {
|
|
25
|
+
case "[":
|
|
26
|
+
brackets++;
|
|
27
|
+
break;
|
|
28
|
+
case "]":
|
|
29
|
+
if (brackets > 0) {
|
|
30
|
+
brackets--;
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
case "{":
|
|
34
|
+
braces++;
|
|
35
|
+
break;
|
|
36
|
+
case "}":
|
|
37
|
+
if (braces > 0) {
|
|
38
|
+
braces--;
|
|
39
|
+
}
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return { brackets, braces };
|
|
44
|
+
}
|
|
45
|
+
function isValidGlobPattern(pattern) {
|
|
46
|
+
if (pattern.length === 0) {
|
|
47
|
+
return { valid: false, error: "empty pattern" };
|
|
48
|
+
}
|
|
49
|
+
const unclosed = countUnclosedDelimiters(pattern);
|
|
50
|
+
if (unclosed.brackets > 0) {
|
|
51
|
+
return { valid: false, error: "unclosed bracket '['" };
|
|
52
|
+
}
|
|
53
|
+
if (unclosed.braces > 0) {
|
|
54
|
+
return { valid: false, error: "unclosed brace '{'" };
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const result = minimatch.makeRe(pattern);
|
|
58
|
+
return result === false ? { valid: false, error: "invalid pattern syntax" } : { valid: true };
|
|
59
|
+
} catch (error) {
|
|
60
|
+
const message = error instanceof Error ? error.message : "Invalid glob pattern";
|
|
61
|
+
return { valid: false, error: message };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
var globPatternSchema = z.string().refine(
|
|
65
|
+
(pattern) => isValidGlobPattern(pattern).valid,
|
|
66
|
+
(pattern) => ({
|
|
67
|
+
message: `Invalid glob pattern: "${pattern}" - ${isValidGlobPattern(pattern).error}`
|
|
68
|
+
})
|
|
69
|
+
);
|
|
70
|
+
var eslintRuleSeverity = z.enum(["off", "warn", "error"]);
|
|
71
|
+
var eslintRuleWithOptions = z.object({
|
|
72
|
+
severity: eslintRuleSeverity
|
|
73
|
+
}).catchall(z.unknown());
|
|
74
|
+
var eslintRuleValue = z.union([eslintRuleSeverity, eslintRuleWithOptions]);
|
|
75
|
+
var eslintRulesSchema = z.record(z.string(), eslintRuleValue).optional();
|
|
76
|
+
var eslintConfigSchema = z.object({
|
|
77
|
+
enabled: z.boolean().optional().default(true),
|
|
78
|
+
files: z.array(z.string()).optional(),
|
|
79
|
+
// Glob patterns for files to lint
|
|
80
|
+
ignore: z.array(z.string()).optional(),
|
|
81
|
+
// Glob patterns to ignore
|
|
82
|
+
"max-warnings": z.number().int().nonnegative().optional(),
|
|
83
|
+
// Max warnings before failure
|
|
84
|
+
rules: eslintRulesSchema,
|
|
85
|
+
// Required rules for audit (verifies eslint.config.js)
|
|
86
|
+
dependencies: z.array(z.string()).optional()
|
|
87
|
+
// Custom dependency files for drift tracking
|
|
88
|
+
}).strict().optional();
|
|
89
|
+
var ruffLintSchema = z.object({
|
|
90
|
+
select: z.array(z.string()).optional(),
|
|
91
|
+
ignore: z.array(z.string()).optional()
|
|
92
|
+
}).strict().optional();
|
|
93
|
+
var ruffConfigSchema = z.object({
|
|
94
|
+
enabled: z.boolean().optional().default(true),
|
|
95
|
+
"line-length": z.number().int().positive().optional(),
|
|
96
|
+
lint: ruffLintSchema,
|
|
97
|
+
dependencies: z.array(z.string()).optional()
|
|
98
|
+
// Custom dependency files for drift tracking
|
|
99
|
+
}).strict().optional();
|
|
100
|
+
var tscCompilerOptionsSchema = z.object({
|
|
101
|
+
strict: z.boolean().optional(),
|
|
102
|
+
noImplicitAny: z.boolean().optional(),
|
|
103
|
+
strictNullChecks: z.boolean().optional(),
|
|
104
|
+
noUnusedLocals: z.boolean().optional(),
|
|
105
|
+
noUnusedParameters: z.boolean().optional(),
|
|
106
|
+
noImplicitReturns: z.boolean().optional(),
|
|
107
|
+
noFallthroughCasesInSwitch: z.boolean().optional(),
|
|
108
|
+
esModuleInterop: z.boolean().optional(),
|
|
109
|
+
skipLibCheck: z.boolean().optional(),
|
|
110
|
+
forceConsistentCasingInFileNames: z.boolean().optional()
|
|
111
|
+
}).strict().optional();
|
|
112
|
+
var tscConfigSchema = z.object({
|
|
113
|
+
enabled: z.boolean().optional().default(false),
|
|
114
|
+
require: tscCompilerOptionsSchema,
|
|
115
|
+
// Required compiler options for audit
|
|
116
|
+
dependencies: z.array(z.string()).optional()
|
|
117
|
+
// Custom dependency files for drift tracking
|
|
118
|
+
}).strict().optional();
|
|
119
|
+
var tyConfigSchema = z.object({
|
|
120
|
+
enabled: z.boolean().optional().default(false),
|
|
121
|
+
dependencies: z.array(z.string()).optional()
|
|
122
|
+
// Custom dependency files for drift tracking
|
|
123
|
+
}).strict().optional();
|
|
124
|
+
var knipConfigSchema = z.object({
|
|
125
|
+
enabled: z.boolean().optional().default(false),
|
|
126
|
+
dependencies: z.array(z.string()).optional()
|
|
127
|
+
// Custom dependency files for drift tracking
|
|
128
|
+
}).strict().optional();
|
|
129
|
+
var vultureConfigSchema = z.object({
|
|
130
|
+
enabled: z.boolean().optional().default(false),
|
|
131
|
+
dependencies: z.array(z.string()).optional()
|
|
132
|
+
// Custom dependency files for drift tracking
|
|
133
|
+
}).strict().optional();
|
|
134
|
+
var coverageRunnerSchema = z.enum(["vitest", "jest", "pytest", "auto"]);
|
|
135
|
+
var coverageRunConfigSchema = z.object({
|
|
136
|
+
enabled: z.boolean().optional().default(false),
|
|
137
|
+
min_threshold: z.number().int().min(0).max(100).optional().default(80),
|
|
138
|
+
// Minimum coverage percentage
|
|
139
|
+
runner: coverageRunnerSchema.optional().default("auto"),
|
|
140
|
+
// Test runner to use
|
|
141
|
+
command: z.string().optional(),
|
|
142
|
+
// Custom command to run tests with coverage
|
|
143
|
+
dependencies: z.array(z.string()).optional()
|
|
144
|
+
// Custom dependency files for drift tracking
|
|
145
|
+
}).strict().optional();
|
|
146
|
+
var secretsConfigSchema = z.object({
|
|
147
|
+
enabled: z.boolean().optional().default(false),
|
|
148
|
+
scan_mode: z.enum(["branch", "files", "staged", "full"]).optional().default("branch"),
|
|
149
|
+
// branch: scan current branch commits, files: scan filesystem, staged: staged files only, full: entire git history
|
|
150
|
+
base_branch: z.string().optional().default("main"),
|
|
151
|
+
// Branch to compare against for "branch" mode
|
|
152
|
+
dependencies: z.array(z.string()).optional()
|
|
153
|
+
// Custom dependency files for drift tracking
|
|
154
|
+
}).strict().optional();
|
|
155
|
+
var pnpmauditConfigSchema = z.object({
|
|
156
|
+
enabled: z.boolean().optional().default(false),
|
|
157
|
+
exclude_dev: z.boolean().optional().default(true),
|
|
158
|
+
dependencies: z.array(z.string()).optional()
|
|
159
|
+
// Custom dependency files for drift tracking
|
|
160
|
+
}).strict().optional();
|
|
161
|
+
var pipauditConfigSchema = z.object({
|
|
162
|
+
enabled: z.boolean().optional().default(false),
|
|
163
|
+
dependencies: z.array(z.string()).optional()
|
|
164
|
+
// Custom dependency files for drift tracking
|
|
165
|
+
}).strict().optional();
|
|
166
|
+
var codeSecuritySchema = z.object({
|
|
167
|
+
secrets: secretsConfigSchema,
|
|
168
|
+
pnpmaudit: pnpmauditConfigSchema,
|
|
169
|
+
pipaudit: pipauditConfigSchema
|
|
170
|
+
}).strict().optional();
|
|
171
|
+
var caseTypeSchema = z.enum(["kebab-case", "snake_case", "camelCase", "PascalCase"]);
|
|
172
|
+
var uniqueArraySchema = (schema) => z.array(schema).refine((arr) => new Set(arr).size === arr.length, {
|
|
173
|
+
message: "Duplicate values not allowed"
|
|
174
|
+
});
|
|
175
|
+
var uniqueArraySchemaMin1 = (schema) => z.array(schema).min(1, "At least one value is required").refine((arr) => new Set(arr).size === arr.length, {
|
|
176
|
+
message: "Duplicate values not allowed"
|
|
177
|
+
});
|
|
178
|
+
var namingRuleSchema = z.object({
|
|
179
|
+
extensions: uniqueArraySchemaMin1(z.string()),
|
|
180
|
+
// e.g., ["ts", "tsx"] - no duplicates allowed, at least one required
|
|
181
|
+
file_case: caseTypeSchema,
|
|
182
|
+
folder_case: caseTypeSchema,
|
|
183
|
+
exclude: z.array(z.string()).optional(),
|
|
184
|
+
// Glob patterns to exclude, e.g., ["tests/**"]
|
|
185
|
+
allow_dynamic_routes: z.boolean().optional()
|
|
186
|
+
// Allow Next.js/Remix dynamic route folders: [id], [...slug], (group)
|
|
187
|
+
}).strict();
|
|
188
|
+
var namingConfigSchema = z.object({
|
|
189
|
+
enabled: z.boolean().optional().default(false),
|
|
190
|
+
rules: z.array(namingRuleSchema).optional()
|
|
191
|
+
}).strict().superRefine((data, ctx) => {
|
|
192
|
+
if (!data.rules || data.rules.length <= 1) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const extensionToRuleIndex = /* @__PURE__ */ new Map();
|
|
196
|
+
for (let i = 0; i < data.rules.length; i++) {
|
|
197
|
+
for (const ext of data.rules[i].extensions) {
|
|
198
|
+
const existing = extensionToRuleIndex.get(ext);
|
|
199
|
+
if (existing !== void 0) {
|
|
200
|
+
ctx.addIssue({
|
|
201
|
+
code: z.ZodIssueCode.custom,
|
|
202
|
+
message: `Extension "${ext}" appears in multiple naming rules (rules ${existing + 1} and ${i + 1}). Each extension can only appear in one rule.`,
|
|
203
|
+
path: ["rules", i, "extensions"]
|
|
204
|
+
});
|
|
205
|
+
} else {
|
|
206
|
+
extensionToRuleIndex.set(ext, i);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}).optional();
|
|
211
|
+
var disableCommentsConfigSchema = z.object({
|
|
212
|
+
enabled: z.boolean().optional().default(false),
|
|
213
|
+
patterns: z.array(z.string()).optional(),
|
|
214
|
+
// Override default patterns
|
|
215
|
+
extensions: uniqueArraySchema(z.string()).optional(),
|
|
216
|
+
// File extensions to scan - no duplicates allowed
|
|
217
|
+
exclude: z.array(z.string()).optional()
|
|
218
|
+
// Glob patterns to exclude
|
|
219
|
+
}).strict().optional();
|
|
220
|
+
var codeQualitySchema = z.object({
|
|
221
|
+
"disable-comments": disableCommentsConfigSchema
|
|
222
|
+
}).strict().optional();
|
|
223
|
+
var codeLintingSchema = z.object({
|
|
224
|
+
eslint: eslintConfigSchema,
|
|
225
|
+
ruff: ruffConfigSchema
|
|
226
|
+
}).strict().optional();
|
|
227
|
+
var codeTypesSchema = z.object({
|
|
228
|
+
tsc: tscConfigSchema,
|
|
229
|
+
ty: tyConfigSchema
|
|
230
|
+
}).strict().optional();
|
|
231
|
+
var codeUnusedSchema = z.object({
|
|
232
|
+
knip: knipConfigSchema,
|
|
233
|
+
vulture: vultureConfigSchema
|
|
234
|
+
}).strict().optional();
|
|
235
|
+
var codeSchema = z.object({
|
|
236
|
+
linting: codeLintingSchema,
|
|
237
|
+
types: codeTypesSchema,
|
|
238
|
+
unused: codeUnusedSchema,
|
|
239
|
+
coverage_run: coverageRunConfigSchema,
|
|
240
|
+
security: codeSecuritySchema,
|
|
241
|
+
naming: namingConfigSchema,
|
|
242
|
+
quality: codeQualitySchema
|
|
243
|
+
}).strict().optional();
|
|
244
|
+
var hookCommandsSchema = z.record(z.string(), z.array(z.string())).optional();
|
|
245
|
+
var hooksConfigSchema = z.object({
|
|
246
|
+
enabled: z.boolean().optional().default(false),
|
|
247
|
+
require_husky: z.boolean().optional().default(true),
|
|
248
|
+
// Require .husky/ directory
|
|
249
|
+
require_hooks: z.array(z.string()).optional(),
|
|
250
|
+
// e.g., ["pre-commit", "pre-push"]
|
|
251
|
+
commands: hookCommandsSchema,
|
|
252
|
+
// e.g., { "pre-commit": ["lint-staged"] }
|
|
253
|
+
protected_branches: z.array(z.string()).optional()
|
|
254
|
+
// e.g., ["main", "master"] - verify pre-push prevents direct pushes
|
|
255
|
+
}).strict().optional();
|
|
256
|
+
var ciCommandsValueSchema = z.union([
|
|
257
|
+
z.array(z.string()),
|
|
258
|
+
// Workflow-level: ["cmd1", "cmd2"]
|
|
259
|
+
z.record(z.string(), z.array(z.string()))
|
|
260
|
+
// Job-level: { jobName: ["cmd1"] }
|
|
261
|
+
]);
|
|
262
|
+
var ciCommandsSchema = z.record(z.string(), ciCommandsValueSchema).optional();
|
|
263
|
+
var ciConfigSchema = z.object({
|
|
264
|
+
enabled: z.boolean().optional().default(false),
|
|
265
|
+
require_workflows: z.array(z.string()).optional(),
|
|
266
|
+
// e.g., ["ci.yml", "release.yml"]
|
|
267
|
+
jobs: z.record(z.string(), z.array(z.string())).optional(),
|
|
268
|
+
// e.g., { "ci.yml": ["test", "lint"] }
|
|
269
|
+
actions: z.record(z.string(), z.array(z.string())).optional(),
|
|
270
|
+
// e.g., { "ci.yml": ["actions/checkout"] }
|
|
271
|
+
commands: ciCommandsSchema
|
|
272
|
+
// e.g., { "ci.yml": ["conform code check"] } or { "ci.yml": { "test": ["npm test"] } }
|
|
273
|
+
}).strict().optional();
|
|
274
|
+
var branchesConfigSchema = z.object({
|
|
275
|
+
enabled: z.boolean().optional().default(false),
|
|
276
|
+
pattern: z.string().optional(),
|
|
277
|
+
// Regex pattern for branch names
|
|
278
|
+
exclude: z.array(z.string()).optional(),
|
|
279
|
+
// Branches to skip (e.g., ["main", "master"])
|
|
280
|
+
require_issue: z.boolean().optional().default(false),
|
|
281
|
+
// Require issue number in branch name
|
|
282
|
+
issue_pattern: z.string().optional()
|
|
283
|
+
// Regex to extract issue number (default: captures number after type/)
|
|
284
|
+
}).strict().optional();
|
|
285
|
+
var commitsConfigSchema = z.object({
|
|
286
|
+
enabled: z.boolean().optional().default(false),
|
|
287
|
+
pattern: z.string().optional(),
|
|
288
|
+
// Regex pattern for commit messages (e.g., conventional commits)
|
|
289
|
+
types: z.array(z.string()).optional(),
|
|
290
|
+
// Allowed commit types (e.g., ["feat", "fix", "chore"])
|
|
291
|
+
require_scope: z.boolean().optional().default(false),
|
|
292
|
+
// Require scope like feat(api): ...
|
|
293
|
+
max_subject_length: z.number().int().positive().optional()
|
|
294
|
+
// Max length of subject line
|
|
295
|
+
}).strict().optional();
|
|
296
|
+
var changesetBumpTypeSchema = z.enum(["patch", "minor", "major"]);
|
|
297
|
+
var changesetsConfigSchema = z.object({
|
|
298
|
+
enabled: z.boolean().optional().default(false),
|
|
299
|
+
require_for_paths: z.array(z.string()).optional(),
|
|
300
|
+
// Glob patterns that require changesets (e.g., ["src/**"])
|
|
301
|
+
exclude_paths: z.array(z.string()).optional(),
|
|
302
|
+
// Paths that don't require changesets (e.g., ["**/*.test.ts"])
|
|
303
|
+
validate_format: z.boolean().optional().default(true),
|
|
304
|
+
// Validate changeset file format (frontmatter, description)
|
|
305
|
+
allowed_bump_types: z.array(changesetBumpTypeSchema).optional(),
|
|
306
|
+
// Restrict allowed bump types (e.g., ["patch", "minor"])
|
|
307
|
+
require_description: z.boolean().optional().default(true),
|
|
308
|
+
// Require non-empty description
|
|
309
|
+
min_description_length: z.number().int().positive().optional()
|
|
310
|
+
// Minimum description length
|
|
311
|
+
}).strict().optional();
|
|
312
|
+
var prConfigSchema = z.object({
|
|
313
|
+
enabled: z.boolean().optional().default(false),
|
|
314
|
+
max_files: z.number().int().positive().optional(),
|
|
315
|
+
// Max files changed in PR
|
|
316
|
+
max_lines: z.number().int().positive().optional(),
|
|
317
|
+
// Max lines changed (additions + deletions)
|
|
318
|
+
require_issue: z.boolean().optional().default(false),
|
|
319
|
+
// Require issue reference in PR description
|
|
320
|
+
issue_keywords: z.array(z.string()).optional(),
|
|
321
|
+
// Keywords that link to issues (e.g., ["Closes", "Fixes", "Resolves"])
|
|
322
|
+
exclude: z.array(globPatternSchema).optional()
|
|
323
|
+
// Glob patterns to exclude from size calculation (e.g., ["*.lock", "**/*.snap"])
|
|
324
|
+
}).strict().optional();
|
|
325
|
+
var ticketsConfigSchema = z.object({
|
|
326
|
+
enabled: z.boolean().optional().default(false),
|
|
327
|
+
pattern: z.string().optional(),
|
|
328
|
+
// Regex pattern for ticket IDs (e.g., "^(ABC|XYZ)-[0-9]+")
|
|
329
|
+
require_in_commits: z.boolean().optional().default(true),
|
|
330
|
+
// Require ticket in commit messages
|
|
331
|
+
require_in_branch: z.boolean().optional().default(false)
|
|
332
|
+
// Require ticket in branch name
|
|
333
|
+
}).strict().optional();
|
|
334
|
+
var coverageEnforceInSchema = z.enum(["ci", "config", "both"]);
|
|
335
|
+
var coverageConfigSchema = z.object({
|
|
336
|
+
enabled: z.boolean().optional().default(false),
|
|
337
|
+
min_threshold: z.number().int().min(0).max(100).optional(),
|
|
338
|
+
// Minimum coverage percentage
|
|
339
|
+
enforce_in: coverageEnforceInSchema.optional().default("config"),
|
|
340
|
+
// Where to verify coverage
|
|
341
|
+
ci_workflow: z.string().optional(),
|
|
342
|
+
// Workflow file to check (e.g., "ci.yml")
|
|
343
|
+
ci_job: z.string().optional()
|
|
344
|
+
// Job name to check (e.g., "test")
|
|
345
|
+
}).strict().optional();
|
|
346
|
+
var bypassActorTypeSchema = z.enum([
|
|
347
|
+
"Integration",
|
|
348
|
+
// GitHub App
|
|
349
|
+
"OrganizationAdmin",
|
|
350
|
+
// Org admin role
|
|
351
|
+
"RepositoryRole",
|
|
352
|
+
// Repository role (1=read, 2=triage, 3=write, 4=maintain, 5=admin)
|
|
353
|
+
"Team",
|
|
354
|
+
// GitHub team
|
|
355
|
+
"DeployKey"
|
|
356
|
+
// Deploy key
|
|
357
|
+
]);
|
|
358
|
+
var bypassModeSchema = z.enum([
|
|
359
|
+
"always",
|
|
360
|
+
// Can always bypass
|
|
361
|
+
"pull_request"
|
|
362
|
+
// Can bypass only via pull request
|
|
363
|
+
]);
|
|
364
|
+
var bypassActorSchema = z.object({
|
|
365
|
+
actor_type: bypassActorTypeSchema,
|
|
366
|
+
actor_id: z.number().int().positive().optional(),
|
|
367
|
+
// Actor ID (required except for DeployKey)
|
|
368
|
+
bypass_mode: bypassModeSchema.optional().default("always")
|
|
369
|
+
}).strict();
|
|
370
|
+
var rulesetConfigSchema = z.object({
|
|
371
|
+
name: z.string().optional().default("Branch Protection"),
|
|
372
|
+
// Ruleset name in GitHub
|
|
373
|
+
branch: z.string().optional().default("main"),
|
|
374
|
+
// Branch to check (default: main)
|
|
375
|
+
enforcement: z.enum(["active", "evaluate", "disabled"]).optional().default("active"),
|
|
376
|
+
// Ruleset enforcement
|
|
377
|
+
required_reviews: z.number().int().min(0).optional(),
|
|
378
|
+
// Minimum required reviews
|
|
379
|
+
dismiss_stale_reviews: z.boolean().optional(),
|
|
380
|
+
// Dismiss stale reviews on new commits
|
|
381
|
+
require_code_owner_reviews: z.boolean().optional(),
|
|
382
|
+
// Require CODEOWNER review
|
|
383
|
+
require_status_checks: z.array(z.string()).optional(),
|
|
384
|
+
// Required status checks
|
|
385
|
+
require_branches_up_to_date: z.boolean().optional(),
|
|
386
|
+
// Require branch to be up to date
|
|
387
|
+
require_signed_commits: z.boolean().optional(),
|
|
388
|
+
// Require signed commits
|
|
389
|
+
enforce_admins: z.boolean().optional(),
|
|
390
|
+
// Enforce rules for admins (no bypass actors when true)
|
|
391
|
+
bypass_actors: z.array(bypassActorSchema).optional()
|
|
392
|
+
// Actors that can bypass rules
|
|
393
|
+
}).strict().optional();
|
|
394
|
+
var tagProtectionConfigSchema = z.object({
|
|
395
|
+
patterns: z.array(z.string()).optional(),
|
|
396
|
+
// Tag patterns to protect (e.g., ["v*"])
|
|
397
|
+
prevent_deletion: z.boolean().optional().default(true),
|
|
398
|
+
// Prevent tag deletion
|
|
399
|
+
prevent_update: z.boolean().optional().default(true)
|
|
400
|
+
// Prevent tag updates (force-push)
|
|
401
|
+
}).strict().optional();
|
|
402
|
+
var repoConfigSchema = z.object({
|
|
403
|
+
enabled: z.boolean().optional().default(false),
|
|
404
|
+
require_branch_protection: z.boolean().optional().default(false),
|
|
405
|
+
// Check branch protection exists
|
|
406
|
+
require_codeowners: z.boolean().optional().default(false),
|
|
407
|
+
// Check CODEOWNERS file exists
|
|
408
|
+
ruleset: rulesetConfigSchema,
|
|
409
|
+
// GitHub Ruleset configuration
|
|
410
|
+
tag_protection: tagProtectionConfigSchema
|
|
411
|
+
// Tag protection via GitHub rulesets
|
|
412
|
+
}).strict().optional();
|
|
413
|
+
var backupsConfigSchema = z.object({
|
|
414
|
+
enabled: z.boolean().optional().default(false),
|
|
415
|
+
bucket: z.string().optional(),
|
|
416
|
+
// S3 bucket name
|
|
417
|
+
prefix: z.string().optional(),
|
|
418
|
+
// S3 key prefix
|
|
419
|
+
max_age_hours: z.number().int().positive().optional().default(24),
|
|
420
|
+
// Max age of most recent backup
|
|
421
|
+
region: z.string().optional()
|
|
422
|
+
// AWS region (defaults to AWS_REGION env)
|
|
423
|
+
}).strict().optional();
|
|
424
|
+
var codeownersRuleSchema = z.object({
|
|
425
|
+
pattern: z.string(),
|
|
426
|
+
// File pattern (e.g., "/standards.toml", "*.js", "/src/api/*")
|
|
427
|
+
owners: z.array(z.string())
|
|
428
|
+
// Owner handles (e.g., ["@user", "@org/team"])
|
|
429
|
+
}).strict();
|
|
430
|
+
var codeownersConfigSchema = z.object({
|
|
431
|
+
enabled: z.boolean().optional().default(false),
|
|
432
|
+
rules: z.array(codeownersRuleSchema).optional()
|
|
433
|
+
// Required rules in CODEOWNERS
|
|
434
|
+
}).strict().optional();
|
|
435
|
+
var docsTypeConfigSchema = z.object({
|
|
436
|
+
required_sections: z.array(z.string()).optional(),
|
|
437
|
+
// e.g., ["Overview", "Parameters", "Returns", "Examples"]
|
|
438
|
+
frontmatter: z.array(z.string()).optional()
|
|
439
|
+
// e.g., ["title", "tracks"]
|
|
440
|
+
}).strict();
|
|
441
|
+
var docsEnforcementSchema = z.enum(["block", "warn"]);
|
|
442
|
+
var docsConfigSchema = z.object({
|
|
443
|
+
enabled: z.boolean().optional().default(false),
|
|
444
|
+
path: z.string().optional().default("docs/"),
|
|
445
|
+
// Documentation directory
|
|
446
|
+
enforcement: docsEnforcementSchema.optional().default("warn"),
|
|
447
|
+
// "block" or "warn"
|
|
448
|
+
allowlist: z.array(z.string()).optional(),
|
|
449
|
+
// Markdown files allowed outside docs/, e.g., ["README.md", "CLAUDE.md"]
|
|
450
|
+
max_files: z.number().int().positive().optional(),
|
|
451
|
+
// Max markdown files in docs/
|
|
452
|
+
max_file_lines: z.number().int().positive().optional(),
|
|
453
|
+
// Max lines per markdown file
|
|
454
|
+
max_total_kb: z.number().int().positive().optional(),
|
|
455
|
+
// Max total size of docs/
|
|
456
|
+
staleness_days: z.number().int().positive().optional().default(30),
|
|
457
|
+
// Days before doc is considered stale
|
|
458
|
+
stale_mappings: z.record(z.string(), z.string()).optional(),
|
|
459
|
+
// Override doc-to-source mappings
|
|
460
|
+
min_coverage: z.number().int().min(0).max(100).optional(),
|
|
461
|
+
// Minimum API coverage percentage
|
|
462
|
+
coverage_paths: z.array(z.string()).optional(),
|
|
463
|
+
// Glob patterns for source files, e.g., ["src/**/*.ts"]
|
|
464
|
+
exclude_patterns: z.array(z.string()).optional(),
|
|
465
|
+
// Exclude from coverage, e.g., ["**/*.test.ts"]
|
|
466
|
+
types: z.record(z.string(), docsTypeConfigSchema).optional()
|
|
467
|
+
// Per-type config, e.g., { api: {...}, guide: {...} }
|
|
468
|
+
}).strict().optional();
|
|
469
|
+
var mcpStandardsSchema = z.object({
|
|
470
|
+
source: z.string().optional().describe(
|
|
471
|
+
'Standards repository source: "github:owner/repo", "github:owner/repo@ref", or local path'
|
|
472
|
+
)
|
|
473
|
+
}).strict().optional();
|
|
474
|
+
var mcpSchema = z.object({
|
|
475
|
+
standards: mcpStandardsSchema
|
|
476
|
+
}).strict().optional();
|
|
477
|
+
var infraSchema = z.object({
|
|
478
|
+
enabled: z.boolean().optional().default(false),
|
|
479
|
+
manifest: z.string().optional().default("infra-manifest.json")
|
|
480
|
+
// Path to manifest file
|
|
481
|
+
}).strict().optional();
|
|
482
|
+
var DEFAULT_FORBIDDEN_FILES_IGNORE = ["**/node_modules/**", "**/.git/**"];
|
|
483
|
+
var forbiddenFilesConfigSchema = z.object({
|
|
484
|
+
enabled: z.boolean().optional().default(false),
|
|
485
|
+
files: z.array(globPatternSchema).optional(),
|
|
486
|
+
// Glob patterns for files that must not exist (validated)
|
|
487
|
+
ignore: z.array(globPatternSchema).optional(),
|
|
488
|
+
// Glob patterns to ignore (validated, overrides defaults if provided)
|
|
489
|
+
message: z.string().optional()
|
|
490
|
+
// Custom message explaining why these files are forbidden
|
|
491
|
+
}).strict().optional();
|
|
492
|
+
var processSchema = z.object({
|
|
493
|
+
hooks: hooksConfigSchema,
|
|
494
|
+
ci: ciConfigSchema,
|
|
495
|
+
branches: branchesConfigSchema,
|
|
496
|
+
commits: commitsConfigSchema,
|
|
497
|
+
changesets: changesetsConfigSchema,
|
|
498
|
+
pr: prConfigSchema,
|
|
499
|
+
tickets: ticketsConfigSchema,
|
|
500
|
+
coverage: coverageConfigSchema,
|
|
501
|
+
repo: repoConfigSchema,
|
|
502
|
+
backups: backupsConfigSchema,
|
|
503
|
+
codeowners: codeownersConfigSchema,
|
|
504
|
+
docs: docsConfigSchema,
|
|
505
|
+
forbidden_files: forbiddenFilesConfigSchema
|
|
506
|
+
}).strict().optional();
|
|
507
|
+
var extendsSchema = z.object({
|
|
508
|
+
registry: z.string(),
|
|
509
|
+
// e.g., "github:myorg/standards" or local path
|
|
510
|
+
rulesets: z.array(z.string())
|
|
511
|
+
// e.g., ["base", "typescript"]
|
|
512
|
+
}).strict().optional();
|
|
513
|
+
var monorepoSchema = z.object({
|
|
514
|
+
exclude: z.array(globPatternSchema).optional()
|
|
515
|
+
// Glob patterns to exclude from project detection
|
|
516
|
+
}).strict().optional();
|
|
517
|
+
var configSchema = z.object({
|
|
518
|
+
extends: extendsSchema,
|
|
519
|
+
code: codeSchema,
|
|
520
|
+
process: processSchema,
|
|
521
|
+
infra: infraSchema,
|
|
522
|
+
mcp: mcpSchema,
|
|
523
|
+
monorepo: monorepoSchema
|
|
524
|
+
}).strict();
|
|
525
|
+
var defaultConfig = {
|
|
526
|
+
code: {
|
|
527
|
+
linting: {
|
|
528
|
+
eslint: { enabled: false },
|
|
529
|
+
ruff: { enabled: false }
|
|
530
|
+
},
|
|
531
|
+
types: {
|
|
532
|
+
tsc: { enabled: false },
|
|
533
|
+
ty: { enabled: false }
|
|
534
|
+
},
|
|
535
|
+
unused: {
|
|
536
|
+
knip: { enabled: false },
|
|
537
|
+
vulture: { enabled: false }
|
|
538
|
+
},
|
|
539
|
+
coverage_run: {
|
|
540
|
+
enabled: false,
|
|
541
|
+
min_threshold: 80,
|
|
542
|
+
runner: "auto"
|
|
543
|
+
},
|
|
544
|
+
security: {
|
|
545
|
+
secrets: { enabled: false, scan_mode: "branch", base_branch: "main" },
|
|
546
|
+
pnpmaudit: { enabled: false, exclude_dev: true },
|
|
547
|
+
pipaudit: { enabled: false }
|
|
548
|
+
},
|
|
549
|
+
naming: {
|
|
550
|
+
enabled: false
|
|
551
|
+
},
|
|
552
|
+
quality: {
|
|
553
|
+
"disable-comments": { enabled: false }
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
monorepo: {},
|
|
557
|
+
process: {
|
|
558
|
+
hooks: {
|
|
559
|
+
enabled: false,
|
|
560
|
+
require_husky: true
|
|
561
|
+
},
|
|
562
|
+
ci: {
|
|
563
|
+
enabled: false
|
|
564
|
+
},
|
|
565
|
+
branches: {
|
|
566
|
+
enabled: false,
|
|
567
|
+
require_issue: false
|
|
568
|
+
},
|
|
569
|
+
commits: {
|
|
570
|
+
enabled: false,
|
|
571
|
+
require_scope: false
|
|
572
|
+
},
|
|
573
|
+
changesets: {
|
|
574
|
+
enabled: false,
|
|
575
|
+
validate_format: true,
|
|
576
|
+
require_description: true
|
|
577
|
+
},
|
|
578
|
+
pr: {
|
|
579
|
+
enabled: false,
|
|
580
|
+
require_issue: false
|
|
581
|
+
},
|
|
582
|
+
tickets: {
|
|
583
|
+
enabled: false,
|
|
584
|
+
require_in_commits: true,
|
|
585
|
+
require_in_branch: false
|
|
586
|
+
},
|
|
587
|
+
coverage: {
|
|
588
|
+
enabled: false,
|
|
589
|
+
enforce_in: "config"
|
|
590
|
+
},
|
|
591
|
+
repo: {
|
|
592
|
+
enabled: false,
|
|
593
|
+
require_branch_protection: false,
|
|
594
|
+
require_codeowners: false
|
|
595
|
+
},
|
|
596
|
+
backups: {
|
|
597
|
+
enabled: false,
|
|
598
|
+
max_age_hours: 24
|
|
599
|
+
},
|
|
600
|
+
codeowners: {
|
|
601
|
+
enabled: false
|
|
602
|
+
},
|
|
603
|
+
docs: {
|
|
604
|
+
enabled: false,
|
|
605
|
+
path: "docs/",
|
|
606
|
+
enforcement: "warn",
|
|
607
|
+
staleness_days: 30
|
|
608
|
+
},
|
|
609
|
+
forbidden_files: {
|
|
610
|
+
enabled: false
|
|
611
|
+
}
|
|
612
|
+
},
|
|
613
|
+
infra: {
|
|
614
|
+
enabled: false,
|
|
615
|
+
manifest: "infra-manifest.json"
|
|
616
|
+
},
|
|
617
|
+
mcp: {
|
|
618
|
+
standards: {
|
|
619
|
+
source: void 0
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
// ../core/src/loader.ts
|
|
625
|
+
var CONFIG_FILE_NAME = "standards.toml";
|
|
626
|
+
var ConfigError = class extends Error {
|
|
627
|
+
constructor(message) {
|
|
628
|
+
super(message);
|
|
629
|
+
this.name = "ConfigError";
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
function isBrokenSymlink(filePath) {
|
|
633
|
+
try {
|
|
634
|
+
const stats = fs.lstatSync(filePath);
|
|
635
|
+
if (stats.isSymbolicLink()) {
|
|
636
|
+
try {
|
|
637
|
+
fs.statSync(filePath);
|
|
638
|
+
return false;
|
|
639
|
+
} catch {
|
|
640
|
+
return true;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
return false;
|
|
644
|
+
} catch {
|
|
645
|
+
return false;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
function findConfigFile(startDir = process.cwd()) {
|
|
649
|
+
let currentDir = path.resolve(startDir);
|
|
650
|
+
const root = path.parse(currentDir).root;
|
|
651
|
+
while (currentDir !== root) {
|
|
652
|
+
const configPath = path.join(currentDir, CONFIG_FILE_NAME);
|
|
653
|
+
if (isBrokenSymlink(configPath)) {
|
|
654
|
+
throw new ConfigError(`${CONFIG_FILE_NAME} exists but is a broken symlink: ${configPath}`);
|
|
655
|
+
}
|
|
656
|
+
if (fs.existsSync(configPath)) {
|
|
657
|
+
return configPath;
|
|
658
|
+
}
|
|
659
|
+
currentDir = path.dirname(currentDir);
|
|
660
|
+
}
|
|
661
|
+
const rootConfig = path.join(root, CONFIG_FILE_NAME);
|
|
662
|
+
if (isBrokenSymlink(rootConfig)) {
|
|
663
|
+
throw new ConfigError(`${CONFIG_FILE_NAME} exists but is a broken symlink: ${rootConfig}`);
|
|
664
|
+
}
|
|
665
|
+
return fs.existsSync(rootConfig) ? rootConfig : null;
|
|
666
|
+
}
|
|
667
|
+
function resolveConfigPath(configPath) {
|
|
668
|
+
const resolved = configPath ?? findConfigFile();
|
|
669
|
+
if (!resolved) {
|
|
670
|
+
throw new ConfigError(`No ${CONFIG_FILE_NAME} found. Create one or specify --config path.`);
|
|
671
|
+
}
|
|
672
|
+
const absolutePath = path.resolve(resolved);
|
|
673
|
+
if (!fs.existsSync(absolutePath)) {
|
|
674
|
+
throw new ConfigError(`Config file not found: ${resolved}`);
|
|
675
|
+
}
|
|
676
|
+
return absolutePath;
|
|
677
|
+
}
|
|
678
|
+
function parseTomlFile(filePath) {
|
|
679
|
+
try {
|
|
680
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
681
|
+
return TOML.parse(content);
|
|
682
|
+
} catch (error) {
|
|
683
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
684
|
+
throw new ConfigError(`Failed to parse ${CONFIG_FILE_NAME}: ${message}`);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
function validateConfig(rawConfig) {
|
|
688
|
+
const result = configSchema.safeParse(rawConfig);
|
|
689
|
+
if (!result.success) {
|
|
690
|
+
const errors = result.error.errors.map((e) => ` - ${e.path.join(".")}: ${e.message}`).join("\n");
|
|
691
|
+
throw new ConfigError(`Invalid ${CONFIG_FILE_NAME} configuration:
|
|
692
|
+
${errors}`);
|
|
693
|
+
}
|
|
694
|
+
return result.data;
|
|
695
|
+
}
|
|
696
|
+
function loadConfig(configPath) {
|
|
697
|
+
const resolvedPath = resolveConfigPath(configPath);
|
|
698
|
+
const rawConfig = parseTomlFile(resolvedPath);
|
|
699
|
+
const validatedConfig = validateConfig(rawConfig);
|
|
700
|
+
const config = mergeWithDefaults(validatedConfig);
|
|
701
|
+
return { config, configPath: resolvedPath };
|
|
702
|
+
}
|
|
703
|
+
async function loadConfigAsync(configPath) {
|
|
704
|
+
const resolvedPath = resolveConfigPath(configPath);
|
|
705
|
+
const rawConfig = parseTomlFile(resolvedPath);
|
|
706
|
+
const validatedConfig = validateConfig(rawConfig);
|
|
707
|
+
const configDir = path.dirname(resolvedPath);
|
|
708
|
+
const resolvedConfig = await resolveExtends(validatedConfig, configDir);
|
|
709
|
+
const config = mergeWithDefaults(resolvedConfig);
|
|
710
|
+
return { config, configPath: resolvedPath };
|
|
711
|
+
}
|
|
712
|
+
function merge(a, b) {
|
|
713
|
+
return { ...a, ...b };
|
|
714
|
+
}
|
|
715
|
+
function mergeLinting(c, dc) {
|
|
716
|
+
const cl = c.code?.linting;
|
|
717
|
+
const dl = dc.code?.linting;
|
|
718
|
+
return { eslint: merge(dl?.eslint, cl?.eslint), ruff: merge(dl?.ruff, cl?.ruff) };
|
|
719
|
+
}
|
|
720
|
+
function mergeSecurity(c, dc) {
|
|
721
|
+
const cs = c.code?.security;
|
|
722
|
+
const ds = dc.code?.security;
|
|
723
|
+
return {
|
|
724
|
+
secrets: merge(ds?.secrets, cs?.secrets),
|
|
725
|
+
pnpmaudit: merge(ds?.pnpmaudit, cs?.pnpmaudit),
|
|
726
|
+
pipaudit: merge(ds?.pipaudit, cs?.pipaudit)
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
function mergeTypes(c, dc) {
|
|
730
|
+
return {
|
|
731
|
+
tsc: merge(dc.code?.types?.tsc, c.code?.types?.tsc),
|
|
732
|
+
ty: merge(dc.code?.types?.ty, c.code?.types?.ty)
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
function mergeUnused(c, dc) {
|
|
736
|
+
return {
|
|
737
|
+
knip: merge(dc.code?.unused?.knip, c.code?.unused?.knip),
|
|
738
|
+
vulture: merge(dc.code?.unused?.vulture, c.code?.unused?.vulture)
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
function mergeCoverageRun(c, dc) {
|
|
742
|
+
return merge(dc.code?.coverage_run, c.code?.coverage_run);
|
|
743
|
+
}
|
|
744
|
+
function mergeNaming(c, dc) {
|
|
745
|
+
const cn = c.code?.naming;
|
|
746
|
+
const dn = dc.code?.naming;
|
|
747
|
+
return {
|
|
748
|
+
enabled: cn?.enabled ?? dn?.enabled ?? false,
|
|
749
|
+
rules: cn?.rules ?? dn?.rules
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
function mergeQuality(c, dc) {
|
|
753
|
+
const cq = c.code?.quality;
|
|
754
|
+
const dq = dc.code?.quality;
|
|
755
|
+
return {
|
|
756
|
+
"disable-comments": merge(dq?.["disable-comments"], cq?.["disable-comments"])
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
function mergeCode(c, dc) {
|
|
760
|
+
return {
|
|
761
|
+
linting: mergeLinting(c, dc),
|
|
762
|
+
types: mergeTypes(c, dc),
|
|
763
|
+
unused: mergeUnused(c, dc),
|
|
764
|
+
coverage_run: mergeCoverageRun(c, dc),
|
|
765
|
+
security: mergeSecurity(c, dc),
|
|
766
|
+
naming: mergeNaming(c, dc),
|
|
767
|
+
quality: mergeQuality(c, dc)
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
var defaultHooks = { enabled: false, require_husky: true };
|
|
771
|
+
var defaultCi = { enabled: false };
|
|
772
|
+
var defaultBranches = { enabled: false, require_issue: false };
|
|
773
|
+
var defaultCommits = { enabled: false, require_scope: false };
|
|
774
|
+
var defaultChangesets = {
|
|
775
|
+
enabled: false,
|
|
776
|
+
validate_format: true,
|
|
777
|
+
require_description: true
|
|
778
|
+
};
|
|
779
|
+
var defaultPr = { enabled: false, require_issue: false };
|
|
780
|
+
var defaultTickets = {
|
|
781
|
+
enabled: false,
|
|
782
|
+
require_in_commits: true,
|
|
783
|
+
require_in_branch: false
|
|
784
|
+
};
|
|
785
|
+
var defaultCoverage = { enabled: false, enforce_in: "config" };
|
|
786
|
+
var defaultRepo = {
|
|
787
|
+
enabled: false,
|
|
788
|
+
require_branch_protection: false,
|
|
789
|
+
require_codeowners: false
|
|
790
|
+
};
|
|
791
|
+
var defaultBackups = { enabled: false, max_age_hours: 24 };
|
|
792
|
+
var defaultCodeowners = { enabled: false };
|
|
793
|
+
var defaultDocs = {
|
|
794
|
+
enabled: false,
|
|
795
|
+
path: "docs/",
|
|
796
|
+
enforcement: "warn",
|
|
797
|
+
staleness_days: 30
|
|
798
|
+
};
|
|
799
|
+
var defaultForbiddenFiles = { enabled: false };
|
|
800
|
+
function mergeProcessSection(defaultVal, dcVal, cVal) {
|
|
801
|
+
return { ...defaultVal, ...dcVal, ...cVal };
|
|
802
|
+
}
|
|
803
|
+
function mergeProcessHooks(cp, dcp) {
|
|
804
|
+
return mergeProcessSection(defaultHooks, dcp?.hooks, cp?.hooks);
|
|
805
|
+
}
|
|
806
|
+
function mergeProcessCi(cp, dcp) {
|
|
807
|
+
return mergeProcessSection(defaultCi, dcp?.ci, cp?.ci);
|
|
808
|
+
}
|
|
809
|
+
function mergeProcessBranches(cp, dcp) {
|
|
810
|
+
return mergeProcessSection(defaultBranches, dcp?.branches, cp?.branches);
|
|
811
|
+
}
|
|
812
|
+
function mergeProcessCommits(cp, dcp) {
|
|
813
|
+
return mergeProcessSection(defaultCommits, dcp?.commits, cp?.commits);
|
|
814
|
+
}
|
|
815
|
+
function mergeProcessChangesets(cp, dcp) {
|
|
816
|
+
return mergeProcessSection(defaultChangesets, dcp?.changesets, cp?.changesets);
|
|
817
|
+
}
|
|
818
|
+
function mergeProcessPr(cp, dcp) {
|
|
819
|
+
return mergeProcessSection(defaultPr, dcp?.pr, cp?.pr);
|
|
820
|
+
}
|
|
821
|
+
function mergeProcessTickets(cp, dcp) {
|
|
822
|
+
return mergeProcessSection(defaultTickets, dcp?.tickets, cp?.tickets);
|
|
823
|
+
}
|
|
824
|
+
function mergeProcessCoverage(cp, dcp) {
|
|
825
|
+
return mergeProcessSection(defaultCoverage, dcp?.coverage, cp?.coverage);
|
|
826
|
+
}
|
|
827
|
+
function mergeProcessRepo(cp, dcp) {
|
|
828
|
+
return mergeProcessSection(defaultRepo, dcp?.repo, cp?.repo);
|
|
829
|
+
}
|
|
830
|
+
function mergeProcessBackups(cp, dcp) {
|
|
831
|
+
return mergeProcessSection(defaultBackups, dcp?.backups, cp?.backups);
|
|
832
|
+
}
|
|
833
|
+
function mergeProcessCodeowners(cp, dcp) {
|
|
834
|
+
const cco = cp?.codeowners;
|
|
835
|
+
const dco = dcp?.codeowners;
|
|
836
|
+
const registryRules = dco?.rules ?? [];
|
|
837
|
+
const projectRules = cco?.rules ?? [];
|
|
838
|
+
const ruleMap = /* @__PURE__ */ new Map();
|
|
839
|
+
for (const rule of registryRules) {
|
|
840
|
+
ruleMap.set(rule.pattern, rule);
|
|
841
|
+
}
|
|
842
|
+
for (const rule of projectRules) {
|
|
843
|
+
ruleMap.set(rule.pattern, rule);
|
|
844
|
+
}
|
|
845
|
+
const mergedRules = Array.from(ruleMap.values());
|
|
846
|
+
return {
|
|
847
|
+
...defaultCodeowners,
|
|
848
|
+
...dco,
|
|
849
|
+
...cco,
|
|
850
|
+
rules: mergedRules.length > 0 ? mergedRules : void 0
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
function mergeProcessDocs(cp, dcp) {
|
|
854
|
+
return mergeProcessSection(defaultDocs, dcp?.docs, cp?.docs);
|
|
855
|
+
}
|
|
856
|
+
function mergeProcessForbiddenFiles(cp, dcp) {
|
|
857
|
+
return mergeProcessSection(defaultForbiddenFiles, dcp?.forbidden_files, cp?.forbidden_files);
|
|
858
|
+
}
|
|
859
|
+
function mergeProcess(c, dc) {
|
|
860
|
+
return {
|
|
861
|
+
hooks: mergeProcessHooks(c.process, dc.process),
|
|
862
|
+
ci: mergeProcessCi(c.process, dc.process),
|
|
863
|
+
branches: mergeProcessBranches(c.process, dc.process),
|
|
864
|
+
commits: mergeProcessCommits(c.process, dc.process),
|
|
865
|
+
changesets: mergeProcessChangesets(c.process, dc.process),
|
|
866
|
+
pr: mergeProcessPr(c.process, dc.process),
|
|
867
|
+
tickets: mergeProcessTickets(c.process, dc.process),
|
|
868
|
+
coverage: mergeProcessCoverage(c.process, dc.process),
|
|
869
|
+
repo: mergeProcessRepo(c.process, dc.process),
|
|
870
|
+
backups: mergeProcessBackups(c.process, dc.process),
|
|
871
|
+
codeowners: mergeProcessCodeowners(c.process, dc.process),
|
|
872
|
+
docs: mergeProcessDocs(c.process, dc.process),
|
|
873
|
+
forbidden_files: mergeProcessForbiddenFiles(c.process, dc.process)
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
function mergeWithDefaults(config) {
|
|
877
|
+
return {
|
|
878
|
+
code: mergeCode(config, defaultConfig),
|
|
879
|
+
process: mergeProcess(config, defaultConfig),
|
|
880
|
+
infra: {
|
|
881
|
+
enabled: config.infra?.enabled ?? defaultConfig.infra?.enabled ?? false,
|
|
882
|
+
manifest: config.infra?.manifest ?? defaultConfig.infra?.manifest ?? "infra-manifest.json"
|
|
883
|
+
},
|
|
884
|
+
monorepo: config.monorepo
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
function getProjectRoot(configPath) {
|
|
888
|
+
return path.dirname(configPath);
|
|
889
|
+
}
|
|
890
|
+
function checkRuleOverride(projectRule, registryOwners) {
|
|
891
|
+
if (!registryOwners) {
|
|
892
|
+
return null;
|
|
893
|
+
}
|
|
894
|
+
const registryStr = registryOwners.join(" ");
|
|
895
|
+
const projectStr = projectRule.owners.join(" ");
|
|
896
|
+
if (registryStr === projectStr) {
|
|
897
|
+
return null;
|
|
898
|
+
}
|
|
899
|
+
return {
|
|
900
|
+
section: "process.codeowners.rules",
|
|
901
|
+
key: projectRule.pattern,
|
|
902
|
+
registryValue: registryStr,
|
|
903
|
+
projectValue: projectStr
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
function detectCodeownersOverrides(registryConfig, projectConfig) {
|
|
907
|
+
const registryRules = registryConfig?.process?.codeowners?.rules ?? [];
|
|
908
|
+
const projectRules = projectConfig?.process?.codeowners?.rules ?? [];
|
|
909
|
+
const registryMap = new Map(registryRules.map((r) => [r.pattern, r.owners]));
|
|
910
|
+
return projectRules.map((rule) => checkRuleOverride(rule, registryMap.get(rule.pattern))).filter((o) => o !== null);
|
|
911
|
+
}
|
|
912
|
+
async function loadRegistryConfig(extendsConfig, configDir) {
|
|
913
|
+
const registryModule = await import("./registry-V65CC7IN.js");
|
|
914
|
+
const loc = registryModule.parseRegistryUrl(extendsConfig.registry, configDir);
|
|
915
|
+
const registryDir = await registryModule.fetchRegistry(loc);
|
|
916
|
+
let config = {};
|
|
917
|
+
for (const name of extendsConfig.rulesets) {
|
|
918
|
+
config = registryModule.mergeConfigs(config, registryModule.loadRuleset(registryDir, name));
|
|
919
|
+
}
|
|
920
|
+
return config;
|
|
921
|
+
}
|
|
922
|
+
async function loadConfigWithOverrides(configPath) {
|
|
923
|
+
const resolvedPath = resolveConfigPath(configPath);
|
|
924
|
+
const validatedConfig = validateConfig(parseTomlFile(resolvedPath));
|
|
925
|
+
let overrides = [];
|
|
926
|
+
if (validatedConfig.extends) {
|
|
927
|
+
const registryConfig = await loadRegistryConfig(
|
|
928
|
+
validatedConfig.extends,
|
|
929
|
+
path.dirname(resolvedPath)
|
|
930
|
+
);
|
|
931
|
+
overrides = detectCodeownersOverrides(registryConfig, validatedConfig);
|
|
932
|
+
}
|
|
933
|
+
const { config, configPath: finalPath } = await loadConfigAsync(configPath);
|
|
934
|
+
return { config, configPath: finalPath, overrides };
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
// ../core/src/registry.ts
|
|
938
|
+
function detectAuthMethod() {
|
|
939
|
+
if (process.env.CONFORM_REGISTRY_TOKEN || process.env.GITHUB_TOKEN) {
|
|
940
|
+
return "token";
|
|
941
|
+
}
|
|
942
|
+
if (process.env.SSH_AUTH_SOCK) {
|
|
943
|
+
return "ssh";
|
|
944
|
+
}
|
|
945
|
+
return "none";
|
|
946
|
+
}
|
|
947
|
+
function getAuthToken() {
|
|
948
|
+
return process.env.CONFORM_REGISTRY_TOKEN ?? process.env.GITHUB_TOKEN;
|
|
949
|
+
}
|
|
950
|
+
function buildGitHubUrl(owner, repo, auth) {
|
|
951
|
+
switch (auth) {
|
|
952
|
+
case "ssh":
|
|
953
|
+
return `git@github.com:${owner}/${repo}.git`;
|
|
954
|
+
case "token": {
|
|
955
|
+
const token = getAuthToken();
|
|
956
|
+
if (token) {
|
|
957
|
+
return `https://x-access-token:${token}@github.com/${owner}/${repo}.git`;
|
|
958
|
+
}
|
|
959
|
+
return `https://github.com/${owner}/${repo}.git`;
|
|
960
|
+
}
|
|
961
|
+
case "none":
|
|
962
|
+
default:
|
|
963
|
+
return `https://github.com/${owner}/${repo}.git`;
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
function parseAuthFromUrl(url) {
|
|
967
|
+
if (url.startsWith("github+ssh:")) {
|
|
968
|
+
return { auth: "ssh", rest: url.slice(11) };
|
|
969
|
+
}
|
|
970
|
+
if (url.startsWith("github+token:")) {
|
|
971
|
+
return { auth: "token", rest: url.slice(13) };
|
|
972
|
+
}
|
|
973
|
+
if (url.startsWith("github:")) {
|
|
974
|
+
return { auth: "auto", rest: url.slice(7) };
|
|
975
|
+
}
|
|
976
|
+
throw new ConfigError(`Invalid GitHub registry URL: ${url}`);
|
|
977
|
+
}
|
|
978
|
+
function parseGitHubUrl(url) {
|
|
979
|
+
const { auth: explicitAuth, rest } = parseAuthFromUrl(url);
|
|
980
|
+
const [repoPath, ref] = rest.split("@");
|
|
981
|
+
const [owner, repo] = repoPath.split("/");
|
|
982
|
+
if (!owner || !repo) {
|
|
983
|
+
throw new ConfigError(
|
|
984
|
+
`Invalid GitHub registry URL: ${url}. Expected format: github:owner/repo or github+ssh:owner/repo`
|
|
985
|
+
);
|
|
986
|
+
}
|
|
987
|
+
const auth = explicitAuth === "auto" ? detectAuthMethod() : explicitAuth;
|
|
988
|
+
return {
|
|
989
|
+
type: "github",
|
|
990
|
+
owner,
|
|
991
|
+
repo,
|
|
992
|
+
ref: ref || void 0,
|
|
993
|
+
path: buildGitHubUrl(owner, repo, auth),
|
|
994
|
+
auth
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
function parseRegistryUrl(url, configDir) {
|
|
998
|
+
if (url.startsWith("github:") || url.startsWith("github+")) {
|
|
999
|
+
return parseGitHubUrl(url);
|
|
1000
|
+
}
|
|
1001
|
+
const localPath = !path2.isAbsolute(url) && configDir ? path2.resolve(configDir, url) : url;
|
|
1002
|
+
return { type: "local", path: localPath };
|
|
1003
|
+
}
|
|
1004
|
+
async function updateExistingRepo(repoDir, ref) {
|
|
1005
|
+
try {
|
|
1006
|
+
if (ref) {
|
|
1007
|
+
await execa("git", ["fetch", "--all"], { cwd: repoDir });
|
|
1008
|
+
await execa("git", ["checkout", ref], { cwd: repoDir });
|
|
1009
|
+
} else {
|
|
1010
|
+
await execa("git", ["pull", "--ff-only"], { cwd: repoDir });
|
|
1011
|
+
}
|
|
1012
|
+
return true;
|
|
1013
|
+
} catch {
|
|
1014
|
+
fs2.rmSync(repoDir, { recursive: true, force: true });
|
|
1015
|
+
return false;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
async function cloneRepo(location, repoDir) {
|
|
1019
|
+
const cacheDir = path2.dirname(repoDir);
|
|
1020
|
+
fs2.mkdirSync(cacheDir, { recursive: true });
|
|
1021
|
+
const cloneArgs = ["clone", "--depth", "1"];
|
|
1022
|
+
if (location.ref) {
|
|
1023
|
+
cloneArgs.push("--branch", location.ref);
|
|
1024
|
+
}
|
|
1025
|
+
cloneArgs.push(location.path, repoDir);
|
|
1026
|
+
try {
|
|
1027
|
+
await execa("git", cloneArgs, { timeout: 30 * 1e3 });
|
|
1028
|
+
} catch (error) {
|
|
1029
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1030
|
+
if (message.includes("timed out")) {
|
|
1031
|
+
throw new ConfigError(`Registry clone timed out after 30 seconds: ${location.path}`);
|
|
1032
|
+
}
|
|
1033
|
+
throw new ConfigError(`Failed to clone registry: ${message}`);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
async function fetchRegistry(location) {
|
|
1037
|
+
if (location.type === "local") {
|
|
1038
|
+
if (!fs2.existsSync(location.path)) {
|
|
1039
|
+
throw new ConfigError(`Registry not found: ${location.path}`);
|
|
1040
|
+
}
|
|
1041
|
+
return location.path;
|
|
1042
|
+
}
|
|
1043
|
+
const cacheDir = path2.join(os.tmpdir(), "conform-registry-cache");
|
|
1044
|
+
const repoDir = path2.join(cacheDir, `${location.owner}-${location.repo}`);
|
|
1045
|
+
if (fs2.existsSync(repoDir)) {
|
|
1046
|
+
await updateExistingRepo(repoDir, location.ref);
|
|
1047
|
+
}
|
|
1048
|
+
if (!fs2.existsSync(repoDir)) {
|
|
1049
|
+
await cloneRepo(location, repoDir);
|
|
1050
|
+
}
|
|
1051
|
+
return repoDir;
|
|
1052
|
+
}
|
|
1053
|
+
function loadRuleset(registryDir, rulesetName) {
|
|
1054
|
+
const rulesetPath = path2.join(registryDir, "rulesets", `${rulesetName}.toml`);
|
|
1055
|
+
if (!fs2.existsSync(rulesetPath)) {
|
|
1056
|
+
throw new ConfigError(`Ruleset not found: ${rulesetName} (expected at ${rulesetPath})`);
|
|
1057
|
+
}
|
|
1058
|
+
const content = fs2.readFileSync(rulesetPath, "utf-8");
|
|
1059
|
+
let parsed;
|
|
1060
|
+
try {
|
|
1061
|
+
parsed = toml.parse(content);
|
|
1062
|
+
} catch (error) {
|
|
1063
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1064
|
+
throw new ConfigError(`Failed to parse ruleset ${rulesetName}: ${message}`);
|
|
1065
|
+
}
|
|
1066
|
+
const result = configSchema.safeParse(parsed);
|
|
1067
|
+
if (!result.success) {
|
|
1068
|
+
const errors = result.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
|
|
1069
|
+
throw new ConfigError(`Invalid ruleset ${rulesetName}: ${errors}`);
|
|
1070
|
+
}
|
|
1071
|
+
return result.data;
|
|
1072
|
+
}
|
|
1073
|
+
function mergeToolConfig(base, override) {
|
|
1074
|
+
if (!override) {
|
|
1075
|
+
return base;
|
|
1076
|
+
}
|
|
1077
|
+
return { ...base, ...override };
|
|
1078
|
+
}
|
|
1079
|
+
function mergeLinting2(base, override) {
|
|
1080
|
+
if (!override) {
|
|
1081
|
+
return base;
|
|
1082
|
+
}
|
|
1083
|
+
return {
|
|
1084
|
+
...base,
|
|
1085
|
+
eslint: mergeToolConfig(base?.eslint, override.eslint),
|
|
1086
|
+
ruff: mergeToolConfig(base?.ruff, override.ruff)
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
function mergeTypes2(base, override) {
|
|
1090
|
+
if (!override) {
|
|
1091
|
+
return base;
|
|
1092
|
+
}
|
|
1093
|
+
return {
|
|
1094
|
+
...base,
|
|
1095
|
+
tsc: mergeToolConfig(base?.tsc, override.tsc),
|
|
1096
|
+
ty: mergeToolConfig(base?.ty, override.ty)
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
function mergeUnused2(base, override) {
|
|
1100
|
+
if (!override) {
|
|
1101
|
+
return base;
|
|
1102
|
+
}
|
|
1103
|
+
return {
|
|
1104
|
+
...base,
|
|
1105
|
+
knip: mergeToolConfig(base?.knip, override.knip),
|
|
1106
|
+
vulture: mergeToolConfig(base?.vulture, override.vulture)
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
function mergeSecurity2(base, override) {
|
|
1110
|
+
if (!override) {
|
|
1111
|
+
return base;
|
|
1112
|
+
}
|
|
1113
|
+
return {
|
|
1114
|
+
...base,
|
|
1115
|
+
secrets: mergeToolConfig(base?.secrets, override.secrets),
|
|
1116
|
+
pnpmaudit: mergeToolConfig(base?.pnpmaudit, override.pnpmaudit),
|
|
1117
|
+
pipaudit: mergeToolConfig(base?.pipaudit, override.pipaudit)
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
function mergeNaming2(base, override) {
|
|
1121
|
+
if (!override) {
|
|
1122
|
+
return base;
|
|
1123
|
+
}
|
|
1124
|
+
return {
|
|
1125
|
+
enabled: override.enabled,
|
|
1126
|
+
rules: override.rules ?? base?.rules
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
function mergeQuality2(base, override) {
|
|
1130
|
+
if (!override) {
|
|
1131
|
+
return base;
|
|
1132
|
+
}
|
|
1133
|
+
return {
|
|
1134
|
+
...base,
|
|
1135
|
+
"disable-comments": mergeToolConfig(base?.["disable-comments"], override["disable-comments"])
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
function mergeCodeSection(base, override) {
|
|
1139
|
+
return {
|
|
1140
|
+
linting: mergeLinting2(base?.linting, override.linting),
|
|
1141
|
+
types: mergeTypes2(base?.types, override.types),
|
|
1142
|
+
unused: mergeUnused2(base?.unused, override.unused),
|
|
1143
|
+
coverage_run: mergeToolConfig(base?.coverage_run, override.coverage_run),
|
|
1144
|
+
security: mergeSecurity2(base?.security, override.security),
|
|
1145
|
+
naming: mergeNaming2(base?.naming, override.naming),
|
|
1146
|
+
quality: mergeQuality2(base?.quality, override.quality)
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
function mergeHooksConfig(base, override) {
|
|
1150
|
+
if (!override) {
|
|
1151
|
+
return base;
|
|
1152
|
+
}
|
|
1153
|
+
return {
|
|
1154
|
+
enabled: override.enabled,
|
|
1155
|
+
require_husky: override.require_husky,
|
|
1156
|
+
require_hooks: override.require_hooks ?? base?.require_hooks,
|
|
1157
|
+
commands: override.commands ?? base?.commands
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
function mergeCiConfig(base, override) {
|
|
1161
|
+
if (!override) {
|
|
1162
|
+
return base;
|
|
1163
|
+
}
|
|
1164
|
+
return {
|
|
1165
|
+
enabled: override.enabled,
|
|
1166
|
+
require_workflows: override.require_workflows ?? base?.require_workflows,
|
|
1167
|
+
jobs: override.jobs ?? base?.jobs,
|
|
1168
|
+
actions: override.actions ?? base?.actions
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
function mergeBranchesConfig(base, override) {
|
|
1172
|
+
if (!override) {
|
|
1173
|
+
return base;
|
|
1174
|
+
}
|
|
1175
|
+
return {
|
|
1176
|
+
enabled: override.enabled,
|
|
1177
|
+
require_issue: override.require_issue,
|
|
1178
|
+
pattern: override.pattern ?? base?.pattern,
|
|
1179
|
+
exclude: override.exclude ?? base?.exclude,
|
|
1180
|
+
issue_pattern: override.issue_pattern ?? base?.issue_pattern
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
function mergePrConfig(base, override) {
|
|
1184
|
+
if (!override) {
|
|
1185
|
+
return base;
|
|
1186
|
+
}
|
|
1187
|
+
return {
|
|
1188
|
+
enabled: override.enabled,
|
|
1189
|
+
require_issue: override.require_issue,
|
|
1190
|
+
max_files: override.max_files ?? base?.max_files,
|
|
1191
|
+
max_lines: override.max_lines ?? base?.max_lines,
|
|
1192
|
+
issue_keywords: override.issue_keywords ?? base?.issue_keywords
|
|
1193
|
+
};
|
|
1194
|
+
}
|
|
1195
|
+
function mergeTicketsConfig(base, override) {
|
|
1196
|
+
if (!override) {
|
|
1197
|
+
return base;
|
|
1198
|
+
}
|
|
1199
|
+
return {
|
|
1200
|
+
enabled: override.enabled,
|
|
1201
|
+
pattern: override.pattern ?? base?.pattern,
|
|
1202
|
+
require_in_commits: override.require_in_commits,
|
|
1203
|
+
require_in_branch: override.require_in_branch
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
function mergeCoverageConfig(base, override) {
|
|
1207
|
+
if (!override) {
|
|
1208
|
+
return base;
|
|
1209
|
+
}
|
|
1210
|
+
return {
|
|
1211
|
+
enabled: override.enabled,
|
|
1212
|
+
min_threshold: override.min_threshold ?? base?.min_threshold,
|
|
1213
|
+
enforce_in: override.enforce_in,
|
|
1214
|
+
ci_workflow: override.ci_workflow ?? base?.ci_workflow,
|
|
1215
|
+
ci_job: override.ci_job ?? base?.ci_job
|
|
1216
|
+
};
|
|
1217
|
+
}
|
|
1218
|
+
function mergeCommitsConfig(base, override) {
|
|
1219
|
+
if (!override) {
|
|
1220
|
+
return base;
|
|
1221
|
+
}
|
|
1222
|
+
return {
|
|
1223
|
+
enabled: override.enabled,
|
|
1224
|
+
pattern: override.pattern ?? base?.pattern,
|
|
1225
|
+
types: override.types ?? base?.types,
|
|
1226
|
+
require_scope: override.require_scope,
|
|
1227
|
+
max_subject_length: override.max_subject_length ?? base?.max_subject_length
|
|
1228
|
+
};
|
|
1229
|
+
}
|
|
1230
|
+
function mergeChangesetsConfig(base, override) {
|
|
1231
|
+
if (!override) {
|
|
1232
|
+
return base;
|
|
1233
|
+
}
|
|
1234
|
+
return {
|
|
1235
|
+
enabled: override.enabled,
|
|
1236
|
+
require_for_paths: override.require_for_paths ?? base?.require_for_paths,
|
|
1237
|
+
exclude_paths: override.exclude_paths ?? base?.exclude_paths,
|
|
1238
|
+
validate_format: override.validate_format,
|
|
1239
|
+
allowed_bump_types: override.allowed_bump_types ?? base?.allowed_bump_types,
|
|
1240
|
+
require_description: override.require_description,
|
|
1241
|
+
min_description_length: override.min_description_length ?? base?.min_description_length
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
function mergeRepoConfig(base, override) {
|
|
1245
|
+
if (!override) {
|
|
1246
|
+
return base;
|
|
1247
|
+
}
|
|
1248
|
+
return {
|
|
1249
|
+
enabled: override.enabled,
|
|
1250
|
+
require_branch_protection: override.require_branch_protection,
|
|
1251
|
+
require_codeowners: override.require_codeowners,
|
|
1252
|
+
ruleset: override.ruleset ?? base?.ruleset,
|
|
1253
|
+
tag_protection: override.tag_protection ?? base?.tag_protection
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
function mergeBackupsConfig(base, override) {
|
|
1257
|
+
if (!override) {
|
|
1258
|
+
return base;
|
|
1259
|
+
}
|
|
1260
|
+
return {
|
|
1261
|
+
enabled: override.enabled,
|
|
1262
|
+
bucket: override.bucket ?? base?.bucket,
|
|
1263
|
+
prefix: override.prefix ?? base?.prefix,
|
|
1264
|
+
max_age_hours: override.max_age_hours,
|
|
1265
|
+
region: override.region ?? base?.region
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
function mergeCodeownersConfig(base, override) {
|
|
1269
|
+
if (!override) {
|
|
1270
|
+
return base;
|
|
1271
|
+
}
|
|
1272
|
+
return {
|
|
1273
|
+
enabled: override.enabled,
|
|
1274
|
+
rules: override.rules ?? base?.rules
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1277
|
+
function mergeDocsConfig(base, override) {
|
|
1278
|
+
if (!override) {
|
|
1279
|
+
return base;
|
|
1280
|
+
}
|
|
1281
|
+
return {
|
|
1282
|
+
enabled: override.enabled,
|
|
1283
|
+
path: override.path,
|
|
1284
|
+
enforcement: override.enforcement,
|
|
1285
|
+
allowlist: override.allowlist ?? base?.allowlist,
|
|
1286
|
+
max_files: override.max_files ?? base?.max_files,
|
|
1287
|
+
max_file_lines: override.max_file_lines ?? base?.max_file_lines,
|
|
1288
|
+
max_total_kb: override.max_total_kb ?? base?.max_total_kb,
|
|
1289
|
+
staleness_days: override.staleness_days,
|
|
1290
|
+
stale_mappings: override.stale_mappings ?? base?.stale_mappings,
|
|
1291
|
+
min_coverage: override.min_coverage ?? base?.min_coverage,
|
|
1292
|
+
coverage_paths: override.coverage_paths ?? base?.coverage_paths,
|
|
1293
|
+
exclude_patterns: override.exclude_patterns ?? base?.exclude_patterns,
|
|
1294
|
+
types: override.types ?? base?.types
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
function mergeProcessSection2(base, override) {
|
|
1298
|
+
return {
|
|
1299
|
+
hooks: mergeHooksConfig(base?.hooks, override.hooks),
|
|
1300
|
+
ci: mergeCiConfig(base?.ci, override.ci),
|
|
1301
|
+
branches: mergeBranchesConfig(base?.branches, override.branches),
|
|
1302
|
+
commits: mergeCommitsConfig(base?.commits, override.commits),
|
|
1303
|
+
changesets: mergeChangesetsConfig(base?.changesets, override.changesets),
|
|
1304
|
+
pr: mergePrConfig(base?.pr, override.pr),
|
|
1305
|
+
tickets: mergeTicketsConfig(base?.tickets, override.tickets),
|
|
1306
|
+
coverage: mergeCoverageConfig(base?.coverage, override.coverage),
|
|
1307
|
+
repo: mergeRepoConfig(base?.repo, override.repo),
|
|
1308
|
+
backups: mergeBackupsConfig(base?.backups, override.backups),
|
|
1309
|
+
codeowners: mergeCodeownersConfig(base?.codeowners, override.codeowners),
|
|
1310
|
+
docs: mergeDocsConfig(base?.docs, override.docs)
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
function mergeConfigs(base, override) {
|
|
1314
|
+
const merged = { ...base };
|
|
1315
|
+
if (override.code) {
|
|
1316
|
+
merged.code = mergeCodeSection(base.code, override.code);
|
|
1317
|
+
}
|
|
1318
|
+
if (override.process) {
|
|
1319
|
+
merged.process = mergeProcessSection2(base.process, override.process);
|
|
1320
|
+
}
|
|
1321
|
+
if (override.infra) {
|
|
1322
|
+
merged.infra = override.infra;
|
|
1323
|
+
}
|
|
1324
|
+
if (override.monorepo) {
|
|
1325
|
+
merged.monorepo = override.monorepo;
|
|
1326
|
+
}
|
|
1327
|
+
return merged;
|
|
1328
|
+
}
|
|
1329
|
+
async function resolveExtends(config, configDir) {
|
|
1330
|
+
if (!config.extends) {
|
|
1331
|
+
return config;
|
|
1332
|
+
}
|
|
1333
|
+
const { registry, rulesets } = config.extends;
|
|
1334
|
+
const location = parseRegistryUrl(registry, configDir);
|
|
1335
|
+
const registryDir = await fetchRegistry(location);
|
|
1336
|
+
let mergedConfig = {};
|
|
1337
|
+
for (const rulesetName of rulesets) {
|
|
1338
|
+
const ruleset = loadRuleset(registryDir, rulesetName);
|
|
1339
|
+
mergedConfig = mergeConfigs(mergedConfig, ruleset);
|
|
1340
|
+
}
|
|
1341
|
+
const localConfig = {
|
|
1342
|
+
code: config.code,
|
|
1343
|
+
process: config.process,
|
|
1344
|
+
infra: config.infra,
|
|
1345
|
+
monorepo: config.monorepo
|
|
1346
|
+
};
|
|
1347
|
+
return mergeConfigs(mergedConfig, localConfig);
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
export {
|
|
1351
|
+
DEFAULT_FORBIDDEN_FILES_IGNORE,
|
|
1352
|
+
configSchema,
|
|
1353
|
+
defaultConfig,
|
|
1354
|
+
parseRegistryUrl,
|
|
1355
|
+
fetchRegistry,
|
|
1356
|
+
loadRuleset,
|
|
1357
|
+
mergeConfigs,
|
|
1358
|
+
resolveExtends,
|
|
1359
|
+
CONFIG_FILE_NAME,
|
|
1360
|
+
ConfigError,
|
|
1361
|
+
findConfigFile,
|
|
1362
|
+
loadConfig,
|
|
1363
|
+
loadConfigAsync,
|
|
1364
|
+
getProjectRoot,
|
|
1365
|
+
loadConfigWithOverrides
|
|
1366
|
+
};
|
|
1367
|
+
//# sourceMappingURL=chunk-KHO6NIAI.js.map
|