@ankhorage/doctor 0.11.6 → 0.11.8
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 +13 -0
- package/README.md +1 -1
- package/dist/analysis.d.ts.map +1 -1
- package/dist/analysis.js +62 -181
- package/dist/analysis.js.map +1 -1
- package/dist/cliLayoutAnalysis.d.ts.map +1 -1
- package/dist/cliLayoutAnalysis.js +26 -26
- package/dist/cliLayoutAnalysis.js.map +1 -1
- package/dist/sourceArchitectureAnalysis.d.ts.map +1 -1
- package/dist/sourceArchitectureAnalysis.js +35 -70
- package/dist/sourceArchitectureAnalysis.js.map +1 -1
- package/dist/utils/getArchitecturePolicyRule.d.ts +281 -0
- package/dist/utils/getArchitecturePolicyRule.d.ts.map +1 -0
- package/dist/utils/getArchitecturePolicyRule.js +12 -0
- package/dist/utils/getArchitecturePolicyRule.js.map +1 -0
- package/package.json +3 -3
- package/src/analysis.ts +83 -218
- package/src/cliLayoutAnalysis.ts +33 -26
- package/src/sourceArchitectureAnalysis.ts +59 -105
- package/src/utils/getArchitecturePolicyRule.ts +15 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.11.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 53a39da: Consume canonical source-architecture and public-package profile rules from `@ankhorage/policy/architecture` instead of duplicating them in Doctor.
|
|
8
|
+
|
|
9
|
+
## 0.11.7
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- caf0f19: Update Ankhorage dependencies: `@ankhorage/policy`.
|
|
14
|
+
- caf0f19: Update `@ankhorage/policy` to 0.5.1 so Doctor can consume literal architecture rule ids without casts.
|
|
15
|
+
|
|
3
16
|
## 0.11.6
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
# @ankhorage/doctor
|
|
5
5
|
|
|
6
|
-
         
|
|
7
7
|
|
|
8
8
|
Executable Ankh provider and standalone CLI for lightweight repo and package compliance diagnostics.
|
|
9
9
|
|
package/dist/analysis.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../src/analysis.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../src/analysis.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC5F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGtD,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAChE,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;AACvE,MAAM,MAAM,uBAAuB,GACjC,kBAAkB,GAAG,aAAa,GAAG,aAAa,GAAG,aAAa,CAAC;AAErE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACjD,QAAQ,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAClD,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,aAAa,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACrD,QAAQ,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAClD,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,cAAc,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACxD,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAChD,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AA+BD,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CA+I/B"}
|
package/dist/analysis.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { promises as fs } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
|
+
import { ARCHITECTURE_POLICY } from '@ankhorage/policy/architecture';
|
|
4
5
|
import { uniqueSortedStrings } from '@ankhorage/utility/array';
|
|
6
|
+
import { getArchitecturePolicyRule } from './utils/getArchitecturePolicyRule.js';
|
|
5
7
|
const REPO_MARKERS = [
|
|
6
8
|
{ label: '.git', relativePath: '.git' },
|
|
7
9
|
{ label: '.github/workflows', relativePath: path.join('.github', 'workflows') },
|
|
@@ -13,21 +15,7 @@ const REPO_MARKERS = [
|
|
|
13
15
|
{ label: 'package-lock.json', relativePath: 'package-lock.json' },
|
|
14
16
|
{ label: 'yarn.lock', relativePath: 'yarn.lock' },
|
|
15
17
|
];
|
|
16
|
-
const
|
|
17
|
-
'build',
|
|
18
|
-
'typecheck',
|
|
19
|
-
'lint',
|
|
20
|
-
'lint:fix',
|
|
21
|
-
'format',
|
|
22
|
-
'format:check',
|
|
23
|
-
'test',
|
|
24
|
-
'test:standalone',
|
|
25
|
-
'knip:check',
|
|
26
|
-
'docs',
|
|
27
|
-
'changeset',
|
|
28
|
-
'changeset:status',
|
|
29
|
-
'version-packages',
|
|
30
|
-
];
|
|
18
|
+
const PUBLIC_PACKAGE_POLICY = ARCHITECTURE_POLICY.publicPackage;
|
|
31
19
|
const PROVIDER_SOURCE_CANDIDATES = [
|
|
32
20
|
path.join('src', 'ankh.provider.ts'),
|
|
33
21
|
path.join('src', 'ankh.provider.tsx'),
|
|
@@ -146,11 +134,9 @@ export async function analyzeDoctorTarget(request) {
|
|
|
146
134
|
async function analyzeRepoPolicy(request) {
|
|
147
135
|
const diagnostics = [];
|
|
148
136
|
if (request.profile === 'public-package') {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
await maybeRequirePath(diagnostics, request.plannedChanges, request.targetPath, '.changeset', 'repo.changeset.required', 'create-directory');
|
|
153
|
-
await maybeRequirePath(diagnostics, request.plannedChanges, request.targetPath, path.join('.github', 'workflows'), 'repo.workflows.required', 'create-directory');
|
|
137
|
+
for (const artifact of PUBLIC_PACKAGE_POLICY.requiredRepoPaths) {
|
|
138
|
+
await maybeRequirePath(diagnostics, request.plannedChanges, request.targetPath, artifact.path, artifact.ruleId, artifact.kind === 'file' ? 'create-file' : 'create-directory');
|
|
139
|
+
}
|
|
154
140
|
}
|
|
155
141
|
if (request.profile === 'integration-monorepo') {
|
|
156
142
|
if (!request.repoMarkers.includes('package.json')) {
|
|
@@ -205,29 +191,11 @@ async function analyzePackagePolicy(request) {
|
|
|
205
191
|
const diagnostics = [];
|
|
206
192
|
const { packageJson } = request;
|
|
207
193
|
if (request.profile === 'public-package') {
|
|
208
|
-
|
|
209
|
-
diagnostics,
|
|
210
|
-
packageJson,
|
|
211
|
-
packageJsonPath: request.packageJsonPath,
|
|
212
|
-
profile: request.profile,
|
|
213
|
-
ruleId: 'package.json.name.required',
|
|
214
|
-
fieldName: 'name',
|
|
215
|
-
});
|
|
216
|
-
requireNonEmptyStringField({
|
|
217
|
-
diagnostics,
|
|
218
|
-
packageJson,
|
|
219
|
-
packageJsonPath: request.packageJsonPath,
|
|
220
|
-
profile: request.profile,
|
|
221
|
-
ruleId: 'package.json.version.required',
|
|
222
|
-
fieldName: 'version',
|
|
223
|
-
});
|
|
224
|
-
requireNonEmptyStringField({
|
|
194
|
+
requirePublicPackageFields({
|
|
225
195
|
diagnostics,
|
|
226
196
|
packageJson,
|
|
227
197
|
packageJsonPath: request.packageJsonPath,
|
|
228
198
|
profile: request.profile,
|
|
229
|
-
ruleId: 'package.json.type.required',
|
|
230
|
-
fieldName: 'type',
|
|
231
199
|
});
|
|
232
200
|
}
|
|
233
201
|
if (request.profile !== 'public-package') {
|
|
@@ -240,107 +208,34 @@ async function analyzePackagePolicy(request) {
|
|
|
240
208
|
targetPath: request.targetPath,
|
|
241
209
|
}));
|
|
242
210
|
}
|
|
243
|
-
requireNonEmptyStringField({
|
|
244
|
-
diagnostics,
|
|
245
|
-
packageJson,
|
|
246
|
-
packageJsonPath: request.packageJsonPath,
|
|
247
|
-
profile: request.profile,
|
|
248
|
-
ruleId: 'package.json.description.required',
|
|
249
|
-
fieldName: 'description',
|
|
250
|
-
});
|
|
251
|
-
requireRecordField({
|
|
252
|
-
diagnostics,
|
|
253
|
-
packageJson,
|
|
254
|
-
packageJsonPath: request.packageJsonPath,
|
|
255
|
-
profile: request.profile,
|
|
256
|
-
ruleId: 'package.json.repository.required',
|
|
257
|
-
fieldName: 'repository',
|
|
258
|
-
});
|
|
259
|
-
requireNonEmptyStringField({
|
|
260
|
-
diagnostics,
|
|
261
|
-
packageJson,
|
|
262
|
-
packageJsonPath: request.packageJsonPath,
|
|
263
|
-
profile: request.profile,
|
|
264
|
-
ruleId: 'package.json.homepage.required',
|
|
265
|
-
fieldName: 'homepage',
|
|
266
|
-
});
|
|
267
|
-
requireRecordField({
|
|
268
|
-
diagnostics,
|
|
269
|
-
packageJson,
|
|
270
|
-
packageJsonPath: request.packageJsonPath,
|
|
271
|
-
profile: request.profile,
|
|
272
|
-
ruleId: 'package.json.bugs.required',
|
|
273
|
-
fieldName: 'bugs',
|
|
274
|
-
});
|
|
275
|
-
requireNonEmptyStringField({
|
|
276
|
-
diagnostics,
|
|
277
|
-
packageJson,
|
|
278
|
-
packageJsonPath: request.packageJsonPath,
|
|
279
|
-
profile: request.profile,
|
|
280
|
-
ruleId: 'package.json.license.required',
|
|
281
|
-
fieldName: 'license',
|
|
282
|
-
});
|
|
283
|
-
requireStringArrayField({
|
|
284
|
-
diagnostics,
|
|
285
|
-
packageJson,
|
|
286
|
-
packageJsonPath: request.packageJsonPath,
|
|
287
|
-
profile: request.profile,
|
|
288
|
-
ruleId: 'package.json.keywords.required',
|
|
289
|
-
fieldName: 'keywords',
|
|
290
|
-
});
|
|
291
|
-
requireStringArrayField({
|
|
292
|
-
diagnostics,
|
|
293
|
-
packageJson,
|
|
294
|
-
packageJsonPath: request.packageJsonPath,
|
|
295
|
-
profile: request.profile,
|
|
296
|
-
ruleId: 'package.json.files.required',
|
|
297
|
-
fieldName: 'files',
|
|
298
|
-
});
|
|
299
|
-
requireRecordField({
|
|
300
|
-
diagnostics,
|
|
301
|
-
packageJson,
|
|
302
|
-
packageJsonPath: request.packageJsonPath,
|
|
303
|
-
profile: request.profile,
|
|
304
|
-
ruleId: 'package.json.exports.required',
|
|
305
|
-
fieldName: 'exports',
|
|
306
|
-
});
|
|
307
|
-
requireRecordField({
|
|
308
|
-
diagnostics,
|
|
309
|
-
packageJson,
|
|
310
|
-
packageJsonPath: request.packageJsonPath,
|
|
311
|
-
profile: request.profile,
|
|
312
|
-
ruleId: 'package.json.publish-config.required',
|
|
313
|
-
fieldName: 'publishConfig',
|
|
314
|
-
});
|
|
315
211
|
if (packageJson.private === true) {
|
|
316
212
|
diagnostics.push(createDiagnostic({
|
|
317
213
|
code: 'field-invalid',
|
|
318
214
|
message: 'Public package profiles must not set private: true.',
|
|
319
215
|
path: request.packageJsonPath,
|
|
320
216
|
profile: request.profile,
|
|
321
|
-
|
|
322
|
-
severity: 'error',
|
|
217
|
+
...architecturePolicyRuleFields(PUBLIC_PACKAGE_POLICY.privateDisallowedRuleId),
|
|
323
218
|
}));
|
|
324
219
|
}
|
|
325
|
-
if (packageJson.type !== undefined &&
|
|
220
|
+
if (packageJson.type !== undefined &&
|
|
221
|
+
packageJson.type !== PUBLIC_PACKAGE_POLICY.packageType.value) {
|
|
326
222
|
diagnostics.push(createDiagnostic({
|
|
327
223
|
code: 'field-invalid',
|
|
328
|
-
message:
|
|
224
|
+
message: `package.json "type" must be "${PUBLIC_PACKAGE_POLICY.packageType.value}".`,
|
|
329
225
|
path: request.packageJsonPath,
|
|
330
226
|
profile: request.profile,
|
|
331
|
-
|
|
332
|
-
severity: 'error',
|
|
227
|
+
...architecturePolicyRuleFields(PUBLIC_PACKAGE_POLICY.packageType.ruleId),
|
|
333
228
|
}));
|
|
334
229
|
}
|
|
335
230
|
const { publishConfig } = packageJson;
|
|
336
|
-
if (isRecord(publishConfig) &&
|
|
231
|
+
if (isRecord(publishConfig) &&
|
|
232
|
+
publishConfig.access !== PUBLIC_PACKAGE_POLICY.publishAccess.value) {
|
|
337
233
|
diagnostics.push(createDiagnostic({
|
|
338
234
|
code: isNonEmptyString(publishConfig.access) ? 'field-invalid' : 'field-missing',
|
|
339
|
-
message:
|
|
235
|
+
message: `package.json publishConfig.access must exist and equal "${PUBLIC_PACKAGE_POLICY.publishAccess.value}".`,
|
|
340
236
|
path: request.packageJsonPath,
|
|
341
237
|
profile: request.profile,
|
|
342
|
-
|
|
343
|
-
severity: 'error',
|
|
238
|
+
...architecturePolicyRuleFields(PUBLIC_PACKAGE_POLICY.publishAccess.ruleId),
|
|
344
239
|
}));
|
|
345
240
|
}
|
|
346
241
|
if (!isNonEmptyString(packageJson.packageManager)) {
|
|
@@ -349,14 +244,13 @@ async function analyzePackagePolicy(request) {
|
|
|
349
244
|
message: 'package.json must define a Bun-aligned packageManager field.',
|
|
350
245
|
path: request.packageJsonPath,
|
|
351
246
|
profile: request.profile,
|
|
352
|
-
|
|
353
|
-
severity: 'error',
|
|
247
|
+
...architecturePolicyRuleFields(PUBLIC_PACKAGE_POLICY.packageManager.requiredRuleId),
|
|
354
248
|
}));
|
|
355
249
|
request.plannedChanges.push(createPlannedChange({
|
|
356
250
|
description: `Add packageManager: "bun@${Bun.version}" to package.json.`,
|
|
357
251
|
filePath: request.packageJsonPath,
|
|
358
252
|
kind: 'update-json',
|
|
359
|
-
ruleId:
|
|
253
|
+
ruleId: PUBLIC_PACKAGE_POLICY.packageManager.requiredRuleId,
|
|
360
254
|
}));
|
|
361
255
|
}
|
|
362
256
|
else if (!packageJson.packageManager.startsWith('bun@')) {
|
|
@@ -365,20 +259,18 @@ async function analyzePackagePolicy(request) {
|
|
|
365
259
|
message: 'package.json packageManager must be Bun-aligned, for example "bun@1.x".',
|
|
366
260
|
path: request.packageJsonPath,
|
|
367
261
|
profile: request.profile,
|
|
368
|
-
|
|
369
|
-
severity: 'error',
|
|
262
|
+
...architecturePolicyRuleFields(PUBLIC_PACKAGE_POLICY.packageManager.bunRuleId),
|
|
370
263
|
}));
|
|
371
264
|
}
|
|
372
265
|
const scripts = isRecord(packageJson.scripts) ? packageJson.scripts : null;
|
|
373
|
-
for (const
|
|
374
|
-
if (scripts === null || !isNonEmptyString(scripts[
|
|
266
|
+
for (const requirement of PUBLIC_PACKAGE_POLICY.requiredScripts) {
|
|
267
|
+
if (scripts === null || !isNonEmptyString(scripts[requirement.name])) {
|
|
375
268
|
diagnostics.push(createDiagnostic({
|
|
376
269
|
code: 'missing-script',
|
|
377
|
-
message: `Missing required package script: ${
|
|
270
|
+
message: `Missing required package script: ${requirement.name}`,
|
|
378
271
|
path: request.packageJsonPath,
|
|
379
272
|
profile: request.profile,
|
|
380
|
-
ruleId
|
|
381
|
-
severity: 'error',
|
|
273
|
+
...architecturePolicyRuleFields(requirement.ruleId),
|
|
382
274
|
}));
|
|
383
275
|
}
|
|
384
276
|
}
|
|
@@ -392,8 +284,7 @@ async function analyzePackagePolicy(request) {
|
|
|
392
284
|
message: 'Public package repos must declare TypeScript in dependencies or devDependencies.',
|
|
393
285
|
path: request.packageJsonPath,
|
|
394
286
|
profile: request.profile,
|
|
395
|
-
|
|
396
|
-
severity: 'error',
|
|
287
|
+
...architecturePolicyRuleFields(PUBLIC_PACKAGE_POLICY.dependencyRules.typescript),
|
|
397
288
|
}));
|
|
398
289
|
}
|
|
399
290
|
const changesetsDependencyDiagnostic = createChangesetsDependencyDiagnostic({
|
|
@@ -412,8 +303,7 @@ async function analyzePackagePolicy(request) {
|
|
|
412
303
|
message: 'Public package repos must declare @types/bun in devDependencies.',
|
|
413
304
|
path: request.packageJsonPath,
|
|
414
305
|
profile: request.profile,
|
|
415
|
-
|
|
416
|
-
severity: 'error',
|
|
306
|
+
...architecturePolicyRuleFields(PUBLIC_PACKAGE_POLICY.dependencyRules.bunTypes),
|
|
417
307
|
}));
|
|
418
308
|
}
|
|
419
309
|
if (!hasDependency(devDependencies, '@types/node')) {
|
|
@@ -422,8 +312,7 @@ async function analyzePackagePolicy(request) {
|
|
|
422
312
|
message: 'Public package repos must declare @types/node in devDependencies.',
|
|
423
313
|
path: request.packageJsonPath,
|
|
424
314
|
profile: request.profile,
|
|
425
|
-
|
|
426
|
-
severity: 'error',
|
|
315
|
+
...architecturePolicyRuleFields(PUBLIC_PACKAGE_POLICY.dependencyRules.nodeTypes),
|
|
427
316
|
}));
|
|
428
317
|
}
|
|
429
318
|
if (expectsDevtools(packageJson) && !hasDependency(devDependencies, '@ankhorage/devtools')) {
|
|
@@ -432,8 +321,7 @@ async function analyzePackagePolicy(request) {
|
|
|
432
321
|
message: 'This package consumes shared Ankhorage lint/format/knip tooling and must declare @ankhorage/devtools.',
|
|
433
322
|
path: request.packageJsonPath,
|
|
434
323
|
profile: request.profile,
|
|
435
|
-
|
|
436
|
-
severity: 'error',
|
|
324
|
+
...architecturePolicyRuleFields(PUBLIC_PACKAGE_POLICY.dependencyRules.devtools),
|
|
437
325
|
}));
|
|
438
326
|
}
|
|
439
327
|
if (packageJson.name !== '@ankhorage/paradox' &&
|
|
@@ -444,8 +332,7 @@ async function analyzePackagePolicy(request) {
|
|
|
444
332
|
message: 'This package owns Paradox docs generation and must declare @ankhorage/paradox.',
|
|
445
333
|
path: request.packageJsonPath,
|
|
446
334
|
profile: request.profile,
|
|
447
|
-
|
|
448
|
-
severity: 'error',
|
|
335
|
+
...architecturePolicyRuleFields(PUBLIC_PACKAGE_POLICY.dependencyRules.paradox),
|
|
449
336
|
}));
|
|
450
337
|
}
|
|
451
338
|
return diagnostics.concat(await validateAnkhMetadataAndProvider({
|
|
@@ -474,8 +361,7 @@ function createChangesetsDependencyDiagnostic(request) {
|
|
|
474
361
|
: 'Public package repos must not declare @changesets/cli directly; @ankhorage/devtools owns Changesets execution.',
|
|
475
362
|
path: request.packageJsonPath,
|
|
476
363
|
profile: request.profile,
|
|
477
|
-
|
|
478
|
-
severity: 'error',
|
|
364
|
+
...architecturePolicyRuleFields(PUBLIC_PACKAGE_POLICY.dependencyRules.changesets),
|
|
479
365
|
});
|
|
480
366
|
}
|
|
481
367
|
async function validateAnkhMetadataAndProvider(request) {
|
|
@@ -731,6 +617,30 @@ async function isProviderPackage(targetPath) {
|
|
|
731
617
|
}
|
|
732
618
|
return false;
|
|
733
619
|
}
|
|
620
|
+
/*** Validate every generic public-package metadata field from canonical Policy. */
|
|
621
|
+
function requirePublicPackageFields(request) {
|
|
622
|
+
for (const requirement of PUBLIC_PACKAGE_POLICY.requiredFields) {
|
|
623
|
+
const input = {
|
|
624
|
+
diagnostics: request.diagnostics,
|
|
625
|
+
fieldName: requirement.name,
|
|
626
|
+
packageJson: request.packageJson,
|
|
627
|
+
packageJsonPath: request.packageJsonPath,
|
|
628
|
+
profile: request.profile,
|
|
629
|
+
ruleId: requirement.ruleId,
|
|
630
|
+
};
|
|
631
|
+
switch (requirement.kind) {
|
|
632
|
+
case 'non-empty-string':
|
|
633
|
+
requireNonEmptyStringField(input);
|
|
634
|
+
break;
|
|
635
|
+
case 'record':
|
|
636
|
+
requireRecordField(input);
|
|
637
|
+
break;
|
|
638
|
+
case 'string-array':
|
|
639
|
+
requireStringArrayField(input);
|
|
640
|
+
break;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
734
644
|
async function maybeRequirePath(diagnostics, plannedChanges, rootPath, relativePath, ruleId, kind) {
|
|
735
645
|
const absolutePath = path.join(rootPath, relativePath);
|
|
736
646
|
if (await pathExists(absolutePath)) {
|
|
@@ -741,8 +651,7 @@ async function maybeRequirePath(diagnostics, plannedChanges, rootPath, relativeP
|
|
|
741
651
|
message: `Missing expected repo artifact: ${relativePath}`,
|
|
742
652
|
path: absolutePath,
|
|
743
653
|
profile: 'public-package',
|
|
744
|
-
ruleId,
|
|
745
|
-
severity: 'error',
|
|
654
|
+
...architecturePolicyRuleFields(ruleId),
|
|
746
655
|
}));
|
|
747
656
|
plannedChanges.push(createPlannedChange({
|
|
748
657
|
description: `Create missing ${relativePath}.`,
|
|
@@ -760,8 +669,7 @@ function requireNonEmptyStringField(request) {
|
|
|
760
669
|
message: `package.json must define a non-empty "${request.fieldName}" field.`,
|
|
761
670
|
path: request.packageJsonPath,
|
|
762
671
|
profile: request.profile,
|
|
763
|
-
|
|
764
|
-
severity: 'error',
|
|
672
|
+
...architecturePolicyRuleFields(request.ruleId),
|
|
765
673
|
}));
|
|
766
674
|
}
|
|
767
675
|
function requireRecordField(request) {
|
|
@@ -773,8 +681,7 @@ function requireRecordField(request) {
|
|
|
773
681
|
message: `package.json must define an object "${request.fieldName}" field.`,
|
|
774
682
|
path: request.packageJsonPath,
|
|
775
683
|
profile: request.profile,
|
|
776
|
-
|
|
777
|
-
severity: 'error',
|
|
684
|
+
...architecturePolicyRuleFields(request.ruleId),
|
|
778
685
|
}));
|
|
779
686
|
}
|
|
780
687
|
function requireStringArrayField(request) {
|
|
@@ -786,8 +693,7 @@ function requireStringArrayField(request) {
|
|
|
786
693
|
message: `package.json must define a non-empty string array "${request.fieldName}" field.`,
|
|
787
694
|
path: request.packageJsonPath,
|
|
788
695
|
profile: request.profile,
|
|
789
|
-
|
|
790
|
-
severity: 'error',
|
|
696
|
+
...architecturePolicyRuleFields(request.ruleId),
|
|
791
697
|
}));
|
|
792
698
|
}
|
|
793
699
|
async function expectsParadox(targetPath, packageJson) {
|
|
@@ -835,36 +741,6 @@ function validateAnkhMetadataShape(value, providerPackage) {
|
|
|
835
741
|
}
|
|
836
742
|
return null;
|
|
837
743
|
}
|
|
838
|
-
function mapScriptRule(scriptName) {
|
|
839
|
-
switch (scriptName) {
|
|
840
|
-
case 'build':
|
|
841
|
-
return 'package.scripts.build.required';
|
|
842
|
-
case 'typecheck':
|
|
843
|
-
return 'package.scripts.typecheck.required';
|
|
844
|
-
case 'lint':
|
|
845
|
-
return 'package.scripts.lint.required';
|
|
846
|
-
case 'lint:fix':
|
|
847
|
-
return 'package.scripts.lint-fix.required';
|
|
848
|
-
case 'format':
|
|
849
|
-
return 'package.scripts.format.required';
|
|
850
|
-
case 'format:check':
|
|
851
|
-
return 'package.scripts.format-check.required';
|
|
852
|
-
case 'test':
|
|
853
|
-
return 'package.scripts.test.required';
|
|
854
|
-
case 'test:standalone':
|
|
855
|
-
return 'package.scripts.standalone.required';
|
|
856
|
-
case 'knip:check':
|
|
857
|
-
return 'package.scripts.knip.required';
|
|
858
|
-
case 'docs':
|
|
859
|
-
return 'package.scripts.docs.required';
|
|
860
|
-
case 'changeset':
|
|
861
|
-
return 'package.scripts.changeset.required';
|
|
862
|
-
case 'changeset:status':
|
|
863
|
-
return 'package.scripts.changeset-status.required';
|
|
864
|
-
case 'version-packages':
|
|
865
|
-
return 'package.scripts.version-packages.required';
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
744
|
function createEarlyResult(targetPath, diagnostic) {
|
|
869
745
|
return {
|
|
870
746
|
appliedChecks: [],
|
|
@@ -877,6 +753,11 @@ function createEarlyResult(targetPath, diagnostic) {
|
|
|
877
753
|
targetPath,
|
|
878
754
|
};
|
|
879
755
|
}
|
|
756
|
+
/*** Return canonical rule id and severity for a Policy-owned generic package rule. */
|
|
757
|
+
function architecturePolicyRuleFields(ruleId) {
|
|
758
|
+
const rule = getArchitecturePolicyRule(ruleId);
|
|
759
|
+
return { ruleId: rule.id, severity: rule.severity };
|
|
760
|
+
}
|
|
880
761
|
function createDiagnostic(diagnostic) {
|
|
881
762
|
return diagnostic;
|
|
882
763
|
}
|