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
package/esm/makePolicy.d.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import type { ConfiguredPolicy, PolicyDefinition, PolicyInstance, PolicyInstanceSettings, PolicyShape } from "./policy.js";
|
|
1
|
+
import type { ConfiguredPolicy, PolicyDefinition, PolicyInstance, PolicyInstanceId, PolicyInstanceSettings, PolicyName, PolicyShape } from "./policy.js";
|
|
2
2
|
/**
|
|
3
3
|
* Options for configuring a policy instance.
|
|
4
4
|
*
|
|
5
5
|
* @alpha
|
|
6
6
|
*/
|
|
7
7
|
export interface PolicyOptions {
|
|
8
|
+
/**
|
|
9
|
+
* A stable identifier for this configured policy instance.
|
|
10
|
+
*
|
|
11
|
+
* This is required when the same policy definition is configured more than once.
|
|
12
|
+
*/
|
|
13
|
+
instanceId?: PolicyInstanceId;
|
|
8
14
|
/**
|
|
9
15
|
* File paths matching these patterns will be excluded from this policy.
|
|
10
16
|
* Patterns are matched against repo-relative paths.
|
|
@@ -31,13 +37,34 @@ export interface PolicyOptions {
|
|
|
31
37
|
*
|
|
32
38
|
* // Policy with config and options
|
|
33
39
|
* policy(PackageJsonProperties, { verbatim: { license: "MIT" } }, { exclude: ["vendor/*"] })
|
|
40
|
+
*
|
|
41
|
+
* // Duplicate policies need stable instance IDs
|
|
42
|
+
* policy(PackageJsonProperties, sourceConfig, { instanceId: "source-packages" })
|
|
43
|
+
* policy(PackageJsonProperties, testConfig, { instanceId: "test-packages" })
|
|
34
44
|
* ```
|
|
35
45
|
*
|
|
36
46
|
* @alpha
|
|
37
47
|
*/
|
|
38
|
-
export declare function policy<C = void>(policyDef: PolicyShape<C>, options?: PolicyOptions
|
|
48
|
+
export declare function policy<C = void>(policyDef: PolicyShape<C>, options?: PolicyOptions & {
|
|
49
|
+
exclude: (string | RegExp)[];
|
|
50
|
+
}): ConfiguredPolicy<C>;
|
|
39
51
|
/** @alpha */
|
|
40
52
|
export declare function policy<C>(policyDef: PolicyShape<C>, config: C, options?: PolicyOptions): ConfiguredPolicy<C>;
|
|
53
|
+
/**
|
|
54
|
+
* Assigns stable identities to configured policy instances.
|
|
55
|
+
*
|
|
56
|
+
* Single instances retain the policy name for compatibility. Duplicate instances
|
|
57
|
+
* must declare explicit identities so their identities remain stable across config
|
|
58
|
+
* reordering and policy renames.
|
|
59
|
+
*
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
62
|
+
export declare function identifyPolicyInstances<T extends {
|
|
63
|
+
name: PolicyName;
|
|
64
|
+
instanceId?: PolicyInstanceId | undefined;
|
|
65
|
+
}>(policies: readonly T[]): (T & {
|
|
66
|
+
instanceId: PolicyInstanceId;
|
|
67
|
+
})[];
|
|
41
68
|
/**
|
|
42
69
|
* Input arguments for creating a policy definition.
|
|
43
70
|
*
|
package/esm/makePolicy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"makePolicy.d.ts","sourceRoot":"","sources":["../src/makePolicy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,gBAAgB,EAEhB,gBAAgB,EAGhB,cAAc,EACd,sBAAsB,EACtB,WAAW,EACX,MAAM,aAAa,CAAC;AAMrB;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC7B;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;CAC9B;AAuBD
|
|
1
|
+
{"version":3,"file":"makePolicy.d.ts","sourceRoot":"","sources":["../src/makePolicy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,gBAAgB,EAEhB,gBAAgB,EAGhB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,UAAU,EACV,WAAW,EACX,MAAM,aAAa,CAAC;AAMrB;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC7B;;;;OAIG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAE9B;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;CAC9B;AAuBD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,MAAM,CAAC,CAAC,GAAG,IAAI,EAC9B,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,EACzB,OAAO,CAAC,EAAE,aAAa,GAAG;IAAE,OAAO,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAA;CAAE,GACxD,gBAAgB,CAAC,CAAC,CAAC,CAAC;AACvB,aAAa;AACb,wBAAgB,MAAM,CAAC,CAAC,EACvB,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,EACzB,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,aAAa,GACrB,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAmDvB;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACtC,CAAC,SAAS;IACT,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAC1C,EACA,QAAQ,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG;IAAE,UAAU,EAAE,gBAAgB,CAAA;CAAE,CAAC,EAAE,CAgDlE;AAMD;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,CAAC,CAAC,GAAG,SAAS,IAAI,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAEvE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,GAAG,SAAS,EACjD,IAAI,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAC5B,gBAAgB,CAAC,CAAC,CAAC,CASrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAC3B,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC/B,MAAM,CAAC,EAAE,CAAC,EACV,QAAQ,CAAC,EAAE,sBAAsB,CAAC,CAAC,CAAC,GAClC,cAAc,CAAC,CAAC,CAAC,CAMnB"}
|
package/esm/makePolicy.js
CHANGED
|
@@ -32,8 +32,8 @@ export function policy(policyDef, configOrOptions, maybeOptions) {
|
|
|
32
32
|
configOrOptions !== null &&
|
|
33
33
|
"exclude" in configOrOptions &&
|
|
34
34
|
!("name" in configOrOptions) &&
|
|
35
|
-
Object.keys(configOrOptions).every((k) => k === "exclude")) {
|
|
36
|
-
// It's options (has
|
|
35
|
+
Object.keys(configOrOptions).every((k) => k === "exclude" || k === "instanceId")) {
|
|
36
|
+
// It's options (has 'exclude' and only option keys)
|
|
37
37
|
options = configOrOptions;
|
|
38
38
|
}
|
|
39
39
|
else {
|
|
@@ -50,9 +50,53 @@ export function policy(policyDef, configOrOptions, maybeOptions) {
|
|
|
50
50
|
config: effectiveConfig,
|
|
51
51
|
exclude: excludePatterns,
|
|
52
52
|
excludeFiles: excludePatterns,
|
|
53
|
+
instanceId: options?.instanceId,
|
|
53
54
|
_internalHandler: normalizeHandler(policyDef.handler),
|
|
54
55
|
};
|
|
55
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Assigns stable identities to configured policy instances.
|
|
59
|
+
*
|
|
60
|
+
* Single instances retain the policy name for compatibility. Duplicate instances
|
|
61
|
+
* must declare explicit identities so their identities remain stable across config
|
|
62
|
+
* reordering and policy renames.
|
|
63
|
+
*
|
|
64
|
+
* @internal
|
|
65
|
+
*/
|
|
66
|
+
export function identifyPolicyInstances(policies) {
|
|
67
|
+
const explicitIds = new Set();
|
|
68
|
+
const nameCounts = new Map();
|
|
69
|
+
for (const configuredPolicy of policies) {
|
|
70
|
+
nameCounts.set(configuredPolicy.name, (nameCounts.get(configuredPolicy.name) ?? 0) + 1);
|
|
71
|
+
if (configuredPolicy.instanceId !== undefined) {
|
|
72
|
+
if (explicitIds.has(configuredPolicy.instanceId)) {
|
|
73
|
+
throw new Error(`Duplicate policy instance ID: ${configuredPolicy.instanceId}`);
|
|
74
|
+
}
|
|
75
|
+
explicitIds.add(configuredPolicy.instanceId);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const usedIds = new Set(explicitIds);
|
|
79
|
+
return policies.map((configuredPolicy) => {
|
|
80
|
+
if (configuredPolicy.instanceId !== undefined) {
|
|
81
|
+
return {
|
|
82
|
+
...configuredPolicy,
|
|
83
|
+
instanceId: configuredPolicy.instanceId,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if ((nameCounts.get(configuredPolicy.name) ?? 0) > 1) {
|
|
87
|
+
throw new Error(`Policy '${configuredPolicy.name}' is configured multiple times. Set a unique instanceId for each instance.`);
|
|
88
|
+
}
|
|
89
|
+
const instanceId = configuredPolicy.name;
|
|
90
|
+
if (usedIds.has(instanceId)) {
|
|
91
|
+
throw new Error(`Policy instance ID '${instanceId}' conflicts with another configured policy. Set an explicit unique instanceId.`);
|
|
92
|
+
}
|
|
93
|
+
usedIds.add(instanceId);
|
|
94
|
+
return {
|
|
95
|
+
...configuredPolicy,
|
|
96
|
+
instanceId,
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
}
|
|
56
100
|
/**
|
|
57
101
|
* Creates a {@link PolicyDefinition} from the provided arguments.
|
|
58
102
|
*
|
package/esm/makePolicy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"makePolicy.js","sourceRoot":"","sources":["../src/makePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAkB,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AA6BtD;;;GAGG;AACH,SAAS,gBAAgB,CACxB,OAAyB;IAEzB,IAAI,mBAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;QAClC,oCAAoC;QACpC,OAAO,OAAkE,CAAC;IAC3E,CAAC;IAED,oCAAoC;IACpC,OAAO,QAAQ,CAAC,EAAE,IAAmB;QACpC,MAAM,YAAY,GAAG,OAEY,CAAC;QAClC,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC;AACH,CAAC;AAoCD,aAAa;AACb,MAAM,UAAU,MAAM,CACrB,SAAyB,EACzB,eAAmC,EACnC,YAA4B;IAE5B,wDAAwD;IACxD,IAAI,MAAqB,CAAC;IAC1B,IAAI,OAAkC,CAAC;IAEvC,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAChC,oDAAoD;QACpD,MAAM,GAAG,eAAoB,CAAC;QAC9B,OAAO,GAAG,YAAY,CAAC;IACxB,CAAC;SAAM,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAC1C,iEAAiE;QACjE,6DAA6D;QAC7D,IACC,OAAO,eAAe,KAAK,QAAQ;YACnC,eAAe,KAAK,IAAI;YACxB,SAAS,IAAI,eAAe;YAC5B,CAAC,CAAC,MAAM,IAAI,eAAe,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,EACzD,CAAC;YACF,oCAAoC;YACpC,OAAO,GAAG,eAAgC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACP,cAAc;YACd,MAAM,GAAG,eAAoB,CAAC;QAC/B,CAAC;IACF,CAAC;IAED,yCAAyC;IACzC,MAAM,eAAe,GAAG,MAAM,IAAK,SAAS,CAAC,aAA+B,CAAC;IAE7E,uEAAuE;IACvE,MAAM,eAAe,GAAG,OAAO,EAAE,OAAO,CAAC;IAEzC,OAAO;QACN,GAAG,SAAS;QACZ,MAAM,EAAE,eAAe;QACvB,OAAO,EAAE,eAAe;QACxB,YAAY,EAAE,eAAe;QAC7B,gBAAgB,EAAE,gBAAgB,CAAC,SAAS,CAAC,OAAO,CAAC;KACrD,CAAC;AACH,CAAC;AAeD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,oBAAoB,CACnC,IAA8B;IAE9B,OAAO;QACN,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACvB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CACzB,UAA+B,EAC/B,MAAU,EACV,QAAoC;IAEpC,OAAO;QACN,GAAG,UAAU;QACb,GAAG,QAAQ;QACX,MAAM;KACsB,CAAC;AAC/B,CAAC","sourcesContent":["import { call, type Operation } from \"effection\";\nimport { isGeneratorFunction } from \"./generators.js\";\nimport type {\n\tConfiguredPolicy,\n\tPolicyArgs,\n\tPolicyDefinition,\n\tPolicyHandler,\n\tPolicyHandlerResult,\n\tPolicyInstance,\n\tPolicyInstanceSettings,\n\tPolicyShape,\n} from \"./policy.js\";\n\n// ============================================================================\n// New API: policy() function\n// ============================================================================\n\n/**\n * Options for configuring a policy instance.\n *\n * @alpha\n */\nexport interface PolicyOptions {\n\t/**\n\t * File paths matching these patterns will be excluded from this policy.\n\t * Patterns are matched against repo-relative paths.\n\t */\n\texclude?: (string | RegExp)[];\n}\n\n/**\n * Normalizes a handler to always return an Effection Operation.\n * Detection happens once at registration time, not per-invocation.\n */\nfunction normalizeHandler<C>(\n\thandler: PolicyHandler<C>,\n): (args: PolicyArgs<C>) => Operation<PolicyHandlerResult> {\n\tif (isGeneratorFunction(handler)) {\n\t\t// Already a generator, return as-is\n\t\treturn handler as (args: PolicyArgs<C>) => Operation<PolicyHandlerResult>;\n\t}\n\n\t// Async function - wrap with call()\n\treturn function* (args: PolicyArgs<C>): Operation<PolicyHandlerResult> {\n\t\tconst asyncHandler = handler as (\n\t\t\tpolicyArgs: PolicyArgs<C>,\n\t\t) => Promise<PolicyHandlerResult>;\n\t\treturn yield* call(() => asyncHandler(args));\n\t};\n}\n\n/**\n * Configure a policy for use in repopo.\n *\n * @remarks\n * This function takes a policy definition and returns a configured policy instance\n * that can be added to the `policies` array in `repopo.config.ts`.\n *\n * Handlers are automatically normalized: async functions are wrapped for Effection\n * compatibility, while generator functions are used directly.\n *\n * @example\n * ```typescript\n * // Policy with no config, just options\n * policy(NoJsFileExtensions, { exclude: [\"bin/*\"] })\n *\n * // Policy with config\n * policy(PackageJsonProperties, { verbatim: { license: \"MIT\" } })\n *\n * // Policy with config and options\n * policy(PackageJsonProperties, { verbatim: { license: \"MIT\" } }, { exclude: [\"vendor/*\"] })\n * ```\n *\n * @alpha\n */\nexport function policy<C = void>(\n\tpolicyDef: PolicyShape<C>,\n\toptions?: PolicyOptions,\n): ConfiguredPolicy<C>;\n/** @alpha */\nexport function policy<C>(\n\tpolicyDef: PolicyShape<C>,\n\tconfig: C,\n\toptions?: PolicyOptions,\n): ConfiguredPolicy<C>;\n/** @alpha */\nexport function policy<C>(\n\tpolicyDef: PolicyShape<C>,\n\tconfigOrOptions?: C | PolicyOptions,\n\tmaybeOptions?: PolicyOptions,\n): ConfiguredPolicy<C> {\n\t// Determine if the second argument is config or options\n\tlet config: C | undefined;\n\tlet options: PolicyOptions | undefined;\n\n\tif (maybeOptions !== undefined) {\n\t\t// Three-argument form: policy(def, config, options)\n\t\tconfig = configOrOptions as C;\n\t\toptions = maybeOptions;\n\t} else if (configOrOptions !== undefined) {\n\t\t// Two-argument form: need to determine if it's config or options\n\t\t// PolicyOptions has a specific shape with 'exclude' property\n\t\tif (\n\t\t\ttypeof configOrOptions === \"object\" &&\n\t\t\tconfigOrOptions !== null &&\n\t\t\t\"exclude\" in configOrOptions &&\n\t\t\t!(\"name\" in configOrOptions) &&\n\t\t\tObject.keys(configOrOptions).every((k) => k === \"exclude\")\n\t\t) {\n\t\t\t// It's options (has only 'exclude')\n\t\t\toptions = configOrOptions as PolicyOptions;\n\t\t} else {\n\t\t\t// It's config\n\t\t\tconfig = configOrOptions as C;\n\t\t}\n\t}\n\n\t// Merge with default config if available\n\tconst effectiveConfig = config ?? (policyDef.defaultConfig as C | undefined);\n\n\t// Support both 'exclude' and 'excludeFiles' for backward compatibility\n\tconst excludePatterns = options?.exclude;\n\n\treturn {\n\t\t...policyDef,\n\t\tconfig: effectiveConfig,\n\t\texclude: excludePatterns,\n\t\texcludeFiles: excludePatterns,\n\t\t_internalHandler: normalizeHandler(policyDef.handler),\n\t};\n}\n\n// ============================================================================\n// Legacy API (Still supported for backward compatibility)\n// ============================================================================\n\n/**\n * Input arguments for creating a policy definition.\n *\n * @deprecated Use {@link PolicyShape} directly instead.\n *\n * @alpha\n */\nexport type PolicyDefinitionInput<C = undefined> = PolicyDefinition<C>;\n\n/**\n * Creates a {@link PolicyDefinition} from the provided arguments.\n *\n * @deprecated Define policies as object literals satisfying {@link PolicyShape} instead.\n *\n * @example\n * ```typescript\n * const MyPolicy = makePolicyDefinition({\n * name: \"MyPolicy\",\n * description: \"Ensures files follow conventions\",\n * match: /\\.ts$/,\n * handler: async ({ file }) => true,\n * });\n * ```\n *\n * @alpha\n */\nexport function makePolicyDefinition<C = undefined>(\n\targs: PolicyDefinitionInput<C>,\n): PolicyDefinition<C> {\n\treturn {\n\t\tname: args.name,\n\t\tdescription: args.description,\n\t\tmatch: args.match,\n\t\thandler: args.handler,\n\t\tdefaultConfig: args.defaultConfig,\n\t\tresolver: args.resolver,\n\t};\n}\n\n/**\n * Combine a {@link PolicyDefinition} with a policy-specific config and other settings.\n *\n * @deprecated Use the `policy` function instead, which has a simpler API.\n *\n * @example\n * ```typescript\n * makePolicy(NoJsFileExtensions, undefined, { excludeFiles: [\"bin/*\"] })\n * ```\n *\n * @alpha\n */\nexport function makePolicy<C>(\n\tdefinition: PolicyDefinition<C>,\n\tconfig?: C,\n\tsettings?: PolicyInstanceSettings<C>,\n): PolicyInstance<C> {\n\treturn {\n\t\t...definition,\n\t\t...settings,\n\t\tconfig,\n\t} satisfies PolicyInstance<C>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"makePolicy.js","sourceRoot":"","sources":["../src/makePolicy.ts"],"names":[],"mappings":"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","sourcesContent":["import { call, type Operation } from \"effection\";\nimport { isGeneratorFunction } from \"./generators.js\";\nimport type {\n\tConfiguredPolicy,\n\tPolicyArgs,\n\tPolicyDefinition,\n\tPolicyHandler,\n\tPolicyHandlerResult,\n\tPolicyInstance,\n\tPolicyInstanceId,\n\tPolicyInstanceSettings,\n\tPolicyName,\n\tPolicyShape,\n} from \"./policy.js\";\n\n// ============================================================================\n// New API: policy() function\n// ============================================================================\n\n/**\n * Options for configuring a policy instance.\n *\n * @alpha\n */\nexport interface PolicyOptions {\n\t/**\n\t * A stable identifier for this configured policy instance.\n\t *\n\t * This is required when the same policy definition is configured more than once.\n\t */\n\tinstanceId?: PolicyInstanceId;\n\n\t/**\n\t * File paths matching these patterns will be excluded from this policy.\n\t * Patterns are matched against repo-relative paths.\n\t */\n\texclude?: (string | RegExp)[];\n}\n\n/**\n * Normalizes a handler to always return an Effection Operation.\n * Detection happens once at registration time, not per-invocation.\n */\nfunction normalizeHandler<C>(\n\thandler: PolicyHandler<C>,\n): (args: PolicyArgs<C>) => Operation<PolicyHandlerResult> {\n\tif (isGeneratorFunction(handler)) {\n\t\t// Already a generator, return as-is\n\t\treturn handler as (args: PolicyArgs<C>) => Operation<PolicyHandlerResult>;\n\t}\n\n\t// Async function - wrap with call()\n\treturn function* (args: PolicyArgs<C>): Operation<PolicyHandlerResult> {\n\t\tconst asyncHandler = handler as (\n\t\t\tpolicyArgs: PolicyArgs<C>,\n\t\t) => Promise<PolicyHandlerResult>;\n\t\treturn yield* call(() => asyncHandler(args));\n\t};\n}\n\n/**\n * Configure a policy for use in repopo.\n *\n * @remarks\n * This function takes a policy definition and returns a configured policy instance\n * that can be added to the `policies` array in `repopo.config.ts`.\n *\n * Handlers are automatically normalized: async functions are wrapped for Effection\n * compatibility, while generator functions are used directly.\n *\n * @example\n * ```typescript\n * // Policy with no config, just options\n * policy(NoJsFileExtensions, { exclude: [\"bin/*\"] })\n *\n * // Policy with config\n * policy(PackageJsonProperties, { verbatim: { license: \"MIT\" } })\n *\n * // Policy with config and options\n * policy(PackageJsonProperties, { verbatim: { license: \"MIT\" } }, { exclude: [\"vendor/*\"] })\n *\n * // Duplicate policies need stable instance IDs\n * policy(PackageJsonProperties, sourceConfig, { instanceId: \"source-packages\" })\n * policy(PackageJsonProperties, testConfig, { instanceId: \"test-packages\" })\n * ```\n *\n * @alpha\n */\nexport function policy<C = void>(\n\tpolicyDef: PolicyShape<C>,\n\toptions?: PolicyOptions & { exclude: (string | RegExp)[] },\n): ConfiguredPolicy<C>;\n/** @alpha */\nexport function policy<C>(\n\tpolicyDef: PolicyShape<C>,\n\tconfig: C,\n\toptions?: PolicyOptions,\n): ConfiguredPolicy<C>;\n/** @alpha */\nexport function policy<C>(\n\tpolicyDef: PolicyShape<C>,\n\tconfigOrOptions?: C | PolicyOptions,\n\tmaybeOptions?: PolicyOptions,\n): ConfiguredPolicy<C> {\n\t// Determine if the second argument is config or options\n\tlet config: C | undefined;\n\tlet options: PolicyOptions | undefined;\n\n\tif (maybeOptions !== undefined) {\n\t\t// Three-argument form: policy(def, config, options)\n\t\tconfig = configOrOptions as C;\n\t\toptions = maybeOptions;\n\t} else if (configOrOptions !== undefined) {\n\t\t// Two-argument form: need to determine if it's config or options\n\t\t// PolicyOptions has a specific shape with 'exclude' property\n\t\tif (\n\t\t\ttypeof configOrOptions === \"object\" &&\n\t\t\tconfigOrOptions !== null &&\n\t\t\t\"exclude\" in configOrOptions &&\n\t\t\t!(\"name\" in configOrOptions) &&\n\t\t\tObject.keys(configOrOptions).every(\n\t\t\t\t(k) => k === \"exclude\" || k === \"instanceId\",\n\t\t\t)\n\t\t) {\n\t\t\t// It's options (has 'exclude' and only option keys)\n\t\t\toptions = configOrOptions as PolicyOptions;\n\t\t} else {\n\t\t\t// It's config\n\t\t\tconfig = configOrOptions as C;\n\t\t}\n\t}\n\n\t// Merge with default config if available\n\tconst effectiveConfig = config ?? (policyDef.defaultConfig as C | undefined);\n\n\t// Support both 'exclude' and 'excludeFiles' for backward compatibility\n\tconst excludePatterns = options?.exclude;\n\n\treturn {\n\t\t...policyDef,\n\t\tconfig: effectiveConfig,\n\t\texclude: excludePatterns,\n\t\texcludeFiles: excludePatterns,\n\t\tinstanceId: options?.instanceId,\n\t\t_internalHandler: normalizeHandler(policyDef.handler),\n\t};\n}\n\n/**\n * Assigns stable identities to configured policy instances.\n *\n * Single instances retain the policy name for compatibility. Duplicate instances\n * must declare explicit identities so their identities remain stable across config\n * reordering and policy renames.\n *\n * @internal\n */\nexport function identifyPolicyInstances<\n\tT extends {\n\t\tname: PolicyName;\n\t\tinstanceId?: PolicyInstanceId | undefined;\n\t},\n>(policies: readonly T[]): (T & { instanceId: PolicyInstanceId })[] {\n\tconst explicitIds = new Set<PolicyInstanceId>();\n\tconst nameCounts = new Map<PolicyName, number>();\n\n\tfor (const configuredPolicy of policies) {\n\t\tnameCounts.set(\n\t\t\tconfiguredPolicy.name,\n\t\t\t(nameCounts.get(configuredPolicy.name) ?? 0) + 1,\n\t\t);\n\t\tif (configuredPolicy.instanceId !== undefined) {\n\t\t\tif (explicitIds.has(configuredPolicy.instanceId)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Duplicate policy instance ID: ${configuredPolicy.instanceId}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\texplicitIds.add(configuredPolicy.instanceId);\n\t\t}\n\t}\n\n\tconst usedIds = new Set(explicitIds);\n\n\treturn policies.map((configuredPolicy) => {\n\t\tif (configuredPolicy.instanceId !== undefined) {\n\t\t\treturn {\n\t\t\t\t...configuredPolicy,\n\t\t\t\tinstanceId: configuredPolicy.instanceId,\n\t\t\t};\n\t\t}\n\n\t\tif ((nameCounts.get(configuredPolicy.name) ?? 0) > 1) {\n\t\t\tthrow new Error(\n\t\t\t\t`Policy '${configuredPolicy.name}' is configured multiple times. Set a unique instanceId for each instance.`,\n\t\t\t);\n\t\t}\n\n\t\tconst instanceId = configuredPolicy.name;\n\t\tif (usedIds.has(instanceId)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Policy instance ID '${instanceId}' conflicts with another configured policy. Set an explicit unique instanceId.`,\n\t\t\t);\n\t\t}\n\t\tusedIds.add(instanceId);\n\n\t\treturn {\n\t\t\t...configuredPolicy,\n\t\t\tinstanceId,\n\t\t};\n\t});\n}\n\n// ============================================================================\n// Legacy API (Still supported for backward compatibility)\n// ============================================================================\n\n/**\n * Input arguments for creating a policy definition.\n *\n * @deprecated Use {@link PolicyShape} directly instead.\n *\n * @alpha\n */\nexport type PolicyDefinitionInput<C = undefined> = PolicyDefinition<C>;\n\n/**\n * Creates a {@link PolicyDefinition} from the provided arguments.\n *\n * @deprecated Define policies as object literals satisfying {@link PolicyShape} instead.\n *\n * @example\n * ```typescript\n * const MyPolicy = makePolicyDefinition({\n * name: \"MyPolicy\",\n * description: \"Ensures files follow conventions\",\n * match: /\\.ts$/,\n * handler: async ({ file }) => true,\n * });\n * ```\n *\n * @alpha\n */\nexport function makePolicyDefinition<C = undefined>(\n\targs: PolicyDefinitionInput<C>,\n): PolicyDefinition<C> {\n\treturn {\n\t\tname: args.name,\n\t\tdescription: args.description,\n\t\tmatch: args.match,\n\t\thandler: args.handler,\n\t\tdefaultConfig: args.defaultConfig,\n\t\tresolver: args.resolver,\n\t};\n}\n\n/**\n * Combine a {@link PolicyDefinition} with a policy-specific config and other settings.\n *\n * @deprecated Use the `policy` function instead, which has a simpler API.\n *\n * @example\n * ```typescript\n * makePolicy(NoJsFileExtensions, undefined, { excludeFiles: [\"bin/*\"] })\n * ```\n *\n * @alpha\n */\nexport function makePolicy<C>(\n\tdefinition: PolicyDefinition<C>,\n\tconfig?: C,\n\tsettings?: PolicyInstanceSettings<C>,\n): PolicyInstance<C> {\n\treturn {\n\t\t...definition,\n\t\t...settings,\n\t\tconfig,\n\t} satisfies PolicyInstance<C>;\n}\n"]}
|
package/esm/perf.d.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import type { Logger } from "@tylerbu/cli-api";
|
|
2
2
|
import type { Operation } from "effection";
|
|
3
|
-
import type {
|
|
3
|
+
import type { PolicyInstanceId } from "./policy.js";
|
|
4
|
+
/**
|
|
5
|
+
* The type of action a policy can perform.
|
|
6
|
+
* @alpha
|
|
7
|
+
*/
|
|
4
8
|
export type PolicyAction = "check" | "resolve" | "handle";
|
|
5
9
|
/**
|
|
6
10
|
* Stores performance data for each handler. Used to collect and display performance stats.
|
|
11
|
+
* @alpha
|
|
7
12
|
*/
|
|
8
13
|
export interface PolicyHandlerPerfStats {
|
|
9
14
|
count: number;
|
|
10
15
|
processed: number;
|
|
11
|
-
data: Map<PolicyAction, Map<
|
|
16
|
+
data: Map<PolicyAction, Map<PolicyInstanceId, number>>;
|
|
12
17
|
}
|
|
13
18
|
export declare function newPerfStats(): PolicyHandlerPerfStats;
|
|
14
19
|
export declare function runWithPerf<T>(name: string, action: PolicyAction, stats: PolicyHandlerPerfStats, run: () => Operation<T>): Operation<T>;
|
package/esm/perf.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perf.d.ts","sourceRoot":"","sources":["../src/perf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"perf.d.ts","sourceRoot":"","sources":["../src/perf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE1D;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC;CACvD;AAED,wBAAgB,YAAY,IAAI,sBAAsB,CAMrD;AAED,wBAAiB,WAAW,CAAC,CAAC,EAC7B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,sBAAsB,EAC7B,GAAG,EAAE,MAAM,SAAS,CAAC,CAAC,CAAC,GACrB,SAAS,CAAC,CAAC,CAAC,CAWd;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAWzE"}
|
package/esm/perf.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perf.js","sourceRoot":"","sources":["../src/perf.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"perf.js","sourceRoot":"","sources":["../src/perf.ts"],"names":[],"mappings":"AAoBA,MAAM,UAAU,YAAY;IAC3B,OAAO;QACN,KAAK,EAAE,CAAC;QACR,SAAS,EAAE,CAAC;QACZ,IAAI,EAAE,IAAI,GAAG,EAA+C;KAC5D,CAAC;AACH,CAAC;AAED,MAAM,SAAS,CAAC,CAAC,WAAW,CAC3B,IAAY,EACZ,MAAoB,EACpB,KAA6B,EAC7B,GAAuB;IAEvB,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAkB,CAAC;IACtE,IAAI,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEnC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC;IAC5B,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;IAE1B,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACzB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC;AACf,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAA6B,EAAE,GAAW;IAClE,GAAG,CAAC,GAAG,CACN,eAAe,KAAK,CAAC,SAAS,oBAAoB;QACjD,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,SAAS,cAAc,KAAK,CAAC,KAAK,QAAQ,CAClE,CAAC;IACF,KAAK,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;QAC1D,GAAG,CAAC,GAAG,CAAC,oBAAoB,MAAM,IAAI,CAAC,CAAC;QACxC,KAAK,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;YACpD,GAAG,CAAC,GAAG,CAAC,OAAO,OAAO,KAAK,GAAG,IAAI,CAAC,CAAC;QACrC,CAAC;IACF,CAAC;AACF,CAAC","sourcesContent":["import type { Logger } from \"@tylerbu/cli-api\";\nimport type { Operation } from \"effection\";\nimport type { PolicyInstanceId } from \"./policy.js\";\n\n/**\n * The type of action a policy can perform.\n * @alpha\n */\nexport type PolicyAction = \"check\" | \"resolve\" | \"handle\";\n\n/**\n * Stores performance data for each handler. Used to collect and display performance stats.\n * @alpha\n */\nexport interface PolicyHandlerPerfStats {\n\tcount: number;\n\tprocessed: number;\n\tdata: Map<PolicyAction, Map<PolicyInstanceId, number>>;\n}\n\nexport function newPerfStats(): PolicyHandlerPerfStats {\n\treturn {\n\t\tcount: 0,\n\t\tprocessed: 0,\n\t\tdata: new Map<PolicyAction, Map<PolicyInstanceId, number>>(),\n\t};\n}\n\nexport function* runWithPerf<T>(\n\tname: string,\n\taction: PolicyAction,\n\tstats: PolicyHandlerPerfStats,\n\trun: () => Operation<T>,\n): Operation<T> {\n\tconst actionMap = stats.data.get(action) ?? new Map<string, number>();\n\tlet dur = actionMap.get(name) ?? 0;\n\n\tconst start = Date.now();\n\tconst result = yield* run();\n\tdur += Date.now() - start;\n\n\tactionMap.set(name, dur);\n\tstats.data.set(action, actionMap);\n\treturn result;\n}\n\nexport function logStats(stats: PolicyHandlerPerfStats, log: Logger): void {\n\tlog.log(\n\t\t`Statistics: ${stats.processed} files processed, ` +\n\t\t\t`${stats.count - stats.processed} excluded, ${stats.count} total`,\n\t);\n\tfor (const [action, handlerPerf] of stats.data.entries()) {\n\t\tlog.log(`Performance for \"${action}\":`);\n\t\tfor (const [handler, dur] of handlerPerf.entries()) {\n\t\t\tlog.log(` ${handler}: ${dur}ms`);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { PolicyShape } from "../policy.js";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for the CargoLicenceValidated policy.
|
|
4
|
+
*
|
|
5
|
+
* @alpha
|
|
6
|
+
*/
|
|
7
|
+
export interface CargoLicenceValidatedConfig {
|
|
8
|
+
/**
|
|
9
|
+
* Allowed SPDX licence identifiers. If set, only these are accepted.
|
|
10
|
+
*/
|
|
11
|
+
allowedLicences?: string[];
|
|
12
|
+
/**
|
|
13
|
+
* If true, validate the licence value against the SPDX licence list
|
|
14
|
+
* using `spdx-correct`. When enabled, typos like "MIIT" are detected
|
|
15
|
+
* and can be auto-fixed to the correct identifier ("MIT").
|
|
16
|
+
*
|
|
17
|
+
* Requires the optional peer dependency `spdx-correct` to be installed.
|
|
18
|
+
*
|
|
19
|
+
* @defaultValue true
|
|
20
|
+
*/
|
|
21
|
+
validateSpdx?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* If true, skip workspace-only Cargo.toml files (those without a [package] section).
|
|
24
|
+
*
|
|
25
|
+
* @defaultValue true
|
|
26
|
+
*/
|
|
27
|
+
skipWorkspace?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A policy that validates the `license` field in Cargo.toml against the SPDX
|
|
31
|
+
* licence list. Supports auto-fixing correctable identifiers.
|
|
32
|
+
*
|
|
33
|
+
* @remarks
|
|
34
|
+
* Cargo.toml uses a single `license` string field (not an array like Gleam's
|
|
35
|
+
* `licences`). This policy validates that the value is a recognized SPDX
|
|
36
|
+
* identifier and can auto-fix common mistakes like wrong casing.
|
|
37
|
+
*
|
|
38
|
+
* @alpha
|
|
39
|
+
*/
|
|
40
|
+
export declare const CargoLicenceValidated: PolicyShape<CargoLicenceValidatedConfig>;
|
|
41
|
+
//# sourceMappingURL=CargoLicenceValidated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CargoLicenceValidated.d.ts","sourceRoot":"","sources":["../../src/policies/CargoLicenceValidated.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAOhD;;;;GAIG;AACH,MAAM,WAAW,2BAA2B;IAC3C;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAKD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAAC,2BAA2B,CAuCxE,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { resolve } from "pathe";
|
|
2
|
+
import { defineCargoPolicy, } from "../policyDefiners/defineCargoPolicy.js";
|
|
3
|
+
import { validateLicenceField } from "../policyDefiners/spdxValidator.js";
|
|
4
|
+
const MANUAL_FIX = "Use a valid SPDX licence identifier (e.g., MIT, Apache-2.0, MPL-2.0).";
|
|
5
|
+
/**
|
|
6
|
+
* A policy that validates the `license` field in Cargo.toml against the SPDX
|
|
7
|
+
* licence list. Supports auto-fixing correctable identifiers.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* Cargo.toml uses a single `license` string field (not an array like Gleam's
|
|
11
|
+
* `licences`). This policy validates that the value is a recognized SPDX
|
|
12
|
+
* identifier and can auto-fix common mistakes like wrong casing.
|
|
13
|
+
*
|
|
14
|
+
* @alpha
|
|
15
|
+
*/
|
|
16
|
+
export const CargoLicenceValidated = defineCargoPolicy({
|
|
17
|
+
name: "CargoLicenceValidated",
|
|
18
|
+
description: "Validates that Cargo.toml has a valid SPDX licence identifier.",
|
|
19
|
+
handler: async (toml, { file, root, resolve: shouldResolve, config }) => {
|
|
20
|
+
const skipWorkspace = config?.skipWorkspace ?? true;
|
|
21
|
+
const pkg = toml.package;
|
|
22
|
+
if (!pkg && skipWorkspace) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
const licence = pkg?.license;
|
|
26
|
+
if (!licence || licence.trim() === "") {
|
|
27
|
+
return {
|
|
28
|
+
error: "Missing or empty license field in [package] section.",
|
|
29
|
+
manualFix: 'Add license = "MIT" (or appropriate SPDX identifier) to [package] in Cargo.toml.',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const result = await validateLicenceField({
|
|
33
|
+
licences: [licence],
|
|
34
|
+
...(config?.allowedLicences !== undefined && {
|
|
35
|
+
allowedLicences: config.allowedLicences,
|
|
36
|
+
}),
|
|
37
|
+
validateSpdx: config?.validateSpdx ?? true,
|
|
38
|
+
shouldResolve,
|
|
39
|
+
filePath: resolve(root, file),
|
|
40
|
+
manualFixMessage: MANUAL_FIX,
|
|
41
|
+
});
|
|
42
|
+
return result ?? true;
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=CargoLicenceValidated.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CargoLicenceValidated.js","sourceRoot":"","sources":["../../src/policies/CargoLicenceValidated.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,EAEN,iBAAiB,GACjB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAgC1E,MAAM,UAAU,GACf,uEAAuE,CAAC;AAEzE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,qBAAqB,GACjC,iBAAiB,CAAC;IACjB,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EACV,gEAAgE;IACjE,OAAO,EAAE,KAAK,EACb,IAAe,EACf,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,EAC7C,EAAE;QACH,MAAM,aAAa,GAAG,MAAM,EAAE,aAAa,IAAI,IAAI,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,OAA8C,CAAC;QAEhE,IAAI,CAAC,GAAG,IAAI,aAAa,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC;QACb,CAAC;QAED,MAAM,OAAO,GAAG,GAAG,EAAE,OAA6B,CAAC;QAEnD,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACvC,OAAO;gBACN,KAAK,EAAE,sDAAsD;gBAC7D,SAAS,EACR,kFAAkF;aACnF,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC;YACzC,QAAQ,EAAE,CAAC,OAAO,CAAC;YACnB,GAAG,CAAC,MAAM,EAAE,eAAe,KAAK,SAAS,IAAI;gBAC5C,eAAe,EAAE,MAAM,CAAC,eAAe;aACvC,CAAC;YACF,YAAY,EAAE,MAAM,EAAE,YAAY,IAAI,IAAI;YAC1C,aAAa;YACb,QAAQ,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC;YAC7B,gBAAgB,EAAE,UAAU;SAC5B,CAAC,CAAC;QAEH,OAAO,MAAM,IAAI,IAAI,CAAC;IACvB,CAAC;CACD,CAAC,CAAC","sourcesContent":["import { resolve } from \"pathe\";\nimport type { PolicyShape } from \"../policy.js\";\nimport {\n\ttype CargoToml,\n\tdefineCargoPolicy,\n} from \"../policyDefiners/defineCargoPolicy.js\";\nimport { validateLicenceField } from \"../policyDefiners/spdxValidator.js\";\n\n/**\n * Configuration for the CargoLicenceValidated policy.\n *\n * @alpha\n */\nexport interface CargoLicenceValidatedConfig {\n\t/**\n\t * Allowed SPDX licence identifiers. If set, only these are accepted.\n\t */\n\tallowedLicences?: string[];\n\n\t/**\n\t * If true, validate the licence value against the SPDX licence list\n\t * using `spdx-correct`. When enabled, typos like \"MIIT\" are detected\n\t * and can be auto-fixed to the correct identifier (\"MIT\").\n\t *\n\t * Requires the optional peer dependency `spdx-correct` to be installed.\n\t *\n\t * @defaultValue true\n\t */\n\tvalidateSpdx?: boolean;\n\n\t/**\n\t * If true, skip workspace-only Cargo.toml files (those without a [package] section).\n\t *\n\t * @defaultValue true\n\t */\n\tskipWorkspace?: boolean;\n}\n\nconst MANUAL_FIX =\n\t\"Use a valid SPDX licence identifier (e.g., MIT, Apache-2.0, MPL-2.0).\";\n\n/**\n * A policy that validates the `license` field in Cargo.toml against the SPDX\n * licence list. Supports auto-fixing correctable identifiers.\n *\n * @remarks\n * Cargo.toml uses a single `license` string field (not an array like Gleam's\n * `licences`). This policy validates that the value is a recognized SPDX\n * identifier and can auto-fix common mistakes like wrong casing.\n *\n * @alpha\n */\nexport const CargoLicenceValidated: PolicyShape<CargoLicenceValidatedConfig> =\n\tdefineCargoPolicy({\n\t\tname: \"CargoLicenceValidated\",\n\t\tdescription:\n\t\t\t\"Validates that Cargo.toml has a valid SPDX licence identifier.\",\n\t\thandler: async (\n\t\t\ttoml: CargoToml,\n\t\t\t{ file, root, resolve: shouldResolve, config },\n\t\t) => {\n\t\t\tconst skipWorkspace = config?.skipWorkspace ?? true;\n\t\t\tconst pkg = toml.package as Record<string, unknown> | undefined;\n\n\t\t\tif (!pkg && skipWorkspace) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst licence = pkg?.license as string | undefined;\n\n\t\t\tif (!licence || licence.trim() === \"\") {\n\t\t\t\treturn {\n\t\t\t\t\terror: \"Missing or empty license field in [package] section.\",\n\t\t\t\t\tmanualFix:\n\t\t\t\t\t\t'Add license = \"MIT\" (or appropriate SPDX identifier) to [package] in Cargo.toml.',\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst result = await validateLicenceField({\n\t\t\t\tlicences: [licence],\n\t\t\t\t...(config?.allowedLicences !== undefined && {\n\t\t\t\t\tallowedLicences: config.allowedLicences,\n\t\t\t\t}),\n\t\t\t\tvalidateSpdx: config?.validateSpdx ?? true,\n\t\t\t\tshouldResolve,\n\t\t\t\tfilePath: resolve(root, file),\n\t\t\t\tmanualFixMessage: MANUAL_FIX,\n\t\t\t});\n\n\t\t\treturn result ?? true;\n\t\t},\n\t});\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PolicyShape } from "../policy.js";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for the CargoLintsConfigured policy.
|
|
4
|
+
*
|
|
5
|
+
* @alpha
|
|
6
|
+
*/
|
|
7
|
+
export interface CargoLintsConfiguredConfig {
|
|
8
|
+
/**
|
|
9
|
+
* Required clippy lint levels. Keys are lint names (without the `clippy::` prefix),
|
|
10
|
+
* values are the minimum level ("warn" or "deny").
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* { pedantic: "warn", nursery: "warn" }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
required?: Record<string, string>;
|
|
18
|
+
/**
|
|
19
|
+
* If true, just require that a [lints.clippy] section exists (without checking specific lints).
|
|
20
|
+
* @defaultValue true
|
|
21
|
+
*/
|
|
22
|
+
requireSection?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A policy that ensures Cargo.toml has a [lints.clippy] section configured.
|
|
26
|
+
*
|
|
27
|
+
* @alpha
|
|
28
|
+
*/
|
|
29
|
+
export declare const CargoLintsConfigured: PolicyShape<CargoLintsConfiguredConfig>;
|
|
30
|
+
//# sourceMappingURL=CargoLintsConfigured.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CargoLintsConfigured.d.ts","sourceRoot":"","sources":["../../src/policies/CargoLintsConfigured.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,WAAW,EAAE,MAAM,cAAc,CAAC;AAMrE;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IAC1C;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAElC;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAgED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,WAAW,CAAC,0BAA0B,CAatE,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { defineCargoPolicy, } from "../policyDefiners/defineCargoPolicy.js";
|
|
2
|
+
function checkClippyLints(clippy, required) {
|
|
3
|
+
const errors = [];
|
|
4
|
+
for (const [lint, expectedLevel] of Object.entries(required)) {
|
|
5
|
+
const actual = clippy[lint];
|
|
6
|
+
if (actual === undefined) {
|
|
7
|
+
errors.push(`Missing clippy lint: ${lint} (expected level: "${expectedLevel}")`);
|
|
8
|
+
}
|
|
9
|
+
else if (String(actual) !== expectedLevel) {
|
|
10
|
+
errors.push(`Clippy lint ${lint} = "${String(actual)}", expected "${expectedLevel}"`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return errors;
|
|
14
|
+
}
|
|
15
|
+
function checkLintsSection(toml, config) {
|
|
16
|
+
const lints = toml.lints;
|
|
17
|
+
const requireSection = config?.requireSection ?? true;
|
|
18
|
+
if (requireSection && lints === undefined) {
|
|
19
|
+
return {
|
|
20
|
+
error: "Missing [lints] section in Cargo.toml.",
|
|
21
|
+
manualFix: 'Add a [lints.clippy] section, e.g.:\n[lints.clippy]\npedantic = "warn"',
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (lints === undefined) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
const clippy = lints.clippy;
|
|
28
|
+
if (requireSection && clippy === undefined) {
|
|
29
|
+
return {
|
|
30
|
+
error: "Missing [lints.clippy] section in Cargo.toml.",
|
|
31
|
+
manualFix: 'Add a [lints.clippy] section, e.g.:\n[lints.clippy]\npedantic = "warn"',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (config?.required && clippy) {
|
|
35
|
+
const errors = checkClippyLints(clippy, config.required);
|
|
36
|
+
if (errors.length > 0) {
|
|
37
|
+
return {
|
|
38
|
+
error: errors.join("; "),
|
|
39
|
+
manualFix: "Update the [lints.clippy] section with the required lint levels.",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A policy that ensures Cargo.toml has a [lints.clippy] section configured.
|
|
47
|
+
*
|
|
48
|
+
* @alpha
|
|
49
|
+
*/
|
|
50
|
+
export const CargoLintsConfigured = defineCargoPolicy({
|
|
51
|
+
name: "CargoLintsConfigured",
|
|
52
|
+
description: "Ensures Cargo.toml has clippy lints configured in the [lints] section.",
|
|
53
|
+
handler: async (toml, { config }) => {
|
|
54
|
+
// Skip workspace root Cargo.toml files
|
|
55
|
+
if (toml.workspace !== undefined && toml.package === undefined) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return checkLintsSection(toml, config);
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
//# sourceMappingURL=CargoLintsConfigured.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CargoLintsConfigured.js","sourceRoot":"","sources":["../../src/policies/CargoLintsConfigured.ts"],"names":[],"mappings":"AACA,OAAO,EAEN,iBAAiB,GACjB,MAAM,wCAAwC,CAAC;AA0BhD,SAAS,gBAAgB,CACxB,MAA+B,EAC/B,QAAgC;IAEhC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9D,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CACV,wBAAwB,IAAI,sBAAsB,aAAa,IAAI,CACnE,CAAC;QACH,CAAC;aAAM,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,aAAa,EAAE,CAAC;YAC7C,MAAM,CAAC,IAAI,CACV,eAAe,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,gBAAgB,aAAa,GAAG,CACxE,CAAC;QACH,CAAC;IACF,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAED,SAAS,iBAAiB,CACzB,IAAe,EACf,MAA8C;IAE9C,MAAM,KAAK,GAAG,IAAI,CAAC,KAA4C,CAAC;IAChE,MAAM,cAAc,GAAG,MAAM,EAAE,cAAc,IAAI,IAAI,CAAC;IAEtD,IAAI,cAAc,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC3C,OAAO;YACN,KAAK,EAAE,wCAAwC;YAC/C,SAAS,EACR,wEAAwE;SACzE,CAAC;IACH,CAAC;IAED,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,MAA6C,CAAC;IACnE,IAAI,cAAc,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC5C,OAAO;YACN,KAAK,EAAE,+CAA+C;YACtD,SAAS,EACR,wEAAwE;SACzE,CAAC;IACH,CAAC;IAED,IAAI,MAAM,EAAE,QAAQ,IAAI,MAAM,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO;gBACN,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;gBACxB,SAAS,EACR,kEAAkE;aACnE,CAAC;QACH,CAAC;IACF,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAChC,iBAAiB,CAAC;IACjB,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EACV,wEAAwE;IACzE,OAAO,EAAE,KAAK,EAAE,IAAe,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QAC9C,uCAAuC;QACvC,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAChE,OAAO,IAAI,CAAC;QACb,CAAC;QAED,OAAO,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;CACD,CAAC,CAAC","sourcesContent":["import type { PolicyHandlerResult, PolicyShape } from \"../policy.js\";\nimport {\n\ttype CargoToml,\n\tdefineCargoPolicy,\n} from \"../policyDefiners/defineCargoPolicy.js\";\n\n/**\n * Configuration for the CargoLintsConfigured policy.\n *\n * @alpha\n */\nexport interface CargoLintsConfiguredConfig {\n\t/**\n\t * Required clippy lint levels. Keys are lint names (without the `clippy::` prefix),\n\t * values are the minimum level (\"warn\" or \"deny\").\n\t *\n\t * @example\n\t * ```typescript\n\t * { pedantic: \"warn\", nursery: \"warn\" }\n\t * ```\n\t */\n\trequired?: Record<string, string>;\n\n\t/**\n\t * If true, just require that a [lints.clippy] section exists (without checking specific lints).\n\t * @defaultValue true\n\t */\n\trequireSection?: boolean;\n}\n\nfunction checkClippyLints(\n\tclippy: Record<string, unknown>,\n\trequired: Record<string, string>,\n): string[] {\n\tconst errors: string[] = [];\n\tfor (const [lint, expectedLevel] of Object.entries(required)) {\n\t\tconst actual = clippy[lint];\n\t\tif (actual === undefined) {\n\t\t\terrors.push(\n\t\t\t\t`Missing clippy lint: ${lint} (expected level: \"${expectedLevel}\")`,\n\t\t\t);\n\t\t} else if (String(actual) !== expectedLevel) {\n\t\t\terrors.push(\n\t\t\t\t`Clippy lint ${lint} = \"${String(actual)}\", expected \"${expectedLevel}\"`,\n\t\t\t);\n\t\t}\n\t}\n\treturn errors;\n}\n\nfunction checkLintsSection(\n\ttoml: CargoToml,\n\tconfig: CargoLintsConfiguredConfig | undefined,\n): PolicyHandlerResult {\n\tconst lints = toml.lints as Record<string, unknown> | undefined;\n\tconst requireSection = config?.requireSection ?? true;\n\n\tif (requireSection && lints === undefined) {\n\t\treturn {\n\t\t\terror: \"Missing [lints] section in Cargo.toml.\",\n\t\t\tmanualFix:\n\t\t\t\t'Add a [lints.clippy] section, e.g.:\\n[lints.clippy]\\npedantic = \"warn\"',\n\t\t};\n\t}\n\n\tif (lints === undefined) {\n\t\treturn true;\n\t}\n\n\tconst clippy = lints.clippy as Record<string, unknown> | undefined;\n\tif (requireSection && clippy === undefined) {\n\t\treturn {\n\t\t\terror: \"Missing [lints.clippy] section in Cargo.toml.\",\n\t\t\tmanualFix:\n\t\t\t\t'Add a [lints.clippy] section, e.g.:\\n[lints.clippy]\\npedantic = \"warn\"',\n\t\t};\n\t}\n\n\tif (config?.required && clippy) {\n\t\tconst errors = checkClippyLints(clippy, config.required);\n\t\tif (errors.length > 0) {\n\t\t\treturn {\n\t\t\t\terror: errors.join(\"; \"),\n\t\t\t\tmanualFix:\n\t\t\t\t\t\"Update the [lints.clippy] section with the required lint levels.\",\n\t\t\t};\n\t\t}\n\t}\n\n\treturn true;\n}\n\n/**\n * A policy that ensures Cargo.toml has a [lints.clippy] section configured.\n *\n * @alpha\n */\nexport const CargoLintsConfigured: PolicyShape<CargoLintsConfiguredConfig> =\n\tdefineCargoPolicy({\n\t\tname: \"CargoLintsConfigured\",\n\t\tdescription:\n\t\t\t\"Ensures Cargo.toml has clippy lints configured in the [lints] section.\",\n\t\thandler: async (toml: CargoToml, { config }) => {\n\t\t\t// Skip workspace root Cargo.toml files\n\t\t\tif (toml.workspace !== undefined && toml.package === undefined) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn checkLintsSection(toml, config);\n\t\t},\n\t});\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { PolicyShape } from "../policy.js";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for the CargoLockPolicy.
|
|
4
|
+
*
|
|
5
|
+
* @alpha
|
|
6
|
+
*/
|
|
7
|
+
export interface CargoLockPolicyConfig {
|
|
8
|
+
/**
|
|
9
|
+
* Policy for binary crates.
|
|
10
|
+
* - "require": Cargo.lock must be committed (default for binaries)
|
|
11
|
+
* - "warn": Emit a warning if missing
|
|
12
|
+
* - "ignore": Skip check
|
|
13
|
+
*
|
|
14
|
+
* @defaultValue "require"
|
|
15
|
+
*/
|
|
16
|
+
binaries?: "require" | "warn" | "ignore";
|
|
17
|
+
/**
|
|
18
|
+
* Policy for library crates.
|
|
19
|
+
* - "require": Cargo.lock must be committed
|
|
20
|
+
* - "warn": Emit a warning if committed (default for libraries)
|
|
21
|
+
* - "ignore": Skip check
|
|
22
|
+
*
|
|
23
|
+
* @defaultValue "ignore"
|
|
24
|
+
*/
|
|
25
|
+
libraries?: "require" | "warn" | "ignore";
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A context-aware policy for Cargo.lock files.
|
|
29
|
+
* Binary crates should commit Cargo.lock; library crates typically shouldn't.
|
|
30
|
+
*
|
|
31
|
+
* @alpha
|
|
32
|
+
*/
|
|
33
|
+
export declare const CargoLockPolicy: PolicyShape<CargoLockPolicyConfig>;
|
|
34
|
+
//# sourceMappingURL=CargoLockPolicy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CargoLockPolicy.d.ts","sourceRoot":"","sources":["../../src/policies/CargoLockPolicy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAMhD;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACrC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;IAEzC;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;CAC1C;AAsBD;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,qBAAqB,CAuC5D,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import path from "pathe";
|
|
3
|
+
import { defineCargoPolicy, } from "../policyDefiners/defineCargoPolicy.js";
|
|
4
|
+
function isBinaryCrate(toml) {
|
|
5
|
+
// Has [[bin]] entries
|
|
6
|
+
if (Array.isArray(toml.bin) && toml.bin.length > 0) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
// Has a default binary (src/main.rs is handled by Cargo implicitly)
|
|
10
|
+
const pkg = toml.package;
|
|
11
|
+
if (pkg) {
|
|
12
|
+
// If there's no explicit lib section and no [[bin]], Cargo assumes binary
|
|
13
|
+
// if src/main.rs exists, but we can't check filesystem here.
|
|
14
|
+
// Best heuristic: if there's no [lib] section, it could be a binary.
|
|
15
|
+
return toml.lib === undefined;
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
function isLibraryCrate(toml) {
|
|
20
|
+
return toml.lib !== undefined;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A context-aware policy for Cargo.lock files.
|
|
24
|
+
* Binary crates should commit Cargo.lock; library crates typically shouldn't.
|
|
25
|
+
*
|
|
26
|
+
* @alpha
|
|
27
|
+
*/
|
|
28
|
+
export const CargoLockPolicy = defineCargoPolicy({
|
|
29
|
+
name: "CargoLockPolicy",
|
|
30
|
+
description: "Context-aware Cargo.lock validation: binaries should commit it, libraries typically should not.",
|
|
31
|
+
handler: async (toml, { root, file, config }) => {
|
|
32
|
+
// Skip workspace root Cargo.toml
|
|
33
|
+
if (toml.workspace !== undefined && toml.package === undefined) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
const dir = path.dirname(path.resolve(root, file));
|
|
37
|
+
const lockExists = existsSync(path.join(dir, "Cargo.lock"));
|
|
38
|
+
const isBinary = isBinaryCrate(toml);
|
|
39
|
+
const isLib = isLibraryCrate(toml);
|
|
40
|
+
const binaryPolicy = config?.binaries ?? "require";
|
|
41
|
+
const libraryPolicy = config?.libraries ?? "ignore";
|
|
42
|
+
if (isBinary && binaryPolicy === "require" && !lockExists) {
|
|
43
|
+
return {
|
|
44
|
+
error: "Binary crate is missing Cargo.lock. Binary crates should commit their lockfile for reproducible builds.",
|
|
45
|
+
manualFix: "Run `cargo generate-lockfile` and commit the Cargo.lock file.",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (isLib && !isBinary && libraryPolicy === "warn" && lockExists) {
|
|
49
|
+
return {
|
|
50
|
+
error: "Library crate has Cargo.lock committed. Library crates typically should not commit their lockfile.",
|
|
51
|
+
manualFix: "Consider adding Cargo.lock to .gitignore for library crates.",
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
//# sourceMappingURL=CargoLockPolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CargoLockPolicy.js","sourceRoot":"","sources":["../../src/policies/CargoLockPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,IAAI,MAAM,OAAO,CAAC;AAEzB,OAAO,EAEN,iBAAiB,GACjB,MAAM,wCAAwC,CAAC;AA6BhD,SAAS,aAAa,CAAC,IAAe;IACrC,sBAAsB;IACtB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpD,OAAO,IAAI,CAAC;IACb,CAAC;IACD,oEAAoE;IACpE,MAAM,GAAG,GAAG,IAAI,CAAC,OAA8C,CAAC;IAChE,IAAI,GAAG,EAAE,CAAC;QACT,0EAA0E;QAC1E,6DAA6D;QAC7D,qEAAqE;QACrE,OAAO,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC;IAC/B,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,SAAS,cAAc,CAAC,IAAe;IACtC,OAAO,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC;AAC/B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAC3B,iBAAiB,CAAC;IACjB,IAAI,EAAE,iBAAiB;IACvB,WAAW,EACV,iGAAiG;IAClG,OAAO,EAAE,KAAK,EAAE,IAAe,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;QAC1D,iCAAiC;QACjC,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAChE,OAAO,IAAI,CAAC;QACb,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACnD,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC;QAC5D,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QAEnC,MAAM,YAAY,GAAG,MAAM,EAAE,QAAQ,IAAI,SAAS,CAAC;QACnD,MAAM,aAAa,GAAG,MAAM,EAAE,SAAS,IAAI,QAAQ,CAAC;QAEpD,IAAI,QAAQ,IAAI,YAAY,KAAK,SAAS,IAAI,CAAC,UAAU,EAAE,CAAC;YAC3D,OAAO;gBACN,KAAK,EACJ,yGAAyG;gBAC1G,SAAS,EACR,+DAA+D;aAChE,CAAC;QACH,CAAC;QAED,IAAI,KAAK,IAAI,CAAC,QAAQ,IAAI,aAAa,KAAK,MAAM,IAAI,UAAU,EAAE,CAAC;YAClE,OAAO;gBACN,KAAK,EACJ,oGAAoG;gBACrG,SAAS,EACR,8DAA8D;aAC/D,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;CACD,CAAC,CAAC","sourcesContent":["import { existsSync } from \"node:fs\";\nimport path from \"pathe\";\nimport type { PolicyShape } from \"../policy.js\";\nimport {\n\ttype CargoToml,\n\tdefineCargoPolicy,\n} from \"../policyDefiners/defineCargoPolicy.js\";\n\n/**\n * Configuration for the CargoLockPolicy.\n *\n * @alpha\n */\nexport interface CargoLockPolicyConfig {\n\t/**\n\t * Policy for binary crates.\n\t * - \"require\": Cargo.lock must be committed (default for binaries)\n\t * - \"warn\": Emit a warning if missing\n\t * - \"ignore\": Skip check\n\t *\n\t * @defaultValue \"require\"\n\t */\n\tbinaries?: \"require\" | \"warn\" | \"ignore\";\n\n\t/**\n\t * Policy for library crates.\n\t * - \"require\": Cargo.lock must be committed\n\t * - \"warn\": Emit a warning if committed (default for libraries)\n\t * - \"ignore\": Skip check\n\t *\n\t * @defaultValue \"ignore\"\n\t */\n\tlibraries?: \"require\" | \"warn\" | \"ignore\";\n}\n\nfunction isBinaryCrate(toml: CargoToml): boolean {\n\t// Has [[bin]] entries\n\tif (Array.isArray(toml.bin) && toml.bin.length > 0) {\n\t\treturn true;\n\t}\n\t// Has a default binary (src/main.rs is handled by Cargo implicitly)\n\tconst pkg = toml.package as Record<string, unknown> | undefined;\n\tif (pkg) {\n\t\t// If there's no explicit lib section and no [[bin]], Cargo assumes binary\n\t\t// if src/main.rs exists, but we can't check filesystem here.\n\t\t// Best heuristic: if there's no [lib] section, it could be a binary.\n\t\treturn toml.lib === undefined;\n\t}\n\treturn false;\n}\n\nfunction isLibraryCrate(toml: CargoToml): boolean {\n\treturn toml.lib !== undefined;\n}\n\n/**\n * A context-aware policy for Cargo.lock files.\n * Binary crates should commit Cargo.lock; library crates typically shouldn't.\n *\n * @alpha\n */\nexport const CargoLockPolicy: PolicyShape<CargoLockPolicyConfig> =\n\tdefineCargoPolicy({\n\t\tname: \"CargoLockPolicy\",\n\t\tdescription:\n\t\t\t\"Context-aware Cargo.lock validation: binaries should commit it, libraries typically should not.\",\n\t\thandler: async (toml: CargoToml, { root, file, config }) => {\n\t\t\t// Skip workspace root Cargo.toml\n\t\t\tif (toml.workspace !== undefined && toml.package === undefined) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst dir = path.dirname(path.resolve(root, file));\n\t\t\tconst lockExists = existsSync(path.join(dir, \"Cargo.lock\"));\n\t\t\tconst isBinary = isBinaryCrate(toml);\n\t\t\tconst isLib = isLibraryCrate(toml);\n\n\t\t\tconst binaryPolicy = config?.binaries ?? \"require\";\n\t\t\tconst libraryPolicy = config?.libraries ?? \"ignore\";\n\n\t\t\tif (isBinary && binaryPolicy === \"require\" && !lockExists) {\n\t\t\t\treturn {\n\t\t\t\t\terror:\n\t\t\t\t\t\t\"Binary crate is missing Cargo.lock. Binary crates should commit their lockfile for reproducible builds.\",\n\t\t\t\t\tmanualFix:\n\t\t\t\t\t\t\"Run `cargo generate-lockfile` and commit the Cargo.lock file.\",\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (isLib && !isBinary && libraryPolicy === \"warn\" && lockExists) {\n\t\t\t\treturn {\n\t\t\t\t\terror:\n\t\t\t\t\t\t\"Library crate has Cargo.lock committed. Library crates typically should not commit their lockfile.\",\n\t\t\t\t\tmanualFix:\n\t\t\t\t\t\t\"Consider adding Cargo.lock to .gitignore for library crates.\",\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn true;\n\t\t},\n\t});\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { PolicyShape } from "../policy.js";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for the CargoTomlRequired policy.
|
|
4
|
+
*
|
|
5
|
+
* @alpha
|
|
6
|
+
*/
|
|
7
|
+
export interface CargoTomlRequiredConfig {
|
|
8
|
+
/**
|
|
9
|
+
* Fields that must exist in the [package] section.
|
|
10
|
+
* @defaultValue ["license", "description"]
|
|
11
|
+
*/
|
|
12
|
+
required?: string[];
|
|
13
|
+
/**
|
|
14
|
+
* Minimum Rust edition to require (e.g., "2021").
|
|
15
|
+
* If set, the `edition` field must exist and be >= this value.
|
|
16
|
+
*/
|
|
17
|
+
minimumEdition?: string;
|
|
18
|
+
/**
|
|
19
|
+
* If true, require the `rust-version` field (MSRV) to be set.
|
|
20
|
+
* @defaultValue false
|
|
21
|
+
*/
|
|
22
|
+
requireRustVersion?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Specific field values to enforce. Keys are field names, values are expected values.
|
|
25
|
+
*/
|
|
26
|
+
expectedValues?: Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A policy that enforces required fields exist in Cargo.toml [package] section.
|
|
30
|
+
*
|
|
31
|
+
* @alpha
|
|
32
|
+
*/
|
|
33
|
+
export declare const CargoTomlRequired: PolicyShape<CargoTomlRequiredConfig>;
|
|
34
|
+
//# sourceMappingURL=CargoTomlRequired.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CargoTomlRequired.d.ts","sourceRoot":"","sources":["../../src/policies/CargoTomlRequired.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAMhD;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACvC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAwED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,uBAAuB,CA+BhE,CAAC"}
|