repo-contract 0.2.0 → 0.3.2
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 +50 -0
- package/README.md +47 -0
- package/dist/.dts/config/validate-config.d.ts.map +1 -1
- package/dist/.dts/errors.d.ts +17 -0
- package/dist/.dts/errors.d.ts.map +1 -1
- package/dist/.dts/evidence/build-evidence.d.ts.map +1 -1
- package/dist/.dts/index.d.ts +2 -1
- package/dist/.dts/index.d.ts.map +1 -1
- package/dist/.dts/parsing/format-schema-issues.d.ts +11 -0
- package/dist/.dts/parsing/format-schema-issues.d.ts.map +1 -0
- package/dist/.dts/parsing/parse-output.d.ts +19 -4
- package/dist/.dts/parsing/parse-output.d.ts.map +1 -1
- package/dist/.dts/standard-schema/types.d.ts +76 -0
- package/dist/.dts/standard-schema/types.d.ts.map +1 -0
- package/dist/.dts/types.d.ts +44 -11
- package/dist/.dts/types.d.ts.map +1 -1
- package/dist/index.cjs +99 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +99 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/schemas/evidence.schema.json +2 -2
- package/src/config/validate-config.ts +55 -1
- package/src/errors.ts +26 -0
- package/src/evidence/build-evidence.ts +6 -1
- package/src/index.ts +3 -0
- package/src/parsing/format-schema-issues.ts +56 -0
- package/src/parsing/parse-output.ts +50 -3
- package/src/standard-schema/types.ts +93 -0
- package/src/types.ts +48 -12
package/dist/index.js
CHANGED
|
@@ -74,6 +74,20 @@ var ParserDependencyMissingError = class extends RepoContractError {
|
|
|
74
74
|
this.format = format;
|
|
75
75
|
}
|
|
76
76
|
};
|
|
77
|
+
var StandardSchemaValidateThrewError = class extends RepoContractError {
|
|
78
|
+
/** Always `"REPO_CONTRACT_STANDARD_SCHEMA_VALIDATE_THREW"`. */
|
|
79
|
+
code = "REPO_CONTRACT_STANDARD_SCHEMA_VALIDATE_THREW";
|
|
80
|
+
/** The id of the check whose `output.schema` threw during validation. */
|
|
81
|
+
checkId;
|
|
82
|
+
constructor(checkId, cause) {
|
|
83
|
+
super(
|
|
84
|
+
`Check "${checkId}"'s output.schema["~standard"].validate() threw instead of returning a Result`,
|
|
85
|
+
{ cause }
|
|
86
|
+
);
|
|
87
|
+
this.name = "StandardSchemaValidateThrewError";
|
|
88
|
+
this.checkId = checkId;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
77
91
|
var PolicyThrewError = class extends RepoContractError {
|
|
78
92
|
/** Always `"REPO_CONTRACT_POLICY_THREW"`. */
|
|
79
93
|
code = "REPO_CONTRACT_POLICY_THREW";
|
|
@@ -358,13 +372,46 @@ function validateOutput(checkId, output) {
|
|
|
358
372
|
if (output === null || typeof output !== "object") {
|
|
359
373
|
throw new InvalidCheckConfigError(checkId, "output must be an object when provided.");
|
|
360
374
|
}
|
|
361
|
-
const { format } = output;
|
|
375
|
+
const { format, schema } = output;
|
|
362
376
|
if (typeof format !== "string" || !OUTPUT_FORMATS.includes(format)) {
|
|
363
377
|
throw new InvalidCheckConfigError(
|
|
364
378
|
checkId,
|
|
365
379
|
`output.format must be one of ${OUTPUT_FORMATS.map((f) => `"${f}"`).join(", ")}.`
|
|
366
380
|
);
|
|
367
381
|
}
|
|
382
|
+
validateOutputSchema(checkId, schema);
|
|
383
|
+
}
|
|
384
|
+
function validateOutputSchema(checkId, schema) {
|
|
385
|
+
if (schema === void 0) return;
|
|
386
|
+
if (schema === null || typeof schema !== "object" && typeof schema !== "function") {
|
|
387
|
+
throw new InvalidCheckConfigError(
|
|
388
|
+
checkId,
|
|
389
|
+
"output.schema must be a Standard Schema-compliant object or function when provided (see https://standardschema.dev)."
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
const standard = schema["~standard"];
|
|
393
|
+
if (standard === null || typeof standard !== "object") {
|
|
394
|
+
throw new InvalidCheckConfigError(
|
|
395
|
+
checkId,
|
|
396
|
+
'output.schema must have a "~standard" property (see https://standardschema.dev).'
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
const { version, vendor, validate } = standard;
|
|
400
|
+
if (version !== 1) {
|
|
401
|
+
throw new InvalidCheckConfigError(checkId, 'output.schema["~standard"].version must be 1.');
|
|
402
|
+
}
|
|
403
|
+
if (typeof vendor !== "string") {
|
|
404
|
+
throw new InvalidCheckConfigError(
|
|
405
|
+
checkId,
|
|
406
|
+
'output.schema["~standard"].vendor must be a string.'
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
if (typeof validate !== "function") {
|
|
410
|
+
throw new InvalidCheckConfigError(
|
|
411
|
+
checkId,
|
|
412
|
+
'output.schema["~standard"].validate must be a function.'
|
|
413
|
+
);
|
|
414
|
+
}
|
|
368
415
|
}
|
|
369
416
|
function validatePolicy(checkId, policy) {
|
|
370
417
|
if (typeof policy !== "function") {
|
|
@@ -405,6 +452,28 @@ function validateDependencyGraph(checks) {
|
|
|
405
452
|
}
|
|
406
453
|
}
|
|
407
454
|
|
|
455
|
+
// src/parsing/format-schema-issues.ts
|
|
456
|
+
function formatSchemaIssues(issues) {
|
|
457
|
+
return `Schema validation failed: ${issues.map(formatIssue).join("; ")}`;
|
|
458
|
+
}
|
|
459
|
+
function formatIssue(issue) {
|
|
460
|
+
const path = formatPath(issue.path);
|
|
461
|
+
return path === "" ? issue.message : `${path}: ${issue.message}`;
|
|
462
|
+
}
|
|
463
|
+
function formatPath(path) {
|
|
464
|
+
if (path === void 0 || path.length === 0) return "";
|
|
465
|
+
return path.map(
|
|
466
|
+
(segment) => (
|
|
467
|
+
// eslint-disable-next-line secure-coding/no-improper-type-validation -- `segment` is declared `PropertyKey | StandardSchemaV1.PathSegment` (never `null` or an array), so `typeof segment === "object"` can only match the `PathSegment` object form here; the null/array-safe rewrite this rule suggests is flagged as an unreachable condition by @typescript-eslint/no-unnecessary-condition given that exact type, so satisfying both rules at once is impossible -- the type itself is the guarantee this check would otherwise add at runtime.
|
|
468
|
+
typeof segment === "object" ? segment.key : segment
|
|
469
|
+
)
|
|
470
|
+
).map((key, index) => {
|
|
471
|
+
if (typeof key === "number") return `[${String(key)}]`;
|
|
472
|
+
const rendered = String(key);
|
|
473
|
+
return index === 0 ? rendered : `.${rendered}`;
|
|
474
|
+
}).join("");
|
|
475
|
+
}
|
|
476
|
+
|
|
408
477
|
// src/parsing/parse-json.ts
|
|
409
478
|
function parseJson(stdout) {
|
|
410
479
|
try {
|
|
@@ -443,7 +512,24 @@ async function parseYaml(stdout, checkId) {
|
|
|
443
512
|
}
|
|
444
513
|
|
|
445
514
|
// src/parsing/parse-output.ts
|
|
446
|
-
async function parseOutput(format, stdout, checkId) {
|
|
515
|
+
async function parseOutput(format, stdout, checkId, schema) {
|
|
516
|
+
const parsed = await dispatch(format, stdout, checkId);
|
|
517
|
+
if (!parsed.success || schema === void 0) return parsed;
|
|
518
|
+
let result;
|
|
519
|
+
try {
|
|
520
|
+
result = await schema["~standard"].validate(parsed.value);
|
|
521
|
+
if (typeof result !== "object" || result === null) {
|
|
522
|
+
throw new TypeError(`validate() returned ${String(result)} instead of a Result object`);
|
|
523
|
+
}
|
|
524
|
+
} catch (error) {
|
|
525
|
+
throw new StandardSchemaValidateThrewError(checkId, error);
|
|
526
|
+
}
|
|
527
|
+
if (result.issues === void 0) {
|
|
528
|
+
return { format, success: true, value: result.value };
|
|
529
|
+
}
|
|
530
|
+
return { format, success: false, error: formatSchemaIssues(result.issues) };
|
|
531
|
+
}
|
|
532
|
+
async function dispatch(format, stdout, checkId) {
|
|
447
533
|
switch (format) {
|
|
448
534
|
case "json":
|
|
449
535
|
return parseJson(stdout);
|
|
@@ -461,7 +547,12 @@ async function buildEvidence(results, startedAt, completedAt) {
|
|
|
461
547
|
results.map(async ([checkId, check, raw]) => {
|
|
462
548
|
if (check.output === void 0) return [checkId, check, raw];
|
|
463
549
|
try {
|
|
464
|
-
const output = await parseOutput(
|
|
550
|
+
const output = await parseOutput(
|
|
551
|
+
check.output.format,
|
|
552
|
+
raw.stdout,
|
|
553
|
+
checkId,
|
|
554
|
+
check.output.schema
|
|
555
|
+
);
|
|
465
556
|
return [checkId, check, { ...raw, output }];
|
|
466
557
|
} catch (error) {
|
|
467
558
|
thrown.push(error);
|
|
@@ -474,7 +565,10 @@ async function buildEvidence(results, startedAt, completedAt) {
|
|
|
474
565
|
throw only;
|
|
475
566
|
}
|
|
476
567
|
if (thrown.length > 1) {
|
|
477
|
-
throw new AggregateError(
|
|
568
|
+
throw new AggregateError(
|
|
569
|
+
thrown,
|
|
570
|
+
`${String(thrown.length)} check output(s) failed during output processing.`
|
|
571
|
+
);
|
|
478
572
|
}
|
|
479
573
|
const evidence = {
|
|
480
574
|
version: 1,
|
|
@@ -1066,6 +1160,6 @@ async function runRepoContractAfterValidation(config, options) {
|
|
|
1066
1160
|
return { evidence, verdict };
|
|
1067
1161
|
}
|
|
1068
1162
|
|
|
1069
|
-
export { DependencyDeclaredLaterError, InvalidCheckConfigError, InvalidRepoContractConfigError, ParserDependencyMissingError, PolicyReadFailedParseValueError, PolicyReadUnrequestedOutputError, PolicyThrewError, RepoContractError, UnknownCheckIdError, defineRepoContract, runRepoContract };
|
|
1163
|
+
export { DependencyDeclaredLaterError, InvalidCheckConfigError, InvalidRepoContractConfigError, ParserDependencyMissingError, PolicyReadFailedParseValueError, PolicyReadUnrequestedOutputError, PolicyThrewError, RepoContractError, StandardSchemaValidateThrewError, UnknownCheckIdError, defineRepoContract, runRepoContract };
|
|
1070
1164
|
//# sourceMappingURL=index.js.map
|
|
1071
1165
|
//# sourceMappingURL=index.js.map
|