repopo 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +60 -0
- package/README.md +41 -2
- package/THIRD-PARTY-LICENSES.txt +71 -11
- package/bin/dev.js +5 -1
- package/esm/baseCommand.d.ts +1 -1
- package/esm/baseCommand.d.ts.map +1 -1
- package/esm/baseCommand.js +6 -9
- package/esm/baseCommand.js.map +1 -1
- package/esm/commands/check-native.d.ts +25 -0
- package/esm/commands/check-native.d.ts.map +1 -0
- package/esm/commands/check-native.js +137 -0
- package/esm/commands/check-native.js.map +1 -0
- package/esm/commands/check.d.ts +8 -20
- package/esm/commands/check.d.ts.map +1 -1
- package/esm/commands/check.js +77 -186
- package/esm/commands/check.js.map +1 -1
- package/esm/commands/list.d.ts.map +1 -1
- package/esm/commands/list.js +5 -6
- package/esm/commands/list.js.map +1 -1
- package/esm/context.d.ts +13 -3
- package/esm/context.d.ts.map +1 -1
- package/esm/context.js +11 -1
- package/esm/context.js.map +1 -1
- package/esm/index.d.ts +6 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +3 -0
- package/esm/index.js.map +1 -1
- package/esm/makePolicy.d.ts +29 -2
- package/esm/makePolicy.d.ts.map +1 -1
- package/esm/makePolicy.js +46 -2
- package/esm/makePolicy.js.map +1 -1
- package/esm/perf.d.ts +7 -2
- package/esm/perf.d.ts.map +1 -1
- package/esm/perf.js.map +1 -1
- package/esm/policies/CargoLicenceValidated.d.ts +41 -0
- package/esm/policies/CargoLicenceValidated.d.ts.map +1 -0
- package/esm/policies/CargoLicenceValidated.js +45 -0
- package/esm/policies/CargoLicenceValidated.js.map +1 -0
- package/esm/policies/CargoLintsConfigured.d.ts +30 -0
- package/esm/policies/CargoLintsConfigured.d.ts.map +1 -0
- package/esm/policies/CargoLintsConfigured.js +61 -0
- package/esm/policies/CargoLintsConfigured.js.map +1 -0
- package/esm/policies/CargoLockPolicy.d.ts +34 -0
- package/esm/policies/CargoLockPolicy.d.ts.map +1 -0
- package/esm/policies/CargoLockPolicy.js +57 -0
- package/esm/policies/CargoLockPolicy.js.map +1 -0
- package/esm/policies/CargoTomlRequired.d.ts +34 -0
- package/esm/policies/CargoTomlRequired.d.ts.map +1 -0
- package/esm/policies/CargoTomlRequired.js +77 -0
- package/esm/policies/CargoTomlRequired.js.map +1 -0
- package/esm/policies/CargoTomlSorted.d.ts +20 -0
- package/esm/policies/CargoTomlSorted.d.ts.map +1 -0
- package/esm/policies/CargoTomlSorted.js +164 -0
- package/esm/policies/CargoTomlSorted.js.map +1 -0
- package/esm/policies/ConditionalScripts.d.ts.map +1 -1
- package/esm/policies/ConditionalScripts.js +3 -2
- package/esm/policies/ConditionalScripts.js.map +1 -1
- package/esm/policies/ExactScripts.d.ts.map +1 -1
- package/esm/policies/ExactScripts.js +3 -2
- package/esm/policies/ExactScripts.js.map +1 -1
- package/esm/policies/GleamDepVersions.d.ts +25 -0
- package/esm/policies/GleamDepVersions.d.ts.map +1 -0
- package/esm/policies/GleamDepVersions.js +67 -0
- package/esm/policies/GleamDepVersions.js.map +1 -0
- package/esm/policies/GleamDocExists.d.ts +24 -0
- package/esm/policies/GleamDocExists.d.ts.map +1 -0
- package/esm/policies/GleamDocExists.js +39 -0
- package/esm/policies/GleamDocExists.js.map +1 -0
- package/esm/policies/GleamInternalModulesConfigured.d.ts +21 -0
- package/esm/policies/GleamInternalModulesConfigured.d.ts.map +1 -0
- package/esm/policies/GleamInternalModulesConfigured.js +30 -0
- package/esm/policies/GleamInternalModulesConfigured.js.map +1 -0
- package/esm/policies/GleamLicenceConfigured.d.ts +29 -0
- package/esm/policies/GleamLicenceConfigured.d.ts.map +1 -0
- package/esm/policies/GleamLicenceConfigured.js +34 -0
- package/esm/policies/GleamLicenceConfigured.js.map +1 -0
- package/esm/policies/GleamManifestCommitted.d.ts +9 -0
- package/esm/policies/GleamManifestCommitted.d.ts.map +1 -0
- package/esm/policies/GleamManifestCommitted.js +26 -0
- package/esm/policies/GleamManifestCommitted.js.map +1 -0
- package/esm/policies/GleamMonorepoConsistency.d.ts +30 -0
- package/esm/policies/GleamMonorepoConsistency.d.ts.map +1 -0
- package/esm/policies/GleamMonorepoConsistency.js +74 -0
- package/esm/policies/GleamMonorepoConsistency.js.map +1 -0
- package/esm/policies/GleamNameRestrictions.d.ts +25 -0
- package/esm/policies/GleamNameRestrictions.d.ts.map +1 -0
- package/esm/policies/GleamNameRestrictions.js +44 -0
- package/esm/policies/GleamNameRestrictions.js.map +1 -0
- package/esm/policies/GleamNoPathDepsInPublished.d.ts +22 -0
- package/esm/policies/GleamNoPathDepsInPublished.d.ts.map +1 -0
- package/esm/policies/GleamNoPathDepsInPublished.js +43 -0
- package/esm/policies/GleamNoPathDepsInPublished.js.map +1 -0
- package/esm/policies/GleamPathDepsValid.d.ts +9 -0
- package/esm/policies/GleamPathDepsValid.d.ts.map +1 -0
- package/esm/policies/GleamPathDepsValid.js +59 -0
- package/esm/policies/GleamPathDepsValid.js.map +1 -0
- package/esm/policies/GleamProjectStructure.d.ts +25 -0
- package/esm/policies/GleamProjectStructure.d.ts.map +1 -0
- package/esm/policies/GleamProjectStructure.js +33 -0
- package/esm/policies/GleamProjectStructure.js.map +1 -0
- package/esm/policies/GleamSharedDependencyVersions.d.ts +29 -0
- package/esm/policies/GleamSharedDependencyVersions.d.ts.map +1 -0
- package/esm/policies/GleamSharedDependencyVersions.js +101 -0
- package/esm/policies/GleamSharedDependencyVersions.js.map +1 -0
- package/esm/policies/GleamTomlRequired.d.ts +30 -0
- package/esm/policies/GleamTomlRequired.d.ts.map +1 -0
- package/esm/policies/GleamTomlRequired.js +37 -0
- package/esm/policies/GleamTomlRequired.js.map +1 -0
- package/esm/policies/GleamTomlSorted.d.ts +20 -0
- package/esm/policies/GleamTomlSorted.d.ts.map +1 -0
- package/esm/policies/GleamTomlSorted.js +153 -0
- package/esm/policies/GleamTomlSorted.js.map +1 -0
- package/esm/policies/GleamVersionConstraint.d.ts +20 -0
- package/esm/policies/GleamVersionConstraint.d.ts.map +1 -0
- package/esm/policies/GleamVersionConstraint.js +64 -0
- package/esm/policies/GleamVersionConstraint.js.map +1 -0
- package/esm/policies/HtmlFileHeaders.js +1 -1
- package/esm/policies/HtmlFileHeaders.js.map +1 -1
- package/esm/policies/NoBuildDirectory.d.ts +9 -0
- package/esm/policies/NoBuildDirectory.d.ts.map +1 -0
- package/esm/policies/NoBuildDirectory.js +29 -0
- package/esm/policies/NoBuildDirectory.js.map +1 -0
- package/esm/policies/NoTargetArtifacts.d.ts +8 -0
- package/esm/policies/NoTargetArtifacts.d.ts.map +1 -0
- package/esm/policies/NoTargetArtifacts.js +42 -0
- package/esm/policies/NoTargetArtifacts.js.map +1 -0
- package/esm/policies/NoUnsafeWithoutJustification.d.ts +24 -0
- package/esm/policies/NoUnsafeWithoutJustification.d.ts.map +1 -0
- package/esm/policies/NoUnsafeWithoutJustification.js +80 -0
- package/esm/policies/NoUnsafeWithoutJustification.js.map +1 -0
- package/esm/policies/NoWildcardDependencies.d.ts +30 -0
- package/esm/policies/NoWildcardDependencies.d.ts.map +1 -0
- package/esm/policies/NoWildcardDependencies.js +83 -0
- package/esm/policies/NoWildcardDependencies.js.map +1 -0
- package/esm/policies/PackageEsmType.d.ts.map +1 -1
- package/esm/policies/PackageEsmType.js +7 -5
- package/esm/policies/PackageEsmType.js.map +1 -1
- package/esm/policies/PackageJsonProperties.d.ts.map +1 -1
- package/esm/policies/PackageJsonProperties.js +12 -4
- package/esm/policies/PackageJsonProperties.js.map +1 -1
- package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts.map +1 -1
- package/esm/policies/PackageJsonRepoDirectoryProperty.js +3 -2
- package/esm/policies/PackageJsonRepoDirectoryProperty.js.map +1 -1
- package/esm/policies/PackageJsonSorted.d.ts.map +1 -1
- package/esm/policies/PackageJsonSorted.js +42 -7
- package/esm/policies/PackageJsonSorted.js.map +1 -1
- package/esm/policies/PackageLicense.d.ts.map +1 -1
- package/esm/policies/PackageLicense.js +1 -2
- package/esm/policies/PackageLicense.js.map +1 -1
- package/esm/policies/PackagePrivateField.d.ts.map +1 -1
- package/esm/policies/PackagePrivateField.js +3 -2
- package/esm/policies/PackagePrivateField.js.map +1 -1
- package/esm/policies/PackageReadme.js +2 -2
- package/esm/policies/PackageReadme.js.map +1 -1
- package/esm/policies/PackageScripts.d.ts.map +1 -1
- package/esm/policies/PackageScripts.js +3 -2
- package/esm/policies/PackageScripts.js.map +1 -1
- package/esm/policies/PackageTestScripts.js +3 -3
- package/esm/policies/PackageTestScripts.js.map +1 -1
- package/esm/policies/PublicApiDocumented.d.ts +21 -0
- package/esm/policies/PublicApiDocumented.d.ts.map +1 -0
- package/esm/policies/PublicApiDocumented.js +36 -0
- package/esm/policies/PublicApiDocumented.js.map +1 -0
- package/esm/policies/RequiredScripts.d.ts.map +1 -1
- package/esm/policies/RequiredScripts.js +3 -2
- package/esm/policies/RequiredScripts.js.map +1 -1
- package/esm/policies/RustDocExists.d.ts +24 -0
- package/esm/policies/RustDocExists.d.ts.map +1 -0
- package/esm/policies/RustDocExists.js +49 -0
- package/esm/policies/RustDocExists.js.map +1 -0
- package/esm/policies/RustToolchainExists.d.ts +20 -0
- package/esm/policies/RustToolchainExists.d.ts.map +1 -0
- package/esm/policies/RustToolchainExists.js +27 -0
- package/esm/policies/RustToolchainExists.js.map +1 -0
- package/esm/policies/RustfmtConfigExists.d.ts +20 -0
- package/esm/policies/RustfmtConfigExists.d.ts.map +1 -0
- package/esm/policies/RustfmtConfigExists.js +27 -0
- package/esm/policies/RustfmtConfigExists.js.map +1 -0
- package/esm/policies/SharedDependencyVersions.d.ts +24 -0
- package/esm/policies/SharedDependencyVersions.d.ts.map +1 -0
- package/esm/policies/SharedDependencyVersions.js +135 -0
- package/esm/policies/SharedDependencyVersions.js.map +1 -0
- package/esm/policies/WorkspaceInheritance.d.ts +24 -0
- package/esm/policies/WorkspaceInheritance.d.ts.map +1 -0
- package/esm/policies/WorkspaceInheritance.js +94 -0
- package/esm/policies/WorkspaceInheritance.js.map +1 -0
- package/esm/policies/WorkspaceMembersValid.d.ts +20 -0
- package/esm/policies/WorkspaceMembersValid.d.ts.map +1 -0
- package/esm/policies/WorkspaceMembersValid.js +88 -0
- package/esm/policies/WorkspaceMembersValid.js.map +1 -0
- package/esm/policies/constants.d.ts +8 -0
- package/esm/policies/constants.d.ts.map +1 -1
- package/esm/policies/constants.js +8 -0
- package/esm/policies/constants.js.map +1 -1
- package/esm/policies.d.ts +30 -0
- package/esm/policies.d.ts.map +1 -1
- package/esm/policies.js +51 -1
- package/esm/policies.js.map +1 -1
- package/esm/policy.d.ts +24 -0
- package/esm/policy.d.ts.map +1 -1
- package/esm/policy.js.map +1 -1
- package/esm/policyDefiners/defineCargoPolicy.d.ts +66 -0
- package/esm/policyDefiners/defineCargoPolicy.d.ts.map +1 -0
- package/esm/policyDefiners/defineCargoPolicy.js +60 -0
- package/esm/policyDefiners/defineCargoPolicy.js.map +1 -0
- package/esm/policyDefiners/defineFileHeaderPolicy.d.ts.map +1 -1
- package/esm/policyDefiners/defineFileHeaderPolicy.js +6 -7
- package/esm/policyDefiners/defineFileHeaderPolicy.js.map +1 -1
- package/esm/policyDefiners/defineGleamPolicy.d.ts +65 -0
- package/esm/policyDefiners/defineGleamPolicy.d.ts.map +1 -0
- package/esm/policyDefiners/defineGleamPolicy.js +59 -0
- package/esm/policyDefiners/defineGleamPolicy.js.map +1 -0
- package/esm/policyDefiners/spdxValidator.d.ts +74 -0
- package/esm/policyDefiners/spdxValidator.d.ts.map +1 -0
- package/esm/policyDefiners/spdxValidator.js +127 -0
- package/esm/policyDefiners/spdxValidator.js.map +1 -0
- package/esm/policyDefiners/tomlParser.d.ts +8 -0
- package/esm/policyDefiners/tomlParser.d.ts.map +1 -0
- package/esm/policyDefiners/tomlParser.js +17 -0
- package/esm/policyDefiners/tomlParser.js.map +1 -0
- package/esm/runner.d.ts +60 -0
- package/esm/runner.d.ts.map +1 -0
- package/esm/runner.js +174 -0
- package/esm/runner.js.map +1 -0
- package/esm/tsdoc-metadata.json +1 -1
- package/oclif.manifest.json +100 -3
- package/package.json +46 -31
- package/scripts/postinstall.mjs +154 -0
- package/sidecar/sidecar.mjs +468 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
/**
|
|
3
|
+
* Lazily load spdx-correct. It's an optional peer dependency.
|
|
4
|
+
*
|
|
5
|
+
* @returns The corrected identifier, `null` if unrecognized, or `undefined` if
|
|
6
|
+
* spdx-correct is not installed.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export async function tryCorrectLicence(licence) {
|
|
11
|
+
try {
|
|
12
|
+
const mod = (await import("spdx-correct"));
|
|
13
|
+
const correct = mod.default ?? mod;
|
|
14
|
+
return correct(licence);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Validate an array of licence identifiers using spdx-correct.
|
|
22
|
+
*
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
export async function validateWithSpdxCorrect(licences) {
|
|
26
|
+
const errors = [];
|
|
27
|
+
const corrections = new Map();
|
|
28
|
+
for (const licence of licences) {
|
|
29
|
+
const corrected = await tryCorrectLicence(licence);
|
|
30
|
+
if (corrected === undefined) {
|
|
31
|
+
errors.push(`Cannot validate "${licence}": spdx-correct is not installed. Install it with: pnpm add spdx-correct`);
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
if (corrected === null) {
|
|
35
|
+
errors.push(`Licence "${licence}" is not a recognized SPDX identifier`);
|
|
36
|
+
}
|
|
37
|
+
else if (corrected !== licence) {
|
|
38
|
+
corrections.set(licence, corrected);
|
|
39
|
+
errors.push(`Licence "${licence}" should be "${corrected}"`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return { errors, corrections };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Check that all licence identifiers are in the allowed list.
|
|
46
|
+
*
|
|
47
|
+
* @internal
|
|
48
|
+
*/
|
|
49
|
+
export function validateAllowlist(licences, allowedLicences) {
|
|
50
|
+
const errors = [];
|
|
51
|
+
for (const licence of licences) {
|
|
52
|
+
if (!allowedLicences.includes(licence)) {
|
|
53
|
+
errors.push(`Licence "${licence}" is not in the allowed list: ${allowedLicences.join(", ")}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return errors;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Replace quoted licence strings in TOML/text content with their corrected forms.
|
|
60
|
+
*
|
|
61
|
+
* @internal
|
|
62
|
+
*/
|
|
63
|
+
export function applyCorrections(content, corrections) {
|
|
64
|
+
let result = content;
|
|
65
|
+
for (const [original, corrected] of corrections) {
|
|
66
|
+
result = result.replace(`"${original}"`, `"${corrected}"`);
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Read a file, apply licence corrections, and write it back.
|
|
72
|
+
*
|
|
73
|
+
* @internal
|
|
74
|
+
*/
|
|
75
|
+
export async function tryAutoFix(filePath, corrections, errors) {
|
|
76
|
+
try {
|
|
77
|
+
const content = await readFile(filePath, "utf-8");
|
|
78
|
+
const fixed = applyCorrections(content, corrections);
|
|
79
|
+
await writeFile(filePath, fixed);
|
|
80
|
+
return { error: errors.join("; "), fixable: true, fixed: true };
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return {
|
|
84
|
+
error: `${errors.join("; ")}. Auto-fix failed.`,
|
|
85
|
+
fixable: true,
|
|
86
|
+
fixed: false,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Validate licence identifiers and optionally auto-fix them.
|
|
92
|
+
*
|
|
93
|
+
* Combines spdx-correct validation with allowlist checking and auto-fix
|
|
94
|
+
* into a single helper used by both Cargo and Gleam licence policies.
|
|
95
|
+
*
|
|
96
|
+
* @returns `true` if valid, or a PolicyError-compatible object on failure.
|
|
97
|
+
* Returns `undefined` if no validation was requested (both allowlist and
|
|
98
|
+
* validateSpdx are empty/false).
|
|
99
|
+
*
|
|
100
|
+
* @internal
|
|
101
|
+
*/
|
|
102
|
+
export async function validateLicenceField(options) {
|
|
103
|
+
const { licences, allowedLicences, validateSpdx, shouldResolve, filePath, manualFixMessage, } = options;
|
|
104
|
+
// Check allowlist first (takes priority)
|
|
105
|
+
if (allowedLicences) {
|
|
106
|
+
const errors = validateAllowlist(licences, allowedLicences);
|
|
107
|
+
if (errors.length > 0) {
|
|
108
|
+
return { error: errors.join("; "), manualFix: manualFixMessage };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Validate with spdx-correct
|
|
112
|
+
if (validateSpdx) {
|
|
113
|
+
const { errors, corrections } = await validateWithSpdxCorrect(licences);
|
|
114
|
+
if (errors.length > 0) {
|
|
115
|
+
if (shouldResolve && corrections.size > 0) {
|
|
116
|
+
return tryAutoFix(filePath, corrections, errors);
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
error: errors.join("; "),
|
|
120
|
+
fixable: corrections.size > 0,
|
|
121
|
+
manualFix: manualFixMessage,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=spdxValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spdxValidator.js","sourceRoot":"","sources":["../../src/policyDefiners/spdxValidator.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\n\n/**\n * Lazily load spdx-correct. It's an optional peer dependency.\n *\n * @returns The corrected identifier, `null` if unrecognized, or `undefined` if\n * spdx-correct is not installed.\n *\n * @internal\n */\nexport async function tryCorrectLicence(\n\tlicence: string,\n): Promise<string | null | undefined> {\n\ttry {\n\t\tconst mod = (await import(\"spdx-correct\")) as {\n\t\t\tdefault?: (id: string) => string | null;\n\t\t};\n\t\tconst correct =\n\t\t\tmod.default ?? (mod as unknown as (id: string) => string | null);\n\t\treturn correct(licence);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Result of validating licence identifiers with spdx-correct.\n *\n * @internal\n */\nexport interface LicenceValidationResult {\n\t/** Human-readable error messages. */\n\terrors: string[];\n\t/** Map from original identifier to its corrected form. */\n\tcorrections: Map<string, string>;\n}\n\n/**\n * Validate an array of licence identifiers using spdx-correct.\n *\n * @internal\n */\nexport async function validateWithSpdxCorrect(\n\tlicences: string[],\n): Promise<LicenceValidationResult> {\n\tconst errors: string[] = [];\n\tconst corrections = new Map<string, string>();\n\n\tfor (const licence of licences) {\n\t\tconst corrected = await tryCorrectLicence(licence);\n\t\tif (corrected === undefined) {\n\t\t\terrors.push(\n\t\t\t\t`Cannot validate \"${licence}\": spdx-correct is not installed. Install it with: pnpm add spdx-correct`,\n\t\t\t);\n\t\t\tbreak;\n\t\t}\n\t\tif (corrected === null) {\n\t\t\terrors.push(`Licence \"${licence}\" is not a recognized SPDX identifier`);\n\t\t} else if (corrected !== licence) {\n\t\t\tcorrections.set(licence, corrected);\n\t\t\terrors.push(`Licence \"${licence}\" should be \"${corrected}\"`);\n\t\t}\n\t}\n\n\treturn { errors, corrections };\n}\n\n/**\n * Check that all licence identifiers are in the allowed list.\n *\n * @internal\n */\nexport function validateAllowlist(\n\tlicences: string[],\n\tallowedLicences: string[],\n): string[] {\n\tconst errors: string[] = [];\n\tfor (const licence of licences) {\n\t\tif (!allowedLicences.includes(licence)) {\n\t\t\terrors.push(\n\t\t\t\t`Licence \"${licence}\" is not in the allowed list: ${allowedLicences.join(\", \")}`,\n\t\t\t);\n\t\t}\n\t}\n\treturn errors;\n}\n\n/**\n * Replace quoted licence strings in TOML/text content with their corrected forms.\n *\n * @internal\n */\nexport function applyCorrections(\n\tcontent: string,\n\tcorrections: Map<string, string>,\n): string {\n\tlet result = content;\n\tfor (const [original, corrected] of corrections) {\n\t\tresult = result.replace(`\"${original}\"`, `\"${corrected}\"`);\n\t}\n\treturn result;\n}\n\n/**\n * Read a file, apply licence corrections, and write it back.\n *\n * @internal\n */\nexport async function tryAutoFix(\n\tfilePath: string,\n\tcorrections: Map<string, string>,\n\terrors: string[],\n): Promise<{ error: string; fixable: boolean; fixed: boolean }> {\n\ttry {\n\t\tconst content = await readFile(filePath, \"utf-8\");\n\t\tconst fixed = applyCorrections(content, corrections);\n\t\tawait writeFile(filePath, fixed);\n\t\treturn { error: errors.join(\"; \"), fixable: true, fixed: true };\n\t} catch {\n\t\treturn {\n\t\t\terror: `${errors.join(\"; \")}. Auto-fix failed.`,\n\t\t\tfixable: true,\n\t\t\tfixed: false,\n\t\t};\n\t}\n}\n\n/**\n * Validate licence identifiers and optionally auto-fix them.\n *\n * Combines spdx-correct validation with allowlist checking and auto-fix\n * into a single helper used by both Cargo and Gleam licence policies.\n *\n * @returns `true` if valid, or a PolicyError-compatible object on failure.\n * Returns `undefined` if no validation was requested (both allowlist and\n * validateSpdx are empty/false).\n *\n * @internal\n */\nexport async function validateLicenceField(options: {\n\tlicences: string[];\n\tallowedLicences?: string[];\n\tvalidateSpdx: boolean;\n\tshouldResolve: boolean;\n\tfilePath: string;\n\tmanualFixMessage: string;\n}): Promise<\n\t| true\n\t| { error: string; fixable?: boolean; fixed?: boolean; manualFix?: string }\n\t| undefined\n> {\n\tconst {\n\t\tlicences,\n\t\tallowedLicences,\n\t\tvalidateSpdx,\n\t\tshouldResolve,\n\t\tfilePath,\n\t\tmanualFixMessage,\n\t} = options;\n\n\t// Check allowlist first (takes priority)\n\tif (allowedLicences) {\n\t\tconst errors = validateAllowlist(licences, allowedLicences);\n\t\tif (errors.length > 0) {\n\t\t\treturn { error: errors.join(\"; \"), manualFix: manualFixMessage };\n\t\t}\n\t}\n\n\t// Validate with spdx-correct\n\tif (validateSpdx) {\n\t\tconst { errors, corrections } = await validateWithSpdxCorrect(licences);\n\t\tif (errors.length > 0) {\n\t\t\tif (shouldResolve && corrections.size > 0) {\n\t\t\t\treturn tryAutoFix(filePath, corrections, errors);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\terror: errors.join(\"; \"),\n\t\t\t\tfixable: corrections.size > 0,\n\t\t\t\tmanualFix: manualFixMessage,\n\t\t\t};\n\t\t}\n\t}\n\n\treturn undefined;\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazily load smol-toml. It's an optional peer dependency, so we import
|
|
3
|
+
* dynamically and surface a clear error when it isn't installed.
|
|
4
|
+
*
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseToml(content: string): Promise<Record<string, unknown>>;
|
|
8
|
+
//# sourceMappingURL=tomlParser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tomlParser.d.ts","sourceRoot":"","sources":["../../src/policyDefiners/tomlParser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAsB,SAAS,CAC9B,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAUlC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazily load smol-toml. It's an optional peer dependency, so we import
|
|
3
|
+
* dynamically and surface a clear error when it isn't installed.
|
|
4
|
+
*
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export async function parseToml(content) {
|
|
8
|
+
try {
|
|
9
|
+
const { parse } = await import("smol-toml");
|
|
10
|
+
return parse(content);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
throw new Error("smol-toml is required for TOML-based policies but is not installed. " +
|
|
14
|
+
"Install it with: pnpm add smol-toml");
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=tomlParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tomlParser.js","sourceRoot":"","sources":["../../src/policyDefiners/tomlParser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC9B,OAAe;IAEf,IAAI,CAAC;QACJ,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAC5C,OAAO,KAAK,CAAC,OAAO,CAA4B,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,KAAK,CACd,sEAAsE;YACrE,qCAAqC,CACtC,CAAC;IACH,CAAC;AACF,CAAC","sourcesContent":["/**\n * Lazily load smol-toml. It's an optional peer dependency, so we import\n * dynamically and surface a clear error when it isn't installed.\n *\n * @internal\n */\nexport async function parseToml(\n\tcontent: string,\n): Promise<Record<string, unknown>> {\n\ttry {\n\t\tconst { parse } = await import(\"smol-toml\");\n\t\treturn parse(content) as Record<string, unknown>;\n\t} catch {\n\t\tthrow new Error(\n\t\t\t\"smol-toml is required for TOML-based policies but is not installed. \" +\n\t\t\t\t\"Install it with: pnpm add smol-toml\",\n\t\t);\n\t}\n}\n"]}
|
package/esm/runner.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Logger } from "@tylerbu/cli-api";
|
|
2
|
+
import { type Operation } from "effection";
|
|
3
|
+
import { type ExcludedPolicyFileMap } from "./context.js";
|
|
4
|
+
import { type PolicyHandlerPerfStats } from "./perf.js";
|
|
5
|
+
import type { PolicyFixResult, PolicyHandlerResult, PolicyInstance, PolicyInstanceId, PolicyName } from "./policy.js";
|
|
6
|
+
/**
|
|
7
|
+
* Result of running a single policy on a single file.
|
|
8
|
+
* @alpha
|
|
9
|
+
*/
|
|
10
|
+
export interface PolicyFileResult {
|
|
11
|
+
file: string;
|
|
12
|
+
policy: PolicyName;
|
|
13
|
+
/** Stable identity of the configured policy instance */
|
|
14
|
+
policyId: PolicyInstanceId;
|
|
15
|
+
/** The raw result from the policy handler */
|
|
16
|
+
outcome: PolicyHandlerResult;
|
|
17
|
+
/** Set when a standalone resolver was attempted (legacy resolver path) */
|
|
18
|
+
resolution?: PolicyFixResult;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Aggregated results from a full policy run.
|
|
22
|
+
* @alpha
|
|
23
|
+
*/
|
|
24
|
+
export interface PolicyRunResults {
|
|
25
|
+
results: PolicyFileResult[];
|
|
26
|
+
perfStats: PolicyHandlerPerfStats;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Options for configuring a {@link PolicyRunner}.
|
|
30
|
+
* @alpha
|
|
31
|
+
*/
|
|
32
|
+
export interface PolicyRunnerOptions {
|
|
33
|
+
policies: PolicyInstance[];
|
|
34
|
+
excludeFromAll: RegExp[];
|
|
35
|
+
excludePoliciesForFiles: ExcludedPolicyFileMap;
|
|
36
|
+
gitRoot: string;
|
|
37
|
+
resolve: boolean;
|
|
38
|
+
logger?: Pick<Logger, "verbose">;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Runs configured policies against files and collects results.
|
|
42
|
+
* @alpha
|
|
43
|
+
*/
|
|
44
|
+
export declare class PolicyRunner {
|
|
45
|
+
private readonly policies;
|
|
46
|
+
private readonly excludeFromAll;
|
|
47
|
+
private readonly excludePoliciesForFiles;
|
|
48
|
+
private readonly gitRoot;
|
|
49
|
+
private readonly resolve;
|
|
50
|
+
private readonly logger;
|
|
51
|
+
constructor(options: PolicyRunnerOptions);
|
|
52
|
+
run(filePaths: string[]): Operation<PolicyRunResults>;
|
|
53
|
+
private checkOrExcludeFile;
|
|
54
|
+
private routeToPolicies;
|
|
55
|
+
private runPolicyOnFile;
|
|
56
|
+
private isPolicyExcluded;
|
|
57
|
+
private executePolicyHandler;
|
|
58
|
+
private attemptResolution;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtD,OAAO,EAEN,KAAK,qBAAqB,EAC1B,MAAM,cAAc,CAAC;AAEtB,OAAO,EAEN,KAAK,sBAAsB,EAE3B,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAEX,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,UAAU,EAEV,MAAM,aAAa,CAAC;AA0BrB;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;IACnB,wDAAwD;IACxD,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,6CAA6C;IAC7C,OAAO,EAAE,mBAAmB,CAAC;IAC7B,0EAA0E;IAC1E,UAAU,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,SAAS,EAAE,sBAAsB,CAAC;CAClC;AAOD;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IACnC,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,uBAAuB,EAAE,qBAAqB,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACjC;AAED;;;GAGG;AACH,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAW;IAC1C,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAwB;IAChE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsC;gBAE1C,OAAO,EAAE,mBAAmB;IAYvC,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,gBAAgB,CAAC;IAgB7D,OAAO,CAAE,kBAAkB;IAc3B,OAAO,CAAE,eAAe;IA2BxB,OAAO,CAAE,eAAe;IAyDxB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAE,oBAAoB;IA2C7B,OAAO,CAAE,iBAAiB;CA4B1B"}
|
package/esm/runner.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { all, call } from "effection";
|
|
2
|
+
import { createExcludedPolicyFileMap, } from "./context.js";
|
|
3
|
+
import { identifyPolicyInstances } from "./makePolicy.js";
|
|
4
|
+
import { newPerfStats, runWithPerf, } from "./perf.js";
|
|
5
|
+
import { isPolicyError, isPolicyFixResult } from "./policy.js";
|
|
6
|
+
function isOperation(value) {
|
|
7
|
+
return (typeof value === "object" &&
|
|
8
|
+
value !== null &&
|
|
9
|
+
"next" in value &&
|
|
10
|
+
typeof value.next === "function");
|
|
11
|
+
}
|
|
12
|
+
function matches(regex, value) {
|
|
13
|
+
if (!(regex.global || regex.sticky)) {
|
|
14
|
+
return regex.test(value);
|
|
15
|
+
}
|
|
16
|
+
const savedLastIndex = regex.lastIndex;
|
|
17
|
+
try {
|
|
18
|
+
regex.lastIndex = 0;
|
|
19
|
+
return regex.test(value);
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
regex.lastIndex = savedLastIndex;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Runs configured policies against files and collects results.
|
|
27
|
+
* @alpha
|
|
28
|
+
*/
|
|
29
|
+
export class PolicyRunner {
|
|
30
|
+
policies;
|
|
31
|
+
excludeFromAll;
|
|
32
|
+
excludePoliciesForFiles;
|
|
33
|
+
gitRoot;
|
|
34
|
+
resolve;
|
|
35
|
+
logger;
|
|
36
|
+
constructor(options) {
|
|
37
|
+
this.policies = identifyPolicyInstances(options.policies);
|
|
38
|
+
this.excludeFromAll = options.excludeFromAll;
|
|
39
|
+
this.excludePoliciesForFiles = createExcludedPolicyFileMap(this.policies);
|
|
40
|
+
for (const [instanceId, exclusions] of options.excludePoliciesForFiles) {
|
|
41
|
+
this.excludePoliciesForFiles.set(instanceId, exclusions);
|
|
42
|
+
}
|
|
43
|
+
this.gitRoot = options.gitRoot;
|
|
44
|
+
this.resolve = options.resolve;
|
|
45
|
+
this.logger = options.logger;
|
|
46
|
+
}
|
|
47
|
+
*run(filePaths) {
|
|
48
|
+
const state = {
|
|
49
|
+
results: [],
|
|
50
|
+
perfStats: newPerfStats(),
|
|
51
|
+
};
|
|
52
|
+
for (const filePath of filePaths) {
|
|
53
|
+
yield* this.checkOrExcludeFile(filePath, state);
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
results: state.results,
|
|
57
|
+
perfStats: state.perfStats,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
*checkOrExcludeFile(relPath, state) {
|
|
61
|
+
state.perfStats.count++;
|
|
62
|
+
try {
|
|
63
|
+
yield* this.routeToPolicies(relPath, state);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
throw new Error(`Error routing ${relPath} to handler: ${error}\nStack:\n${error.stack}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
*routeToPolicies(relPath, state) {
|
|
70
|
+
if (this.excludeFromAll.some((regex) => matches(regex, relPath))) {
|
|
71
|
+
this.logger?.verbose(`Excluded all handlers: ${relPath}`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const matchingPolicies = this.policies.filter((policy) => matches(policy.match, relPath));
|
|
75
|
+
if (this.resolve) {
|
|
76
|
+
// Fixers can read and rewrite the same file.
|
|
77
|
+
for (const policy of matchingPolicies) {
|
|
78
|
+
yield* this.runPolicyOnFile(relPath, policy, state);
|
|
79
|
+
}
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
yield* all(matchingPolicies.map((policy) => {
|
|
83
|
+
return this.runPolicyOnFile(relPath, policy, state);
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
*runPolicyOnFile(relPath, policy, state) {
|
|
87
|
+
if (this.isPolicyExcluded(relPath, policy)) {
|
|
88
|
+
this.logger?.verbose(`Excluded from '${policy.instanceId}' policy: ${relPath}`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const result = yield* this.executePolicyHandler(relPath, policy, state);
|
|
93
|
+
// Success — nothing to report
|
|
94
|
+
if (result === true) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const fileResult = {
|
|
98
|
+
file: relPath,
|
|
99
|
+
policy: policy.name,
|
|
100
|
+
policyId: policy.instanceId,
|
|
101
|
+
outcome: result,
|
|
102
|
+
};
|
|
103
|
+
// Check if resolution should be attempted: result is a failure that
|
|
104
|
+
// wasn't already fixed, resolve mode is on, and a standalone resolver exists.
|
|
105
|
+
const alreadyFixed = isPolicyFixResult(result) ||
|
|
106
|
+
(isPolicyError(result) && result.fixed !== undefined);
|
|
107
|
+
if (!alreadyFixed && this.resolve && policy.resolver) {
|
|
108
|
+
const resolution = yield* this.attemptResolution(relPath, policy, policy.resolver, state);
|
|
109
|
+
fileResult.resolution = resolution;
|
|
110
|
+
}
|
|
111
|
+
state.results.push(fileResult);
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
115
|
+
state.results.push({
|
|
116
|
+
file: relPath,
|
|
117
|
+
policy: policy.name,
|
|
118
|
+
policyId: policy.instanceId,
|
|
119
|
+
outcome: {
|
|
120
|
+
error: `System Error: Error executing policy '${policy.instanceId}' for file '${relPath}': ${message}`,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
isPolicyExcluded(relPath, policy) {
|
|
126
|
+
return (this.excludePoliciesForFiles
|
|
127
|
+
.get(policy.instanceId)
|
|
128
|
+
?.some((regex) => matches(regex, relPath)) ?? false);
|
|
129
|
+
}
|
|
130
|
+
*executePolicyHandler(relPath, policy, state) {
|
|
131
|
+
const { resolve, gitRoot } = this;
|
|
132
|
+
const result = yield* runWithPerf(policy.instanceId, "handle", state.perfStats, function* () {
|
|
133
|
+
const args = {
|
|
134
|
+
file: relPath,
|
|
135
|
+
root: gitRoot,
|
|
136
|
+
resolve,
|
|
137
|
+
config: policy.config,
|
|
138
|
+
};
|
|
139
|
+
if (policy._internalHandler) {
|
|
140
|
+
return yield* policy._internalHandler(args);
|
|
141
|
+
}
|
|
142
|
+
const handlerResult = policy.handler(args);
|
|
143
|
+
if (handlerResult instanceof Promise) {
|
|
144
|
+
return yield* call(() => handlerResult);
|
|
145
|
+
}
|
|
146
|
+
if (isOperation(handlerResult)) {
|
|
147
|
+
return yield* handlerResult;
|
|
148
|
+
}
|
|
149
|
+
throw new Error(`Unexpected handler result type: ${typeof handlerResult}`);
|
|
150
|
+
});
|
|
151
|
+
if (result === undefined) {
|
|
152
|
+
throw new Error("Policy result was undefined.");
|
|
153
|
+
}
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
*attemptResolution(relPath, policy, resolver, state) {
|
|
157
|
+
const { gitRoot } = this;
|
|
158
|
+
return yield* runWithPerf(policy.instanceId, "resolve", state.perfStats, function* () {
|
|
159
|
+
const result = resolver({
|
|
160
|
+
file: relPath,
|
|
161
|
+
root: gitRoot,
|
|
162
|
+
config: policy.config,
|
|
163
|
+
});
|
|
164
|
+
if (result instanceof Promise) {
|
|
165
|
+
return yield* call(() => result);
|
|
166
|
+
}
|
|
167
|
+
if (isOperation(result)) {
|
|
168
|
+
return yield* result;
|
|
169
|
+
}
|
|
170
|
+
throw new Error(`Unexpected resolver result type: ${typeof result}`);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Logger } from \"@tylerbu/cli-api\";\nimport { all, call, type Operation } from \"effection\";\n\nimport {\n\tcreateExcludedPolicyFileMap,\n\ttype ExcludedPolicyFileMap,\n} from \"./context.js\";\nimport { identifyPolicyInstances } from \"./makePolicy.js\";\nimport {\n\tnewPerfStats,\n\ttype PolicyHandlerPerfStats,\n\trunWithPerf,\n} from \"./perf.js\";\nimport type {\n\tIdentifiedPolicy,\n\tPolicyFixResult,\n\tPolicyHandlerResult,\n\tPolicyInstance,\n\tPolicyInstanceId,\n\tPolicyName,\n\tPolicyStandaloneResolver,\n} from \"./policy.js\";\nimport { isPolicyError, isPolicyFixResult } from \"./policy.js\";\n\nfunction isOperation<T>(value: unknown): value is Operation<T> {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"next\" in value &&\n\t\ttypeof (value as { next: unknown }).next === \"function\"\n\t);\n}\n\nfunction matches(regex: RegExp, value: string): boolean {\n\tif (!(regex.global || regex.sticky)) {\n\t\treturn regex.test(value);\n\t}\n\n\tconst savedLastIndex = regex.lastIndex;\n\ttry {\n\t\tregex.lastIndex = 0;\n\t\treturn regex.test(value);\n\t} finally {\n\t\tregex.lastIndex = savedLastIndex;\n\t}\n}\n\n/**\n * Result of running a single policy on a single file.\n * @alpha\n */\nexport interface PolicyFileResult {\n\tfile: string;\n\tpolicy: PolicyName;\n\t/** Stable identity of the configured policy instance */\n\tpolicyId: PolicyInstanceId;\n\t/** The raw result from the policy handler */\n\toutcome: PolicyHandlerResult;\n\t/** Set when a standalone resolver was attempted (legacy resolver path) */\n\tresolution?: PolicyFixResult;\n}\n\n/**\n * Aggregated results from a full policy run.\n * @alpha\n */\nexport interface PolicyRunResults {\n\tresults: PolicyFileResult[];\n\tperfStats: PolicyHandlerPerfStats;\n}\n\ninterface PolicyRunState {\n\tresults: PolicyFileResult[];\n\tperfStats: PolicyHandlerPerfStats;\n}\n\n/**\n * Options for configuring a {@link PolicyRunner}.\n * @alpha\n */\nexport interface PolicyRunnerOptions {\n\tpolicies: PolicyInstance[];\n\texcludeFromAll: RegExp[];\n\texcludePoliciesForFiles: ExcludedPolicyFileMap;\n\tgitRoot: string;\n\tresolve: boolean;\n\tlogger?: Pick<Logger, \"verbose\">;\n}\n\n/**\n * Runs configured policies against files and collects results.\n * @alpha\n */\nexport class PolicyRunner {\n\tprivate readonly policies: IdentifiedPolicy[];\n\tprivate readonly excludeFromAll: RegExp[];\n\tprivate readonly excludePoliciesForFiles: ExcludedPolicyFileMap;\n\tprivate readonly gitRoot: string;\n\tprivate readonly resolve: boolean;\n\tprivate readonly logger: Pick<Logger, \"verbose\"> | undefined;\n\n\tpublic constructor(options: PolicyRunnerOptions) {\n\t\tthis.policies = identifyPolicyInstances(options.policies);\n\t\tthis.excludeFromAll = options.excludeFromAll;\n\t\tthis.excludePoliciesForFiles = createExcludedPolicyFileMap(this.policies);\n\t\tfor (const [instanceId, exclusions] of options.excludePoliciesForFiles) {\n\t\t\tthis.excludePoliciesForFiles.set(instanceId, exclusions);\n\t\t}\n\t\tthis.gitRoot = options.gitRoot;\n\t\tthis.resolve = options.resolve;\n\t\tthis.logger = options.logger;\n\t}\n\n\tpublic *run(filePaths: string[]): Operation<PolicyRunResults> {\n\t\tconst state: PolicyRunState = {\n\t\t\tresults: [],\n\t\t\tperfStats: newPerfStats(),\n\t\t};\n\n\t\tfor (const filePath of filePaths) {\n\t\t\tyield* this.checkOrExcludeFile(filePath, state);\n\t\t}\n\n\t\treturn {\n\t\t\tresults: state.results,\n\t\t\tperfStats: state.perfStats,\n\t\t};\n\t}\n\n\tprivate *checkOrExcludeFile(\n\t\trelPath: string,\n\t\tstate: PolicyRunState,\n\t): Operation<void> {\n\t\tstate.perfStats.count++;\n\t\ttry {\n\t\t\tyield* this.routeToPolicies(relPath, state);\n\t\t} catch (error: unknown) {\n\t\t\tthrow new Error(\n\t\t\t\t`Error routing ${relPath} to handler: ${error}\\nStack:\\n${(error as Error).stack}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate *routeToPolicies(\n\t\trelPath: string,\n\t\tstate: PolicyRunState,\n\t): Operation<void> {\n\t\tif (this.excludeFromAll.some((regex) => matches(regex, relPath))) {\n\t\t\tthis.logger?.verbose(`Excluded all handlers: ${relPath}`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst matchingPolicies = this.policies.filter((policy) =>\n\t\t\tmatches(policy.match, relPath),\n\t\t);\n\t\tif (this.resolve) {\n\t\t\t// Fixers can read and rewrite the same file.\n\t\t\tfor (const policy of matchingPolicies) {\n\t\t\t\tyield* this.runPolicyOnFile(relPath, policy, state);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tyield* all(\n\t\t\tmatchingPolicies.map((policy) => {\n\t\t\t\treturn this.runPolicyOnFile(relPath, policy, state);\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate *runPolicyOnFile(\n\t\trelPath: string,\n\t\tpolicy: IdentifiedPolicy,\n\t\tstate: PolicyRunState,\n\t): Operation<void> {\n\t\tif (this.isPolicyExcluded(relPath, policy)) {\n\t\t\tthis.logger?.verbose(\n\t\t\t\t`Excluded from '${policy.instanceId}' policy: ${relPath}`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst result = yield* this.executePolicyHandler(relPath, policy, state);\n\n\t\t\t// Success — nothing to report\n\t\t\tif (result === true) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst fileResult: PolicyFileResult = {\n\t\t\t\tfile: relPath,\n\t\t\t\tpolicy: policy.name,\n\t\t\t\tpolicyId: policy.instanceId,\n\t\t\t\toutcome: result,\n\t\t\t};\n\n\t\t\t// Check if resolution should be attempted: result is a failure that\n\t\t\t// wasn't already fixed, resolve mode is on, and a standalone resolver exists.\n\t\t\tconst alreadyFixed =\n\t\t\t\tisPolicyFixResult(result) ||\n\t\t\t\t(isPolicyError(result) && result.fixed !== undefined);\n\n\t\t\tif (!alreadyFixed && this.resolve && policy.resolver) {\n\t\t\t\tconst resolution = yield* this.attemptResolution(\n\t\t\t\t\trelPath,\n\t\t\t\t\tpolicy,\n\t\t\t\t\tpolicy.resolver,\n\t\t\t\t\tstate,\n\t\t\t\t);\n\t\t\t\tfileResult.resolution = resolution;\n\t\t\t}\n\n\t\t\tstate.results.push(fileResult);\n\t\t} catch (error: unknown) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tstate.results.push({\n\t\t\t\tfile: relPath,\n\t\t\t\tpolicy: policy.name,\n\t\t\t\tpolicyId: policy.instanceId,\n\t\t\t\toutcome: {\n\t\t\t\t\terror: `System Error: Error executing policy '${policy.instanceId}' for file '${relPath}': ${message}`,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate isPolicyExcluded(relPath: string, policy: IdentifiedPolicy): boolean {\n\t\treturn (\n\t\t\tthis.excludePoliciesForFiles\n\t\t\t\t.get(policy.instanceId)\n\t\t\t\t?.some((regex) => matches(regex, relPath)) ?? false\n\t\t);\n\t}\n\n\tprivate *executePolicyHandler(\n\t\trelPath: string,\n\t\tpolicy: IdentifiedPolicy,\n\t\tstate: PolicyRunState,\n\t): Operation<PolicyHandlerResult> {\n\t\tconst { resolve, gitRoot } = this;\n\n\t\tconst result = yield* runWithPerf(\n\t\t\tpolicy.instanceId,\n\t\t\t\"handle\",\n\t\t\tstate.perfStats,\n\t\t\tfunction* () {\n\t\t\t\tconst args = {\n\t\t\t\t\tfile: relPath,\n\t\t\t\t\troot: gitRoot,\n\t\t\t\t\tresolve,\n\t\t\t\t\tconfig: policy.config,\n\t\t\t\t};\n\n\t\t\t\tif (policy._internalHandler) {\n\t\t\t\t\treturn yield* policy._internalHandler(args);\n\t\t\t\t}\n\n\t\t\t\tconst handlerResult = policy.handler(args);\n\t\t\t\tif (handlerResult instanceof Promise) {\n\t\t\t\t\treturn yield* call(() => handlerResult);\n\t\t\t\t}\n\t\t\t\tif (isOperation<PolicyHandlerResult>(handlerResult)) {\n\t\t\t\t\treturn yield* handlerResult;\n\t\t\t\t}\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Unexpected handler result type: ${typeof handlerResult}`,\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\n\t\tif (result === undefined) {\n\t\t\tthrow new Error(\"Policy result was undefined.\");\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate *attemptResolution(\n\t\trelPath: string,\n\t\tpolicy: IdentifiedPolicy,\n\t\tresolver: PolicyStandaloneResolver,\n\t\tstate: PolicyRunState,\n\t): Operation<PolicyFixResult> {\n\t\tconst { gitRoot } = this;\n\n\t\treturn yield* runWithPerf(\n\t\t\tpolicy.instanceId,\n\t\t\t\"resolve\",\n\t\t\tstate.perfStats,\n\t\t\tfunction* () {\n\t\t\t\tconst result = resolver({\n\t\t\t\t\tfile: relPath,\n\t\t\t\t\troot: gitRoot,\n\t\t\t\t\tconfig: policy.config,\n\t\t\t\t});\n\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\treturn yield* call(() => result);\n\t\t\t\t}\n\t\t\t\tif (isOperation<PolicyFixResult>(result)) {\n\t\t\t\t\treturn yield* result;\n\t\t\t\t}\n\t\t\t\tthrow new Error(`Unexpected resolver result type: ${typeof result}`);\n\t\t\t},\n\t\t);\n\t}\n}\n"]}
|
package/esm/tsdoc-metadata.json
CHANGED
package/oclif.manifest.json
CHANGED
|
@@ -1,5 +1,102 @@
|
|
|
1
1
|
{
|
|
2
2
|
"commands": {
|
|
3
|
+
"check-native": {
|
|
4
|
+
"aliases": [],
|
|
5
|
+
"args": {},
|
|
6
|
+
"description": "Runs the Rust-based repopo-core engine with the Node.js sidecar. This provides the same policy checking as 'check' but with Rust-based file enumeration, regex matching, and orchestration for better performance.",
|
|
7
|
+
"flags": {
|
|
8
|
+
"fix": {
|
|
9
|
+
"aliases": [
|
|
10
|
+
"resolve"
|
|
11
|
+
],
|
|
12
|
+
"char": "f",
|
|
13
|
+
"description": "Fix errors if possible.",
|
|
14
|
+
"name": "fix",
|
|
15
|
+
"required": false,
|
|
16
|
+
"allowNo": false,
|
|
17
|
+
"type": "boolean"
|
|
18
|
+
},
|
|
19
|
+
"stdin": {
|
|
20
|
+
"description": "Read list of files from stdin.",
|
|
21
|
+
"name": "stdin",
|
|
22
|
+
"required": false,
|
|
23
|
+
"allowNo": false,
|
|
24
|
+
"type": "boolean"
|
|
25
|
+
},
|
|
26
|
+
"verbose": {
|
|
27
|
+
"char": "v",
|
|
28
|
+
"description": "Show verbose output including per-policy timing.",
|
|
29
|
+
"name": "verbose",
|
|
30
|
+
"required": false,
|
|
31
|
+
"allowNo": false,
|
|
32
|
+
"type": "boolean"
|
|
33
|
+
},
|
|
34
|
+
"quiet": {
|
|
35
|
+
"char": "q",
|
|
36
|
+
"description": "Suppress all output except errors.",
|
|
37
|
+
"name": "quiet",
|
|
38
|
+
"required": false,
|
|
39
|
+
"allowNo": false,
|
|
40
|
+
"type": "boolean"
|
|
41
|
+
},
|
|
42
|
+
"config": {
|
|
43
|
+
"char": "c",
|
|
44
|
+
"description": "Path to the config file.",
|
|
45
|
+
"name": "config",
|
|
46
|
+
"required": false,
|
|
47
|
+
"hasDynamicHelp": false,
|
|
48
|
+
"multiple": false,
|
|
49
|
+
"type": "option"
|
|
50
|
+
},
|
|
51
|
+
"sidecar-path": {
|
|
52
|
+
"description": "Path to the Node.js sidecar script.",
|
|
53
|
+
"env": "REPOPO_SIDECAR_PATH",
|
|
54
|
+
"name": "sidecar-path",
|
|
55
|
+
"required": false,
|
|
56
|
+
"hasDynamicHelp": false,
|
|
57
|
+
"multiple": false,
|
|
58
|
+
"type": "option"
|
|
59
|
+
},
|
|
60
|
+
"binary-path": {
|
|
61
|
+
"description": "Path to the repopo-core Rust binary.",
|
|
62
|
+
"env": "REPOPO_CORE_PATH",
|
|
63
|
+
"name": "binary-path",
|
|
64
|
+
"required": false,
|
|
65
|
+
"hasDynamicHelp": false,
|
|
66
|
+
"multiple": false,
|
|
67
|
+
"type": "option"
|
|
68
|
+
},
|
|
69
|
+
"runtime": {
|
|
70
|
+
"description": "JS runtime for the sidecar process (auto, node, bun).",
|
|
71
|
+
"env": "REPOPO_RUNTIME",
|
|
72
|
+
"name": "runtime",
|
|
73
|
+
"required": false,
|
|
74
|
+
"hasDynamicHelp": false,
|
|
75
|
+
"multiple": false,
|
|
76
|
+
"options": [
|
|
77
|
+
"auto",
|
|
78
|
+
"node",
|
|
79
|
+
"bun"
|
|
80
|
+
],
|
|
81
|
+
"type": "option"
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"hasDynamicHelp": false,
|
|
85
|
+
"hiddenAliases": [],
|
|
86
|
+
"id": "check-native",
|
|
87
|
+
"pluginAlias": "repopo",
|
|
88
|
+
"pluginName": "repopo",
|
|
89
|
+
"pluginType": "core",
|
|
90
|
+
"strict": true,
|
|
91
|
+
"summary": "Checks and applies policies using the Rust engine.",
|
|
92
|
+
"enableJsonFlag": false,
|
|
93
|
+
"isESM": true,
|
|
94
|
+
"relativePath": [
|
|
95
|
+
"esm",
|
|
96
|
+
"commands",
|
|
97
|
+
"check-native.js"
|
|
98
|
+
]
|
|
99
|
+
},
|
|
3
100
|
"check": {
|
|
4
101
|
"aliases": [],
|
|
5
102
|
"args": {},
|
|
@@ -46,7 +143,7 @@
|
|
|
46
143
|
"type": "boolean"
|
|
47
144
|
},
|
|
48
145
|
"config": {
|
|
49
|
-
"description": "
|
|
146
|
+
"description": "Path to configuration file.",
|
|
50
147
|
"helpGroup": "CONFIGURATION",
|
|
51
148
|
"hidden": true,
|
|
52
149
|
"name": "config",
|
|
@@ -99,7 +196,7 @@
|
|
|
99
196
|
"type": "boolean"
|
|
100
197
|
},
|
|
101
198
|
"config": {
|
|
102
|
-
"description": "
|
|
199
|
+
"description": "Path to configuration file.",
|
|
103
200
|
"helpGroup": "CONFIGURATION",
|
|
104
201
|
"hidden": true,
|
|
105
202
|
"name": "config",
|
|
@@ -125,5 +222,5 @@
|
|
|
125
222
|
]
|
|
126
223
|
}
|
|
127
224
|
},
|
|
128
|
-
"version": "0.
|
|
225
|
+
"version": "0.12.0"
|
|
129
226
|
}
|