repopo 0.10.0 → 0.13.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 +113 -0
- package/README.md +76 -77
- package/THIRD-PARTY-LICENSES.txt +232 -14
- package/bin/dev.js +5 -1
- package/esm/adapters/fluidFramework.d.ts +13 -9
- package/esm/adapters/fluidFramework.d.ts.map +1 -1
- package/esm/adapters/fluidFramework.js +20 -43
- package/esm/adapters/fluidFramework.js.map +1 -1
- package/esm/api.d.ts +64 -1
- package/esm/api.d.ts.map +1 -1
- package/esm/api.js +17 -1
- package/esm/api.js.map +1 -1
- package/esm/baseCommand.d.ts +1 -1
- package/esm/baseCommand.d.ts.map +1 -1
- package/esm/baseCommand.js +7 -10
- 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 +156 -0
- package/esm/commands/check-native.js.map +1 -0
- package/esm/commands/check.d.ts +7 -34
- package/esm/commands/check.d.ts.map +1 -1
- package/esm/commands/check.js +76 -265
- package/esm/commands/check.js.map +1 -1
- package/esm/commands/list.d.ts.map +1 -1
- package/esm/commands/list.js +6 -6
- package/esm/commands/list.js.map +1 -1
- package/esm/concurrency.d.ts +3 -0
- package/esm/concurrency.d.ts.map +1 -0
- package/esm/concurrency.js +8 -0
- package/esm/concurrency.js.map +1 -0
- package/esm/config.d.ts +5 -39
- package/esm/config.d.ts.map +1 -1
- package/esm/config.js +3 -7
- package/esm/config.js.map +1 -1
- package/esm/context.d.ts +20 -3
- package/esm/context.d.ts.map +1 -1
- package/esm/context.js +18 -1
- package/esm/context.js.map +1 -1
- package/esm/executionContractError.d.ts +4 -0
- package/esm/executionContractError.d.ts.map +1 -0
- package/esm/executionContractError.js +4 -0
- package/esm/executionContractError.js.map +1 -0
- package/esm/fileCache.d.ts +12 -0
- package/esm/fileCache.d.ts.map +1 -0
- package/esm/fileCache.js +37 -0
- package/esm/fileCache.js.map +1 -0
- package/esm/filePaths.d.ts +2 -0
- package/esm/filePaths.d.ts.map +1 -0
- package/esm/filePaths.js +9 -0
- package/esm/filePaths.js.map +1 -0
- package/esm/generators.d.ts +0 -20
- package/esm/generators.d.ts.map +1 -1
- package/esm/generators.js.map +1 -1
- package/esm/index.d.ts +3 -11
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +3 -14
- package/esm/index.js.map +1 -1
- package/esm/makePolicy.d.ts +26 -79
- package/esm/makePolicy.d.ts.map +1 -1
- package/esm/makePolicy.js +51 -95
- package/esm/makePolicy.js.map +1 -1
- package/esm/perf.d.ts +10 -2
- package/esm/perf.d.ts.map +1 -1
- package/esm/perf.js +10 -9
- 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 +47 -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 +65 -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 +61 -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 +168 -0
- package/esm/policies/CargoTomlSorted.js.map +1 -0
- package/esm/policies/ConditionalScripts.d.ts +10 -8
- package/esm/policies/ConditionalScripts.d.ts.map +1 -1
- package/esm/policies/ConditionalScripts.js +27 -24
- package/esm/policies/ConditionalScripts.js.map +1 -1
- package/esm/policies/ExactScripts.d.ts +8 -6
- package/esm/policies/ExactScripts.d.ts.map +1 -1
- package/esm/policies/ExactScripts.js +18 -20
- 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 +32 -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 +36 -0
- package/esm/policies/GleamLicenceConfigured.js.map +1 -0
- package/esm/policies/GleamManifestCommitted.d.ts +16 -0
- package/esm/policies/GleamManifestCommitted.d.ts.map +1 -0
- package/esm/policies/GleamManifestCommitted.js +27 -0
- package/esm/policies/GleamManifestCommitted.js.map +1 -0
- package/esm/policies/GleamMonorepoConsistency.d.ts +38 -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 +32 -0
- package/esm/policies/GleamProjectStructure.d.ts.map +1 -0
- package/esm/policies/GleamProjectStructure.js +32 -0
- package/esm/policies/GleamProjectStructure.js.map +1 -0
- package/esm/policies/GleamSharedDependencyVersions.d.ts +37 -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 +157 -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 +68 -0
- package/esm/policies/GleamVersionConstraint.js.map +1 -0
- package/esm/policies/HtmlFileHeaders.d.ts +4 -2
- package/esm/policies/HtmlFileHeaders.d.ts.map +1 -1
- package/esm/policies/HtmlFileHeaders.js +2 -2
- package/esm/policies/HtmlFileHeaders.js.map +1 -1
- package/esm/policies/JsTsFileHeaders.d.ts +4 -2
- package/esm/policies/JsTsFileHeaders.d.ts.map +1 -1
- package/esm/policies/JsTsFileHeaders.js +1 -1
- package/esm/policies/JsTsFileHeaders.js.map +1 -1
- package/esm/policies/LicenseFileExists.d.ts +10 -4
- package/esm/policies/LicenseFileExists.d.ts.map +1 -1
- package/esm/policies/LicenseFileExists.js +27 -20
- package/esm/policies/LicenseFileExists.js.map +1 -1
- package/esm/policies/MutuallyExclusiveScripts.d.ts +8 -6
- package/esm/policies/MutuallyExclusiveScripts.d.ts.map +1 -1
- package/esm/policies/MutuallyExclusiveScripts.js +9 -13
- package/esm/policies/MutuallyExclusiveScripts.js.map +1 -1
- package/esm/policies/NoBuildDirectory.d.ts +15 -0
- package/esm/policies/NoBuildDirectory.d.ts.map +1 -0
- package/esm/policies/NoBuildDirectory.js +24 -0
- package/esm/policies/NoBuildDirectory.js.map +1 -0
- package/esm/policies/NoJsFileExtensions.d.ts +9 -3
- package/esm/policies/NoJsFileExtensions.d.ts.map +1 -1
- package/esm/policies/NoJsFileExtensions.js +9 -14
- package/esm/policies/NoJsFileExtensions.js.map +1 -1
- package/esm/policies/NoLargeBinaryFiles.d.ts +9 -4
- package/esm/policies/NoLargeBinaryFiles.d.ts.map +1 -1
- package/esm/policies/NoLargeBinaryFiles.js +10 -16
- package/esm/policies/NoLargeBinaryFiles.js.map +1 -1
- package/esm/policies/NoPrivateWorkspaceDependencies.d.ts +10 -6
- package/esm/policies/NoPrivateWorkspaceDependencies.d.ts.map +1 -1
- package/esm/policies/NoPrivateWorkspaceDependencies.js +12 -14
- package/esm/policies/NoPrivateWorkspaceDependencies.js.map +1 -1
- package/esm/policies/NoTargetArtifacts.d.ts +14 -0
- package/esm/policies/NoTargetArtifacts.d.ts.map +1 -0
- package/esm/policies/NoTargetArtifacts.js +37 -0
- package/esm/policies/NoTargetArtifacts.js.map +1 -0
- package/esm/policies/NoUnsafeWithoutJustification.d.ts +31 -0
- package/esm/policies/NoUnsafeWithoutJustification.d.ts.map +1 -0
- package/esm/policies/NoUnsafeWithoutJustification.js +79 -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/PackageAllowedScopes.d.ts +9 -5
- package/esm/policies/PackageAllowedScopes.d.ts.map +1 -1
- package/esm/policies/PackageAllowedScopes.js +15 -16
- package/esm/policies/PackageAllowedScopes.js.map +1 -1
- package/esm/policies/PackageEsmType.d.ts +7 -5
- package/esm/policies/PackageEsmType.d.ts.map +1 -1
- package/esm/policies/PackageEsmType.js +38 -36
- package/esm/policies/PackageEsmType.js.map +1 -1
- package/esm/policies/PackageFolderName.d.ts +8 -6
- package/esm/policies/PackageFolderName.d.ts.map +1 -1
- package/esm/policies/PackageFolderName.js +13 -16
- package/esm/policies/PackageFolderName.js.map +1 -1
- package/esm/policies/PackageJsonProperties.d.ts +5 -3
- package/esm/policies/PackageJsonProperties.d.ts.map +1 -1
- package/esm/policies/PackageJsonProperties.js +18 -21
- package/esm/policies/PackageJsonProperties.js.map +1 -1
- package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts +2 -7
- package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts.map +1 -1
- package/esm/policies/PackageJsonRepoDirectoryProperty.js +29 -42
- package/esm/policies/PackageJsonRepoDirectoryProperty.js.map +1 -1
- package/esm/policies/PackageJsonSorted.d.ts +2 -2
- package/esm/policies/PackageJsonSorted.d.ts.map +1 -1
- package/esm/policies/PackageJsonSorted.js +51 -31
- package/esm/policies/PackageJsonSorted.js.map +1 -1
- package/esm/policies/PackageLicense.d.ts +4 -4
- package/esm/policies/PackageLicense.d.ts.map +1 -1
- package/esm/policies/PackageLicense.js +32 -54
- package/esm/policies/PackageLicense.js.map +1 -1
- package/esm/policies/PackagePrivateField.d.ts +12 -8
- package/esm/policies/PackagePrivateField.d.ts.map +1 -1
- package/esm/policies/PackagePrivateField.js +34 -25
- package/esm/policies/PackagePrivateField.js.map +1 -1
- package/esm/policies/PackageReadme.d.ts +6 -5
- package/esm/policies/PackageReadme.d.ts.map +1 -1
- package/esm/policies/PackageReadme.js +24 -61
- package/esm/policies/PackageReadme.js.map +1 -1
- package/esm/policies/PackageScripts.d.ts +26 -22
- package/esm/policies/PackageScripts.d.ts.map +1 -1
- package/esm/policies/PackageScripts.js +42 -38
- package/esm/policies/PackageScripts.js.map +1 -1
- package/esm/policies/PackageTestScripts.d.ts +10 -6
- package/esm/policies/PackageTestScripts.d.ts.map +1 -1
- package/esm/policies/PackageTestScripts.js +17 -19
- 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 +38 -0
- package/esm/policies/PublicApiDocumented.js.map +1 -0
- package/esm/policies/RequiredGitignorePatterns.d.ts +11 -4
- package/esm/policies/RequiredGitignorePatterns.d.ts.map +1 -1
- package/esm/policies/RequiredGitignorePatterns.js +29 -36
- package/esm/policies/RequiredGitignorePatterns.js.map +1 -1
- package/esm/policies/RequiredScripts.d.ts +9 -7
- package/esm/policies/RequiredScripts.d.ts.map +1 -1
- package/esm/policies/RequiredScripts.js +27 -26
- 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 +27 -0
- package/esm/policies/RustToolchainExists.d.ts.map +1 -0
- package/esm/policies/RustToolchainExists.js +28 -0
- package/esm/policies/RustToolchainExists.js.map +1 -0
- package/esm/policies/RustfmtConfigExists.d.ts +27 -0
- package/esm/policies/RustfmtConfigExists.d.ts.map +1 -0
- package/esm/policies/RustfmtConfigExists.js +28 -0
- package/esm/policies/RustfmtConfigExists.js.map +1 -0
- package/esm/policies/ScriptContains.d.ts +9 -7
- package/esm/policies/ScriptContains.d.ts.map +1 -1
- package/esm/policies/ScriptContains.js +9 -13
- package/esm/policies/ScriptContains.js.map +1 -1
- package/esm/policies/SharedDependencyVersions.d.ts +29 -0
- package/esm/policies/SharedDependencyVersions.d.ts.map +1 -0
- package/esm/policies/SharedDependencyVersions.js +143 -0
- package/esm/policies/SharedDependencyVersions.js.map +1 -0
- package/esm/policies/WorkspaceInheritance.d.ts +31 -0
- package/esm/policies/WorkspaceInheritance.d.ts.map +1 -0
- package/esm/policies/WorkspaceInheritance.js +93 -0
- package/esm/policies/WorkspaceInheritance.js.map +1 -0
- package/esm/policies/WorkspaceMembersValid.d.ts +27 -0
- package/esm/policies/WorkspaceMembersValid.d.ts.map +1 -0
- package/esm/policies/WorkspaceMembersValid.js +87 -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 +9 -1
- package/esm/policies/constants.js.map +1 -1
- package/esm/policies.d.ts +43 -5
- package/esm/policies.d.ts.map +1 -1
- package/esm/policies.js +63 -6
- package/esm/policies.js.map +1 -1
- package/esm/policy.d.ts +65 -269
- package/esm/policy.d.ts.map +1 -1
- package/esm/policy.js +1 -122
- package/esm/policy.js.map +1 -1
- package/esm/policyDefiners/defineCargoPolicy.d.ts +82 -0
- package/esm/policyDefiners/defineCargoPolicy.d.ts.map +1 -0
- package/esm/policyDefiners/defineCargoPolicy.js +42 -0
- package/esm/policyDefiners/defineCargoPolicy.js.map +1 -0
- package/esm/policyDefiners/defineFileHeaderPolicy.d.ts +27 -14
- package/esm/policyDefiners/defineFileHeaderPolicy.d.ts.map +1 -1
- package/esm/policyDefiners/defineFileHeaderPolicy.js +19 -39
- package/esm/policyDefiners/defineFileHeaderPolicy.js.map +1 -1
- package/esm/policyDefiners/defineGleamPolicy.d.ts +81 -0
- package/esm/policyDefiners/defineGleamPolicy.d.ts.map +1 -0
- package/esm/policyDefiners/defineGleamPolicy.js +42 -0
- package/esm/policyDefiners/defineGleamPolicy.js.map +1 -0
- package/esm/policyDefiners/definePackagePolicy.d.ts +24 -13
- package/esm/policyDefiners/definePackagePolicy.d.ts.map +1 -1
- package/esm/policyDefiners/definePackagePolicy.js +9 -32
- package/esm/policyDefiners/definePackagePolicy.js.map +1 -1
- package/esm/policyDefiners/spdxValidator.d.ts +66 -0
- package/esm/policyDefiners/spdxValidator.d.ts.map +1 -0
- package/esm/policyDefiners/spdxValidator.js +139 -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/policyExecution.d.ts +19 -0
- package/esm/policyExecution.d.ts.map +1 -0
- package/esm/policyExecution.js +224 -0
- package/esm/policyExecution.js.map +1 -0
- package/esm/repositoryFiles.d.ts +4 -0
- package/esm/repositoryFiles.d.ts.map +1 -0
- package/esm/repositoryFiles.js +8 -0
- package/esm/repositoryFiles.js.map +1 -0
- package/esm/runner.d.ts +85 -0
- package/esm/runner.d.ts.map +1 -0
- package/esm/runner.js +189 -0
- package/esm/runner.js.map +1 -0
- package/esm/settlePolicyPromise.d.ts +4 -0
- package/esm/settlePolicyPromise.d.ts.map +1 -0
- package/esm/settlePolicyPromise.js +10 -0
- package/esm/settlePolicyPromise.js.map +1 -0
- package/esm/tsdoc-metadata.json +1 -1
- package/esm/utils/safePaths.d.ts +9 -0
- package/esm/utils/safePaths.d.ts.map +1 -0
- package/esm/utils/safePaths.js +40 -0
- package/esm/utils/safePaths.js.map +1 -0
- package/oclif.manifest.json +117 -3
- package/package.json +66 -36
- package/scripts/benchmark.mjs +341 -0
- package/scripts/postinstall.mjs +154 -0
- package/sidecar/sidecar.mjs +399 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { defineCargoPolicy, } from "../policyDefiners/defineCargoPolicy.js";
|
|
2
|
+
const DEFAULT_DENY = ["*"];
|
|
3
|
+
const DEFAULT_WARN = [">="];
|
|
4
|
+
function checkVersionSpec(version, denyPatterns, warnPatterns) {
|
|
5
|
+
for (const pattern of denyPatterns) {
|
|
6
|
+
if (version === pattern || version.startsWith(pattern)) {
|
|
7
|
+
return "deny";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
for (const pattern of warnPatterns) {
|
|
11
|
+
if (version.startsWith(pattern)) {
|
|
12
|
+
return "warn";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return "ok";
|
|
16
|
+
}
|
|
17
|
+
function extractVersion(dep) {
|
|
18
|
+
if (typeof dep === "string") {
|
|
19
|
+
return dep;
|
|
20
|
+
}
|
|
21
|
+
if (typeof dep === "object" && dep !== null) {
|
|
22
|
+
const record = dep;
|
|
23
|
+
if (typeof record.version === "string") {
|
|
24
|
+
return record.version;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
function checkSectionDeps(deps, sectionName, isDev, allowDev, denyPatterns, warnPatterns, errors) {
|
|
30
|
+
for (const [depName, depValue] of Object.entries(deps)) {
|
|
31
|
+
const version = extractVersion(depValue);
|
|
32
|
+
if (!version) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const effectiveWarn = isDev && allowDev ? [] : warnPatterns;
|
|
36
|
+
const result = checkVersionSpec(version, denyPatterns, effectiveWarn);
|
|
37
|
+
if (result === "deny") {
|
|
38
|
+
errors.push(`[${sectionName}] ${depName} = "${version}" uses a denied version pattern`);
|
|
39
|
+
}
|
|
40
|
+
else if (result === "warn") {
|
|
41
|
+
errors.push(`[${sectionName}] ${depName} = "${version}" uses an overly permissive version range`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A policy that prevents wildcard or overly permissive version specifications in Cargo.toml.
|
|
47
|
+
*
|
|
48
|
+
* @public
|
|
49
|
+
*/
|
|
50
|
+
export const NoWildcardDependencies = defineCargoPolicy({
|
|
51
|
+
name: "NoWildcardDependencies",
|
|
52
|
+
description: "Prevents wildcard or overly permissive dependency version specifications in Cargo.toml.",
|
|
53
|
+
handler: async (toml, { config }) => {
|
|
54
|
+
// Skip workspace root
|
|
55
|
+
if (toml.workspace !== undefined && toml.package === undefined) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
const denyPatterns = config?.deny ?? DEFAULT_DENY;
|
|
59
|
+
const warnPatterns = config?.warn ?? DEFAULT_WARN;
|
|
60
|
+
const allowDev = config?.allowDev ?? true;
|
|
61
|
+
const errors = [];
|
|
62
|
+
const sections = [
|
|
63
|
+
{ name: "dependencies", isDev: false },
|
|
64
|
+
{ name: "build-dependencies", isDev: false },
|
|
65
|
+
{ name: "dev-dependencies", isDev: true },
|
|
66
|
+
];
|
|
67
|
+
for (const { name, isDev } of sections) {
|
|
68
|
+
const deps = toml[name];
|
|
69
|
+
if (!deps) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
checkSectionDeps(deps, name, isDev, allowDev, denyPatterns, warnPatterns, errors);
|
|
73
|
+
}
|
|
74
|
+
if (errors.length > 0) {
|
|
75
|
+
return errors.map((message) => ({
|
|
76
|
+
message,
|
|
77
|
+
manualFix: 'Use specific version ranges (e.g., "1.0", "^1.0", "~1.0") instead of wildcards.',
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
return [];
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
//# sourceMappingURL=NoWildcardDependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoWildcardDependencies.js","sourceRoot":"","sources":["../../src/policies/NoWildcardDependencies.ts"],"names":[],"mappings":"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","sourcesContent":["import type { FilePolicyDefinition } from \"../policy.js\";\nimport {\n\ttype CargoToml,\n\tdefineCargoPolicy,\n} from \"../policyDefiners/defineCargoPolicy.js\";\n\n/**\n * Configuration for the NoWildcardDependencies policy.\n *\n * @public\n */\nexport interface NoWildcardDependenciesConfig {\n\t/**\n\t * Version patterns to deny outright.\n\t * @defaultValue [\"*\"]\n\t */\n\tdeny?: string[];\n\n\t/**\n\t * Version patterns to warn about.\n\t * @defaultValue `[\">=\"]`\n\t */\n\twarn?: string[];\n\n\t/**\n\t * If true, dev-dependencies are checked more leniently (only deny, not warn).\n\t * @defaultValue true\n\t */\n\tallowDev?: boolean;\n}\n\nconst DEFAULT_DENY = [\"*\"];\nconst DEFAULT_WARN = [\">=\"];\n\nfunction checkVersionSpec(\n\tversion: string,\n\tdenyPatterns: string[],\n\twarnPatterns: string[],\n): \"deny\" | \"warn\" | \"ok\" {\n\tfor (const pattern of denyPatterns) {\n\t\tif (version === pattern || version.startsWith(pattern)) {\n\t\t\treturn \"deny\";\n\t\t}\n\t}\n\tfor (const pattern of warnPatterns) {\n\t\tif (version.startsWith(pattern)) {\n\t\t\treturn \"warn\";\n\t\t}\n\t}\n\treturn \"ok\";\n}\n\nfunction extractVersion(dep: unknown): string | undefined {\n\tif (typeof dep === \"string\") {\n\t\treturn dep;\n\t}\n\tif (typeof dep === \"object\" && dep !== null) {\n\t\tconst record = dep as Record<string, unknown>;\n\t\tif (typeof record.version === \"string\") {\n\t\t\treturn record.version;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction checkSectionDeps(\n\tdeps: Record<string, unknown>,\n\tsectionName: string,\n\tisDev: boolean,\n\tallowDev: boolean,\n\tdenyPatterns: string[],\n\twarnPatterns: string[],\n\terrors: string[],\n): void {\n\tfor (const [depName, depValue] of Object.entries(deps)) {\n\t\tconst version = extractVersion(depValue);\n\t\tif (!version) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst effectiveWarn = isDev && allowDev ? [] : warnPatterns;\n\t\tconst result = checkVersionSpec(version, denyPatterns, effectiveWarn);\n\n\t\tif (result === \"deny\") {\n\t\t\terrors.push(\n\t\t\t\t`[${sectionName}] ${depName} = \"${version}\" uses a denied version pattern`,\n\t\t\t);\n\t\t} else if (result === \"warn\") {\n\t\t\terrors.push(\n\t\t\t\t`[${sectionName}] ${depName} = \"${version}\" uses an overly permissive version range`,\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * A policy that prevents wildcard or overly permissive version specifications in Cargo.toml.\n *\n * @public\n */\nexport const NoWildcardDependencies = defineCargoPolicy({\n\tname: \"NoWildcardDependencies\",\n\tdescription:\n\t\t\"Prevents wildcard or overly permissive dependency version specifications in Cargo.toml.\",\n\thandler: async (toml: CargoToml, { config }) => {\n\t\t// Skip workspace root\n\t\tif (toml.workspace !== undefined && toml.package === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst denyPatterns = config?.deny ?? DEFAULT_DENY;\n\t\tconst warnPatterns = config?.warn ?? DEFAULT_WARN;\n\t\tconst allowDev = config?.allowDev ?? true;\n\t\tconst errors: string[] = [];\n\n\t\tconst sections = [\n\t\t\t{ name: \"dependencies\", isDev: false },\n\t\t\t{ name: \"build-dependencies\", isDev: false },\n\t\t\t{ name: \"dev-dependencies\", isDev: true },\n\t\t];\n\n\t\tfor (const { name, isDev } of sections) {\n\t\t\tconst deps = toml[name] as Record<string, unknown> | undefined;\n\t\t\tif (!deps) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcheckSectionDeps(\n\t\t\t\tdeps,\n\t\t\t\tname,\n\t\t\t\tisDev,\n\t\t\t\tallowDev,\n\t\t\t\tdenyPatterns,\n\t\t\t\twarnPatterns,\n\t\t\t\terrors,\n\t\t\t);\n\t\t}\n\n\t\tif (errors.length > 0) {\n\t\t\treturn errors.map((message) => ({\n\t\t\t\tmessage,\n\t\t\t\tmanualFix:\n\t\t\t\t\t'Use specific version ranges (e.g., \"1.0\", \"^1.0\", \"~1.0\") instead of wildcards.',\n\t\t\t}));\n\t\t}\n\t\treturn [];\n\t},\n}) satisfies FilePolicyDefinition<NoWildcardDependenciesConfig>;\n"]}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* };
|
|
15
15
|
* ```
|
|
16
16
|
*
|
|
17
|
-
* @
|
|
17
|
+
* @public
|
|
18
18
|
*/
|
|
19
19
|
export interface PackageAllowedScopesConfig {
|
|
20
20
|
/**
|
|
@@ -75,14 +75,18 @@ export interface PackageAllowedScopesConfig {
|
|
|
75
75
|
* const config: RepopoConfig = {
|
|
76
76
|
* policies: [
|
|
77
77
|
* makePolicy(PackageAllowedScopes, {
|
|
78
|
-
*
|
|
79
|
-
*
|
|
78
|
+
* config: {
|
|
79
|
+
* allowedScopes: ["@myorg", "@internal"],
|
|
80
|
+
* unscopedPackages: ["legacy-package"],
|
|
81
|
+
* },
|
|
80
82
|
* }),
|
|
81
83
|
* ],
|
|
82
84
|
* };
|
|
83
85
|
* ```
|
|
84
86
|
*
|
|
85
|
-
* @
|
|
87
|
+
* @public
|
|
86
88
|
*/
|
|
87
|
-
export declare const PackageAllowedScopes: import("../policy.js").
|
|
89
|
+
export declare const PackageAllowedScopes: import("../policy.js").FilePolicyDefinition<PackageAllowedScopesConfig | undefined> & {
|
|
90
|
+
requiresConfig: true;
|
|
91
|
+
};
|
|
88
92
|
//# sourceMappingURL=PackageAllowedScopes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PackageAllowedScopes.d.ts","sourceRoot":"","sources":["../../src/policies/PackageAllowedScopes.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,0BAA0B;IAC1C;;;;;;;;;;;;;;;OAeG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;;;;;;;;;;;;OAaG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAiDD
|
|
1
|
+
{"version":3,"file":"PackageAllowedScopes.d.ts","sourceRoot":"","sources":["../../src/policies/PackageAllowedScopes.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,0BAA0B;IAC1C;;;;;;;;;;;;;;;OAeG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;;;;;;;;;;;;OAaG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAiDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,oBAAoB;;CAmD/B,CAAC"}
|
|
@@ -60,40 +60,42 @@ function isUnscopedPackageAllowed(packageName, unscopedPackages) {
|
|
|
60
60
|
* const config: RepopoConfig = {
|
|
61
61
|
* policies: [
|
|
62
62
|
* makePolicy(PackageAllowedScopes, {
|
|
63
|
-
*
|
|
64
|
-
*
|
|
63
|
+
* config: {
|
|
64
|
+
* allowedScopes: ["@myorg", "@internal"],
|
|
65
|
+
* unscopedPackages: ["legacy-package"],
|
|
66
|
+
* },
|
|
65
67
|
* }),
|
|
66
68
|
* ],
|
|
67
69
|
* };
|
|
68
70
|
* ```
|
|
69
71
|
*
|
|
70
|
-
* @
|
|
72
|
+
* @public
|
|
71
73
|
*/
|
|
72
74
|
export const PackageAllowedScopes = definePackagePolicy({
|
|
73
75
|
name: "PackageAllowedScopes",
|
|
76
|
+
requiresConfig: true,
|
|
74
77
|
description: "Ensures packages use only allowed npm scopes and package names.",
|
|
75
|
-
|
|
76
|
-
handler: function* (json, { file, config }) {
|
|
78
|
+
handler: function* (json, { config }) {
|
|
77
79
|
// If no config provided, skip validation
|
|
78
80
|
if (config === undefined) {
|
|
79
|
-
return
|
|
81
|
+
return [];
|
|
80
82
|
}
|
|
81
83
|
const packageName = json.name;
|
|
82
84
|
// Skip packages without a name
|
|
83
85
|
if (packageName === undefined) {
|
|
84
|
-
return
|
|
86
|
+
return [];
|
|
85
87
|
}
|
|
86
88
|
// Skip the root package (common in monorepos)
|
|
87
89
|
if (packageName === "root") {
|
|
88
|
-
return
|
|
90
|
+
return [];
|
|
89
91
|
}
|
|
90
92
|
// Check if the package uses an allowed scope
|
|
91
93
|
if (isScopeAllowed(packageName, config.allowedScopes)) {
|
|
92
|
-
return
|
|
94
|
+
return [];
|
|
93
95
|
}
|
|
94
96
|
// Check if the package is an allowed unscoped package
|
|
95
97
|
if (isUnscopedPackageAllowed(packageName, config.unscopedPackages)) {
|
|
96
|
-
return
|
|
98
|
+
return [];
|
|
97
99
|
}
|
|
98
100
|
// Package doesn't match any allowed pattern - build error message
|
|
99
101
|
const scope = getPackageScope(packageName);
|
|
@@ -106,12 +108,9 @@ export const PackageAllowedScopes = definePackagePolicy({
|
|
|
106
108
|
// Package is unscoped but not in the allowed list
|
|
107
109
|
errorMessage = `Package "${packageName}" is an unscoped package that is not in the allowed unscoped packages list. Allowed unscoped packages: ${config.unscopedPackages?.join(", ") ?? "(none)"}`;
|
|
108
110
|
}
|
|
109
|
-
const failResult = {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
autoFixable: false, // Can't auto-fix package names
|
|
113
|
-
errorMessages: [errorMessage],
|
|
114
|
-
};
|
|
111
|
+
const failResult = [errorMessage].map((message) => ({
|
|
112
|
+
message,
|
|
113
|
+
}));
|
|
115
114
|
return failResult;
|
|
116
115
|
},
|
|
117
116
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PackageAllowedScopes.js","sourceRoot":"","sources":["../../src/policies/PackageAllowedScopes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAwDpE;;;;;;GAMG;AACH,SAAS,cAAc,CACtB,WAAmB,EACnB,aAAmC;IAEnC,IAAI,aAAa,KAAK,SAAS,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/D,OAAO,KAAK,CAAC;IACd,CAAC;IAED,MAAM,KAAK,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,oDAAoD;QACpD,OAAO,KAAK,CAAC;IACd,CAAC;IAED,OAAO,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;GAMG;AACH,SAAS,wBAAwB,CAChC,WAAmB,EACnB,gBAAsC;IAEtC,IAAI,gBAAgB,KAAK,SAAS,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrE,OAAO,KAAK,CAAC;IACd,CAAC;IAED,oCAAoC;IACpC,IAAI,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACd,CAAC;IAED,OAAO,gBAAgB,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC/C,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"PackageAllowedScopes.js","sourceRoot":"","sources":["../../src/policies/PackageAllowedScopes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAwDpE;;;;;;GAMG;AACH,SAAS,cAAc,CACtB,WAAmB,EACnB,aAAmC;IAEnC,IAAI,aAAa,KAAK,SAAS,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/D,OAAO,KAAK,CAAC;IACd,CAAC;IAED,MAAM,KAAK,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,oDAAoD;QACpD,OAAO,KAAK,CAAC;IACd,CAAC;IAED,OAAO,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;GAMG;AACH,SAAS,wBAAwB,CAChC,WAAmB,EACnB,gBAAsC;IAEtC,IAAI,gBAAgB,KAAK,SAAS,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrE,OAAO,KAAK,CAAC;IACd,CAAC;IAED,oCAAoC;IACpC,IAAI,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACd,CAAC;IAED,OAAO,gBAAgB,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAGrD;IACD,IAAI,EAAE,sBAAsB;IAC5B,cAAc,EAAE,IAAI;IACpB,WAAW,EACV,iEAAiE;IAClE,OAAO,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE;QACnC,yCAAyC;QACzC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,EAAE,CAAC;QACX,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC;QAE9B,+BAA+B;QAC/B,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC/B,OAAO,EAAE,CAAC;QACX,CAAC;QAED,8CAA8C;QAC9C,IAAI,WAAW,KAAK,MAAM,EAAE,CAAC;YAC5B,OAAO,EAAE,CAAC;QACX,CAAC;QAED,6CAA6C;QAC7C,IAAI,cAAc,CAAC,WAAW,EAAE,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;YACvD,OAAO,EAAE,CAAC;QACX,CAAC;QAED,sDAAsD;QACtD,IAAI,wBAAwB,CAAC,WAAW,EAAE,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACpE,OAAO,EAAE,CAAC;QACX,CAAC;QAED,kEAAkE;QAClE,MAAM,KAAK,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;QAC3C,IAAI,YAAoB,CAAC;QACzB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,kCAAkC;YAClC,YAAY,GAAG,YAAY,WAAW,iBAAiB,KAAK,8DAA8D,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QAC1K,CAAC;aAAM,CAAC;YACP,kDAAkD;YAClD,YAAY,GAAG,YAAY,WAAW,0GAA0G,MAAM,CAAC,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QACnM,CAAC;QACD,MAAM,UAAU,GAAoB,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACpE,OAAO;SACP,CAAC,CAAC,CAAC;QACJ,OAAO,UAAU,CAAC;IACnB,CAAC;CACD,CAAC,CAAC","sourcesContent":["import type { PackageJson } from \"type-fest\";\nimport type { PolicyFinding } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\nimport { getPackageScope, isScoped } from \"../utils/packageName.js\";\n\n/**\n * Configuration for the PackageAllowedScopes policy.\n *\n * This policy ensures packages in a monorepo use only approved scopes or package names.\n * This prevents accidental introduction of new scopes and ensures naming consistency.\n *\n * @example\n * ```typescript\n * const config: PackageAllowedScopesConfig = {\n * // Only packages in these scopes are allowed\n * allowedScopes: [\"@myorg\", \"@internal\", \"@experimental\"],\n * // These specific unscoped packages are also allowed\n * unscopedPackages: [\"my-legacy-tool\", \"special-package\"],\n * };\n * ```\n *\n * @public\n */\nexport interface PackageAllowedScopesConfig {\n\t/**\n\t * A list of npm scopes that are allowed for packages in this repository.\n\t *\n\t * Scopes should start with `@` (e.g., `@myorg`). A package like `@myorg/foo`\n\t * would match the scope `@myorg`.\n\t *\n\t * @remarks\n\t *\n\t * If a package's scope is not in this list and the package is not in\n\t * `unscopedPackages`, the policy will fail.\n\t *\n\t * @example\n\t * ```typescript\n\t * allowedScopes: [\"@myorg\", \"@myorg-tools\", \"@myorg-internal\"]\n\t * ```\n\t */\n\tallowedScopes?: string[];\n\n\t/**\n\t * A list of unscoped package names that are explicitly allowed.\n\t *\n\t * Use this for legacy packages or special cases where an unscoped name is needed.\n\t *\n\t * @remarks\n\t *\n\t * Unscoped packages not in this list will cause the policy to fail.\n\t *\n\t * @example\n\t * ```typescript\n\t * unscopedPackages: [\"my-legacy-tool\", \"special-package\"]\n\t * ```\n\t */\n\tunscopedPackages?: string[];\n}\n\n/**\n * Check if a package's scope is in the allowed list.\n *\n * @param packageName - The package name to check\n * @param allowedScopes - List of allowed scopes\n * @returns `true` if the package's scope is allowed\n */\nfunction isScopeAllowed(\n\tpackageName: string,\n\tallowedScopes: string[] | undefined,\n): boolean {\n\tif (allowedScopes === undefined || allowedScopes.length === 0) {\n\t\treturn false;\n\t}\n\n\tconst scope = getPackageScope(packageName);\n\tif (scope === undefined) {\n\t\t// Package is unscoped, so scope check doesn't apply\n\t\treturn false;\n\t}\n\n\treturn allowedScopes.includes(scope);\n}\n\n/**\n * Check if an unscoped package name is in the allowed list.\n *\n * @param packageName - The package name to check\n * @param unscopedPackages - List of allowed unscoped package names\n * @returns `true` if the unscoped package is allowed\n */\nfunction isUnscopedPackageAllowed(\n\tpackageName: string,\n\tunscopedPackages: string[] | undefined,\n): boolean {\n\tif (unscopedPackages === undefined || unscopedPackages.length === 0) {\n\t\treturn false;\n\t}\n\n\t// Only applies to unscoped packages\n\tif (isScoped(packageName)) {\n\t\treturn false;\n\t}\n\n\treturn unscopedPackages.includes(packageName);\n}\n\n/**\n * A policy that ensures packages use only allowed scopes and package names.\n *\n * This policy prevents accidental introduction of new npm scopes or unscoped packages\n * in a monorepo. It helps maintain naming consistency and prevents typos or mistakes\n * when creating new packages.\n *\n * @remarks\n *\n * The policy checks packages in the following order:\n *\n * 1. If the package is scoped (starts with `@`), check if its scope is in `allowedScopes`\n * 2. If the package is unscoped, check if it's in `unscopedPackages`\n * 3. If neither check passes, the policy fails\n *\n * The \"root\" package (common in monorepos) is automatically skipped.\n *\n * @example\n * ```typescript\n * import { makePolicy } from \"repopo\";\n * import { PackageAllowedScopes } from \"repopo/policies\";\n *\n * const config: RepopoConfig = {\n * policies: [\n * makePolicy(PackageAllowedScopes, {\n * config: {\n * allowedScopes: [\"@myorg\", \"@internal\"],\n * unscopedPackages: [\"legacy-package\"],\n * },\n * }),\n * ],\n * };\n * ```\n *\n * @public\n */\nexport const PackageAllowedScopes = definePackagePolicy<\n\tPackageJson,\n\tPackageAllowedScopesConfig | undefined\n>({\n\tname: \"PackageAllowedScopes\",\n\trequiresConfig: true,\n\tdescription:\n\t\t\"Ensures packages use only allowed npm scopes and package names.\",\n\thandler: function* (json, { config }) {\n\t\t// If no config provided, skip validation\n\t\tif (config === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst packageName = json.name;\n\n\t\t// Skip packages without a name\n\t\tif (packageName === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Skip the root package (common in monorepos)\n\t\tif (packageName === \"root\") {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Check if the package uses an allowed scope\n\t\tif (isScopeAllowed(packageName, config.allowedScopes)) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Check if the package is an allowed unscoped package\n\t\tif (isUnscopedPackageAllowed(packageName, config.unscopedPackages)) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Package doesn't match any allowed pattern - build error message\n\t\tconst scope = getPackageScope(packageName);\n\t\tlet errorMessage: string;\n\t\tif (scope !== undefined) {\n\t\t\t// Package has an unexpected scope\n\t\t\terrorMessage = `Package \"${packageName}\" uses scope \"${scope}\" which is not in the allowed scopes list. Allowed scopes: ${config.allowedScopes?.join(\", \") ?? \"(none)\"}`;\n\t\t} else {\n\t\t\t// Package is unscoped but not in the allowed list\n\t\t\terrorMessage = `Package \"${packageName}\" is an unscoped package that is not in the allowed unscoped packages list. Allowed unscoped packages: ${config.unscopedPackages?.join(\", \") ?? \"(none)\"}`;\n\t\t}\n\t\tconst failResult: PolicyFinding[] = [errorMessage].map((message) => ({\n\t\t\tmessage,\n\t\t}));\n\t\treturn failResult;\n\t},\n});\n"]}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* };
|
|
15
15
|
* ```
|
|
16
16
|
*
|
|
17
|
-
* @
|
|
17
|
+
* @public
|
|
18
18
|
*/
|
|
19
19
|
export interface PackageEsmTypeConfig {
|
|
20
20
|
/**
|
|
@@ -88,13 +88,15 @@ export interface PackageEsmTypeConfig {
|
|
|
88
88
|
* import { PackageEsmType } from "repopo/policies";
|
|
89
89
|
*
|
|
90
90
|
* // Require all packages to be ESM
|
|
91
|
-
* makePolicy(PackageEsmType, { requiredType: "module" })
|
|
91
|
+
* makePolicy(PackageEsmType, { config: { requiredType: "module" } })
|
|
92
92
|
*
|
|
93
93
|
* // Or detect based on exports
|
|
94
|
-
* makePolicy(PackageEsmType, { detectFromExports: true })
|
|
94
|
+
* makePolicy(PackageEsmType, { config: { detectFromExports: true } })
|
|
95
95
|
* ```
|
|
96
96
|
*
|
|
97
|
-
* @
|
|
97
|
+
* @public
|
|
98
98
|
*/
|
|
99
|
-
export declare const PackageEsmType: import("../policy.js").
|
|
99
|
+
export declare const PackageEsmType: import("../policy.js").FilePolicyDefinition<PackageEsmTypeConfig | undefined> & {
|
|
100
|
+
requiresConfig: true;
|
|
101
|
+
};
|
|
100
102
|
//# sourceMappingURL=PackageEsmType.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PackageEsmType.d.ts","sourceRoot":"","sources":["../../src/policies/PackageEsmType.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PackageEsmType.d.ts","sourceRoot":"","sources":["../../src/policies/PackageEsmType.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,oBAAoB;IACpC;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IAErC;;;;;;;;;;OAUG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B;;;;;;;;;;OAUG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;CAC9C;AAqQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,cAAc;;CAwDzB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import jsonfile from "jsonfile";
|
|
2
|
+
import { resolve as resolvePath } from "pathe";
|
|
2
3
|
import { definePackagePolicy } from "../policyDefiners/definePackagePolicy.js";
|
|
3
4
|
import { detectIndentation } from "../utils/indentation.js";
|
|
4
5
|
const { writeFile: writeJson } = jsonfile;
|
|
@@ -159,20 +160,28 @@ function buildErrorMessage(packageName, currentType, expectedType) {
|
|
|
159
160
|
/**
|
|
160
161
|
* Apply the auto-fix for the type field.
|
|
161
162
|
*/
|
|
162
|
-
async function applyFix(json, file, expectedType, failResult) {
|
|
163
|
-
const fixResult = {
|
|
164
|
-
...
|
|
165
|
-
|
|
166
|
-
};
|
|
163
|
+
async function applyFix(json, file, root, expectedType, failResult) {
|
|
164
|
+
const fixResult = failResult.map((finding) => ({
|
|
165
|
+
...finding,
|
|
166
|
+
fixStatus: "failed",
|
|
167
|
+
}));
|
|
167
168
|
try {
|
|
168
169
|
json.type = expectedType;
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
const filePath = resolvePath(root, file);
|
|
171
|
+
const indent = await detectIndentation(filePath);
|
|
172
|
+
await writeJson(filePath, json, { spaces: indent });
|
|
173
|
+
for (const finding of fixResult) {
|
|
174
|
+
finding.fixStatus = "fixed";
|
|
175
|
+
}
|
|
172
176
|
}
|
|
173
177
|
catch {
|
|
174
|
-
fixResult
|
|
175
|
-
|
|
178
|
+
for (const finding of fixResult) {
|
|
179
|
+
finding.fixStatus = "failed";
|
|
180
|
+
}
|
|
181
|
+
fixResult.splice(0, fixResult.length, ...[`Failed to update ${file}`].map((message) => ({
|
|
182
|
+
...fixResult[0],
|
|
183
|
+
message,
|
|
184
|
+
})));
|
|
176
185
|
}
|
|
177
186
|
return fixResult;
|
|
178
187
|
}
|
|
@@ -200,60 +209,53 @@ async function applyFix(json, file, expectedType, failResult) {
|
|
|
200
209
|
* import { PackageEsmType } from "repopo/policies";
|
|
201
210
|
*
|
|
202
211
|
* // Require all packages to be ESM
|
|
203
|
-
* makePolicy(PackageEsmType, { requiredType: "module" })
|
|
212
|
+
* makePolicy(PackageEsmType, { config: { requiredType: "module" } })
|
|
204
213
|
*
|
|
205
214
|
* // Or detect based on exports
|
|
206
|
-
* makePolicy(PackageEsmType, { detectFromExports: true })
|
|
215
|
+
* makePolicy(PackageEsmType, { config: { detectFromExports: true } })
|
|
207
216
|
* ```
|
|
208
217
|
*
|
|
209
|
-
* @
|
|
218
|
+
* @public
|
|
210
219
|
*/
|
|
211
220
|
export const PackageEsmType = definePackagePolicy({
|
|
212
221
|
name: "PackageEsmType",
|
|
222
|
+
requiresConfig: true,
|
|
213
223
|
description: "Ensures the type field in package.json correctly indicates ESM or CommonJS module format.",
|
|
214
|
-
handler: async (json, { file, config, resolve }) => {
|
|
224
|
+
handler: async (json, { file, root, config, resolve }) => {
|
|
215
225
|
// If no config provided, skip validation
|
|
216
226
|
if (config === undefined) {
|
|
217
|
-
return
|
|
227
|
+
return [];
|
|
218
228
|
}
|
|
219
229
|
const packageName = json.name;
|
|
220
230
|
// Check if package should be skipped
|
|
221
231
|
if (shouldSkipPackage(packageName, config)) {
|
|
222
|
-
return
|
|
232
|
+
return [];
|
|
223
233
|
}
|
|
224
234
|
// Determine the expected type
|
|
225
235
|
const { expectedType, detectionReason } = determineExpectedType(json, config);
|
|
226
236
|
// Handle case where type cannot be detected
|
|
227
237
|
if (expectedType === undefined) {
|
|
228
238
|
if (config.onDetectionFailure === "fail") {
|
|
229
|
-
return
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
autoFixable: false,
|
|
233
|
-
errorMessages: [
|
|
234
|
-
`Package "${packageName}": ${detectionReason ?? "Could not detect module type"}. Set "type" field explicitly or use "requiredType" config.`,
|
|
235
|
-
],
|
|
236
|
-
};
|
|
239
|
+
return [
|
|
240
|
+
`Package "${packageName}": ${detectionReason ?? "Could not detect module type"}. Set "type" field explicitly or use "requiredType" config.`,
|
|
241
|
+
].map((message) => ({ message }));
|
|
237
242
|
}
|
|
238
243
|
// "skip" and "warn" both pass validation
|
|
239
|
-
return
|
|
244
|
+
return [];
|
|
240
245
|
}
|
|
241
246
|
// Check if current type matches expected
|
|
242
247
|
if (json.type === expectedType) {
|
|
243
|
-
return
|
|
248
|
+
return [];
|
|
244
249
|
}
|
|
245
250
|
// Build failure result
|
|
246
|
-
const failResult =
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
buildErrorMessage(packageName, json.type, expectedType),
|
|
253
|
-
],
|
|
254
|
-
};
|
|
251
|
+
const failResult = [
|
|
252
|
+
buildErrorMessage(packageName, json.type, expectedType),
|
|
253
|
+
].map((message) => ({
|
|
254
|
+
message,
|
|
255
|
+
fixStatus: "available",
|
|
256
|
+
}));
|
|
255
257
|
if (resolve) {
|
|
256
|
-
return applyFix(json, file, expectedType, failResult);
|
|
258
|
+
return applyFix(json, file, root, expectedType, failResult);
|
|
257
259
|
}
|
|
258
260
|
return failResult;
|
|
259
261
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PackageEsmType.js","sourceRoot":"","sources":["../../src/policies/PackageEsmType.ts"],"names":[],"mappings":"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","sourcesContent":["import jsonfile from \"jsonfile\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure, PolicyFixResult } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\nimport { detectIndentation } from \"../utils/indentation.js\";\n\nconst { writeFile: writeJson } = jsonfile;\n\n/**\n * Configuration for the PackageEsmType policy.\n *\n * This policy ensures the `type` field in package.json is correctly set\n * to indicate whether the package is an ESM or CommonJS module.\n *\n * @example\n * ```typescript\n * const config: PackageEsmTypeConfig = {\n * // Require ESM type field for all packages\n * requiredType: \"module\",\n * // Or detect based on exports/main field\n * detectFromExports: true,\n * };\n * ```\n *\n * @alpha\n */\nexport interface PackageEsmTypeConfig {\n\t/**\n\t * The required `type` field value for all packages.\n\t *\n\t * - `\"module\"` - All packages must be ESM (use import/export)\n\t * - `\"commonjs\"` - All packages must be CommonJS (use require)\n\t * - `undefined` - Use detection logic based on exports/main\n\t *\n\t * @remarks\n\t *\n\t * If set, this overrides automatic detection. Use `detectFromExports`\n\t * for more flexible per-package type detection.\n\t */\n\trequiredType?: \"module\" | \"commonjs\";\n\n\t/**\n\t * Detect the expected `type` field from the exports or main field.\n\t *\n\t * When enabled, the policy analyzes the package's entry points:\n\t * - If exports use `.mjs` or have `import` conditions → `\"module\"`\n\t * - If exports use `.cjs` or have `require` conditions → `\"commonjs\"`\n\t * - If main field uses `.mjs` → `\"module\"`\n\t * - If main field uses `.cjs` → `\"commonjs\"`\n\t *\n\t * @defaultValue false\n\t */\n\tdetectFromExports?: boolean;\n\n\t/**\n\t * Package names or scopes to exclude from validation.\n\t *\n\t * @example\n\t * ```typescript\n\t * excludePackages: [\"@myorg/legacy-package\", \"old-cjs-lib\"]\n\t * ```\n\t */\n\texcludePackages?: string[];\n\n\t/**\n\t * Behavior when module type cannot be detected from exports/main.\n\t *\n\t * - `\"skip\"` (default) - Skip validation for packages where type cannot be detected\n\t * - `\"warn\"` - Pass validation but include a warning in the output\n\t * - `\"fail\"` - Fail validation when type cannot be detected\n\t *\n\t * This only applies when `detectFromExports` is true and no `requiredType` is set.\n\t *\n\t * @defaultValue \"skip\"\n\t */\n\tonDetectionFailure?: \"skip\" | \"warn\" | \"fail\";\n}\n\n/**\n * Result of detecting the module type from a package.\n */\ninterface DetectionResult {\n\t/**\n\t * The detected type, if any.\n\t */\n\ttype: \"module\" | \"commonjs\" | undefined;\n\n\t/**\n\t * Whether the package appears to be dual-format (both ESM and CommonJS).\n\t * When true, the `type` field should typically match the package's default format.\n\t */\n\tisDualFormat: boolean;\n\n\t/**\n\t * Human-readable reason for the detection result.\n\t */\n\treason: string;\n}\n\n/**\n * Detect module type from the exports field.\n */\nfunction detectTypeFromExports(\n\texports: PackageJson[\"exports\"],\n): DetectionResult | undefined {\n\tif (exports === undefined) {\n\t\treturn undefined;\n\t}\n\n\tconst exportsStr = JSON.stringify(exports);\n\tconst hasEsm = exportsStr.includes(\".mjs\") || exportsStr.includes('\"import\"');\n\tconst hasCjs =\n\t\texportsStr.includes(\".cjs\") || exportsStr.includes('\"require\"');\n\n\t// Dual format packages have both ESM and CJS exports\n\tif (hasEsm && hasCjs) {\n\t\treturn {\n\t\t\ttype: \"module\",\n\t\t\tisDualFormat: true,\n\t\t\treason:\n\t\t\t\t\"Package has both ESM and CommonJS exports (dual format). Defaulting to ESM.\",\n\t\t};\n\t}\n\n\tif (hasEsm) {\n\t\treturn {\n\t\t\ttype: \"module\",\n\t\t\tisDualFormat: false,\n\t\t\treason: \"Detected ESM from exports field (.mjs or import condition)\",\n\t\t};\n\t}\n\n\tif (hasCjs) {\n\t\treturn {\n\t\t\ttype: \"commonjs\",\n\t\t\tisDualFormat: false,\n\t\t\treason:\n\t\t\t\t\"Detected CommonJS from exports field (.cjs or require condition)\",\n\t\t};\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Detect module type from the main field.\n */\nfunction detectTypeFromMain(main: unknown): DetectionResult | undefined {\n\tif (typeof main !== \"string\") {\n\t\treturn undefined;\n\t}\n\n\tif (main.endsWith(\".mjs\")) {\n\t\treturn {\n\t\t\ttype: \"module\",\n\t\t\tisDualFormat: false,\n\t\t\treason: \"Detected ESM from main field (.mjs extension)\",\n\t\t};\n\t}\n\n\tif (main.endsWith(\".cjs\")) {\n\t\treturn {\n\t\t\ttype: \"commonjs\",\n\t\t\tisDualFormat: false,\n\t\t\treason: \"Detected CommonJS from main field (.cjs extension)\",\n\t\t};\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Detect the expected type field from the package's exports or main field.\n *\n * @param json - The package.json content\n * @returns Detection result with type, dual-format indicator, and reason\n */\nfunction detectTypeFromPackage(json: PackageJson): DetectionResult {\n\t// Check exports field for type hints\n\tconst exportsResult = detectTypeFromExports(json.exports);\n\tif (exportsResult !== undefined) {\n\t\treturn exportsResult;\n\t}\n\n\t// Check main field\n\tconst mainResult = detectTypeFromMain(json.main);\n\tif (mainResult !== undefined) {\n\t\treturn mainResult;\n\t}\n\n\t// Check module field (ESM entry point)\n\tif (json.module !== undefined) {\n\t\treturn {\n\t\t\ttype: \"module\",\n\t\t\tisDualFormat: false,\n\t\t\treason: \"Detected ESM from module field presence\",\n\t\t};\n\t}\n\n\treturn {\n\t\ttype: undefined,\n\t\tisDualFormat: false,\n\t\treason: \"Could not detect module type from exports, main, or module fields\",\n\t};\n}\n\n/**\n * Check if a package matches an exclusion pattern.\n *\n * @param packageName - The package name\n * @param excludePackages - List of patterns to exclude\n * @returns true if the package should be excluded\n */\nfunction isExcluded(\n\tpackageName: string,\n\texcludePackages: string[] | undefined,\n): boolean {\n\tif (excludePackages === undefined || excludePackages.length === 0) {\n\t\treturn false;\n\t}\n\n\tfor (const pattern of excludePackages) {\n\t\t// Scope matching\n\t\tif (pattern.startsWith(\"@\") && packageName.startsWith(`${pattern}/`)) {\n\t\t\treturn true;\n\t\t}\n\t\t// Exact match\n\t\tif (packageName === pattern) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Check if the package should be skipped from validation.\n */\nfunction shouldSkipPackage(\n\tpackageName: string | undefined,\n\tconfig: PackageEsmTypeConfig,\n): boolean {\n\t// Skip packages without a name\n\tif (packageName === undefined) {\n\t\treturn true;\n\t}\n\n\t// Skip the root package\n\tif (packageName === \"root\") {\n\t\treturn true;\n\t}\n\n\t// Check exclusions\n\treturn isExcluded(packageName, config.excludePackages);\n}\n\n/**\n * Determine the expected type and reason from the config and package.\n */\nfunction determineExpectedType(\n\tjson: PackageJson,\n\tconfig: PackageEsmTypeConfig,\n): {\n\texpectedType: \"module\" | \"commonjs\" | undefined;\n\tdetectionReason: string | undefined;\n} {\n\tif (config.requiredType !== undefined) {\n\t\treturn {\n\t\t\texpectedType: config.requiredType,\n\t\t\tdetectionReason: `Required type: ${config.requiredType}`,\n\t\t};\n\t}\n\n\tif (config.detectFromExports === true) {\n\t\tconst detection = detectTypeFromPackage(json);\n\t\treturn {\n\t\t\texpectedType: detection.type,\n\t\t\tdetectionReason: detection.reason,\n\t\t};\n\t}\n\n\treturn { expectedType: undefined, detectionReason: undefined };\n}\n\n/**\n * Build the error message for a type mismatch.\n */\nfunction buildErrorMessage(\n\tpackageName: string,\n\tcurrentType: string | undefined,\n\texpectedType: string,\n): string {\n\tif (currentType === undefined) {\n\t\treturn `Package \"${packageName}\" is missing the \"type\" field. Expected: \"type\": \"${expectedType}\"`;\n\t}\n\treturn `Package \"${packageName}\" has \"type\": \"${currentType}\" but expected \"type\": \"${expectedType}\"`;\n}\n\n/**\n * Apply the auto-fix for the type field.\n */\nasync function applyFix(\n\tjson: PackageJson,\n\tfile: string,\n\texpectedType: \"module\" | \"commonjs\",\n\tfailResult: PolicyFailure,\n): Promise<PolicyFixResult> {\n\tconst fixResult: PolicyFixResult = {\n\t\t...failResult,\n\t\tresolved: false,\n\t};\n\n\ttry {\n\t\tjson.type = expectedType;\n\t\tconst indent = await detectIndentation(file);\n\t\tawait writeJson(file, json, { spaces: indent });\n\t\tfixResult.resolved = true;\n\t} catch {\n\t\tfixResult.resolved = false;\n\t\tfixResult.errorMessages = [`Failed to update ${file}`];\n\t}\n\n\treturn fixResult;\n}\n\n/**\n * A policy that ensures the `type` field in package.json is correctly set.\n *\n * This policy helps maintain consistency in how packages declare their module format,\n * which is essential for proper module resolution in Node.js and bundlers.\n *\n * @remarks\n *\n * The policy can operate in two modes:\n *\n * 1. **Required Type**: Set `requiredType` to enforce a specific type for all packages\n * 2. **Detection**: Set `detectFromExports: true` to detect the expected type from\n * the package's exports or main field\n *\n * When `detectFromExports` is enabled, the policy looks for:\n * - `.mjs` extensions or `\"import\"` conditions → expects `\"module\"`\n * - `.cjs` extensions or `\"require\"` conditions → expects `\"commonjs\"`\n *\n * @example\n * ```typescript\n * import { makePolicy } from \"repopo\";\n * import { PackageEsmType } from \"repopo/policies\";\n *\n * // Require all packages to be ESM\n * makePolicy(PackageEsmType, { requiredType: \"module\" })\n *\n * // Or detect based on exports\n * makePolicy(PackageEsmType, { detectFromExports: true })\n * ```\n *\n * @alpha\n */\nexport const PackageEsmType = definePackagePolicy<\n\tPackageJson,\n\tPackageEsmTypeConfig | undefined\n>({\n\tname: \"PackageEsmType\",\n\tdescription:\n\t\t\"Ensures the type field in package.json correctly indicates ESM or CommonJS module format.\",\n\thandler: async (json, { file, config, resolve }) => {\n\t\t// If no config provided, skip validation\n\t\tif (config === undefined) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst packageName = json.name;\n\n\t\t// Check if package should be skipped\n\t\tif (shouldSkipPackage(packageName, config)) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Determine the expected type\n\t\tconst { expectedType, detectionReason } = determineExpectedType(\n\t\t\tjson,\n\t\t\tconfig,\n\t\t);\n\n\t\t// Handle case where type cannot be detected\n\t\tif (expectedType === undefined) {\n\t\t\tif (config.onDetectionFailure === \"fail\") {\n\t\t\t\treturn {\n\t\t\t\t\tname: \"PackageEsmType\",\n\t\t\t\t\tfile,\n\t\t\t\t\tautoFixable: false,\n\t\t\t\t\terrorMessages: [\n\t\t\t\t\t\t`Package \"${packageName}\": ${detectionReason ?? \"Could not detect module type\"}. Set \"type\" field explicitly or use \"requiredType\" config.`,\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t\t// \"skip\" and \"warn\" both pass validation\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check if current type matches expected\n\t\tif (json.type === expectedType) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Build failure result\n\t\tconst failResult: PolicyFailure = {\n\t\t\tname: PackageEsmType.name,\n\t\t\tfile,\n\t\t\tautoFixable: true,\n\t\t\t// packageName is guaranteed to be defined here due to shouldSkipPackage check\n\t\t\terrorMessages: [\n\t\t\t\tbuildErrorMessage(packageName as string, json.type, expectedType),\n\t\t\t],\n\t\t};\n\n\t\tif (resolve) {\n\t\t\treturn applyFix(json, file, expectedType, failResult);\n\t\t}\n\n\t\treturn failResult;\n\t},\n});\n"]}
|
|
1
|
+
{"version":3,"file":"PackageEsmType.js","sourceRoot":"","sources":["../../src/policies/PackageEsmType.ts"],"names":[],"mappings":"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","sourcesContent":["import jsonfile from \"jsonfile\";\nimport { resolve as resolvePath } from \"pathe\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFinding } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\nimport { detectIndentation } from \"../utils/indentation.js\";\n\nconst { writeFile: writeJson } = jsonfile;\n\n/**\n * Configuration for the PackageEsmType policy.\n *\n * This policy ensures the `type` field in package.json is correctly set\n * to indicate whether the package is an ESM or CommonJS module.\n *\n * @example\n * ```typescript\n * const config: PackageEsmTypeConfig = {\n * // Require ESM type field for all packages\n * requiredType: \"module\",\n * // Or detect based on exports/main field\n * detectFromExports: true,\n * };\n * ```\n *\n * @public\n */\nexport interface PackageEsmTypeConfig {\n\t/**\n\t * The required `type` field value for all packages.\n\t *\n\t * - `\"module\"` - All packages must be ESM (use import/export)\n\t * - `\"commonjs\"` - All packages must be CommonJS (use require)\n\t * - `undefined` - Use detection logic based on exports/main\n\t *\n\t * @remarks\n\t *\n\t * If set, this overrides automatic detection. Use `detectFromExports`\n\t * for more flexible per-package type detection.\n\t */\n\trequiredType?: \"module\" | \"commonjs\";\n\n\t/**\n\t * Detect the expected `type` field from the exports or main field.\n\t *\n\t * When enabled, the policy analyzes the package's entry points:\n\t * - If exports use `.mjs` or have `import` conditions → `\"module\"`\n\t * - If exports use `.cjs` or have `require` conditions → `\"commonjs\"`\n\t * - If main field uses `.mjs` → `\"module\"`\n\t * - If main field uses `.cjs` → `\"commonjs\"`\n\t *\n\t * @defaultValue false\n\t */\n\tdetectFromExports?: boolean;\n\n\t/**\n\t * Package names or scopes to exclude from validation.\n\t *\n\t * @example\n\t * ```typescript\n\t * excludePackages: [\"@myorg/legacy-package\", \"old-cjs-lib\"]\n\t * ```\n\t */\n\texcludePackages?: string[];\n\n\t/**\n\t * Behavior when module type cannot be detected from exports/main.\n\t *\n\t * - `\"skip\"` (default) - Skip validation for packages where type cannot be detected\n\t * - `\"warn\"` - Pass validation but include a warning in the output\n\t * - `\"fail\"` - Fail validation when type cannot be detected\n\t *\n\t * This only applies when `detectFromExports` is true and no `requiredType` is set.\n\t *\n\t * @defaultValue \"skip\"\n\t */\n\tonDetectionFailure?: \"skip\" | \"warn\" | \"fail\";\n}\n\n/**\n * Result of detecting the module type from a package.\n */\ninterface DetectionResult {\n\t/**\n\t * The detected type, if any.\n\t */\n\ttype: \"module\" | \"commonjs\" | undefined;\n\n\t/**\n\t * Whether the package appears to be dual-format (both ESM and CommonJS).\n\t * When true, the `type` field should typically match the package's default format.\n\t */\n\tisDualFormat: boolean;\n\n\t/**\n\t * Human-readable reason for the detection result.\n\t */\n\treason: string;\n}\n\n/**\n * Detect module type from the exports field.\n */\nfunction detectTypeFromExports(\n\texports: PackageJson[\"exports\"],\n): DetectionResult | undefined {\n\tif (exports === undefined) {\n\t\treturn undefined;\n\t}\n\n\tconst exportsStr = JSON.stringify(exports);\n\tconst hasEsm = exportsStr.includes(\".mjs\") || exportsStr.includes('\"import\"');\n\tconst hasCjs =\n\t\texportsStr.includes(\".cjs\") || exportsStr.includes('\"require\"');\n\n\t// Dual format packages have both ESM and CJS exports\n\tif (hasEsm && hasCjs) {\n\t\treturn {\n\t\t\ttype: \"module\",\n\t\t\tisDualFormat: true,\n\t\t\treason:\n\t\t\t\t\"Package has both ESM and CommonJS exports (dual format). Defaulting to ESM.\",\n\t\t};\n\t}\n\n\tif (hasEsm) {\n\t\treturn {\n\t\t\ttype: \"module\",\n\t\t\tisDualFormat: false,\n\t\t\treason: \"Detected ESM from exports field (.mjs or import condition)\",\n\t\t};\n\t}\n\n\tif (hasCjs) {\n\t\treturn {\n\t\t\ttype: \"commonjs\",\n\t\t\tisDualFormat: false,\n\t\t\treason:\n\t\t\t\t\"Detected CommonJS from exports field (.cjs or require condition)\",\n\t\t};\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Detect module type from the main field.\n */\nfunction detectTypeFromMain(main: unknown): DetectionResult | undefined {\n\tif (typeof main !== \"string\") {\n\t\treturn undefined;\n\t}\n\n\tif (main.endsWith(\".mjs\")) {\n\t\treturn {\n\t\t\ttype: \"module\",\n\t\t\tisDualFormat: false,\n\t\t\treason: \"Detected ESM from main field (.mjs extension)\",\n\t\t};\n\t}\n\n\tif (main.endsWith(\".cjs\")) {\n\t\treturn {\n\t\t\ttype: \"commonjs\",\n\t\t\tisDualFormat: false,\n\t\t\treason: \"Detected CommonJS from main field (.cjs extension)\",\n\t\t};\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Detect the expected type field from the package's exports or main field.\n *\n * @param json - The package.json content\n * @returns Detection result with type, dual-format indicator, and reason\n */\nfunction detectTypeFromPackage(json: PackageJson): DetectionResult {\n\t// Check exports field for type hints\n\tconst exportsResult = detectTypeFromExports(json.exports);\n\tif (exportsResult !== undefined) {\n\t\treturn exportsResult;\n\t}\n\n\t// Check main field\n\tconst mainResult = detectTypeFromMain(json.main);\n\tif (mainResult !== undefined) {\n\t\treturn mainResult;\n\t}\n\n\t// Check module field (ESM entry point)\n\tif (json.module !== undefined) {\n\t\treturn {\n\t\t\ttype: \"module\",\n\t\t\tisDualFormat: false,\n\t\t\treason: \"Detected ESM from module field presence\",\n\t\t};\n\t}\n\n\treturn {\n\t\ttype: undefined,\n\t\tisDualFormat: false,\n\t\treason: \"Could not detect module type from exports, main, or module fields\",\n\t};\n}\n\n/**\n * Check if a package matches an exclusion pattern.\n *\n * @param packageName - The package name\n * @param excludePackages - List of patterns to exclude\n * @returns true if the package should be excluded\n */\nfunction isExcluded(\n\tpackageName: string,\n\texcludePackages: string[] | undefined,\n): boolean {\n\tif (excludePackages === undefined || excludePackages.length === 0) {\n\t\treturn false;\n\t}\n\n\tfor (const pattern of excludePackages) {\n\t\t// Scope matching\n\t\tif (pattern.startsWith(\"@\") && packageName.startsWith(`${pattern}/`)) {\n\t\t\treturn true;\n\t\t}\n\t\t// Exact match\n\t\tif (packageName === pattern) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Check if the package should be skipped from validation.\n */\nfunction shouldSkipPackage(\n\tpackageName: string | undefined,\n\tconfig: PackageEsmTypeConfig,\n): boolean {\n\t// Skip packages without a name\n\tif (packageName === undefined) {\n\t\treturn true;\n\t}\n\n\t// Skip the root package\n\tif (packageName === \"root\") {\n\t\treturn true;\n\t}\n\n\t// Check exclusions\n\treturn isExcluded(packageName, config.excludePackages);\n}\n\n/**\n * Determine the expected type and reason from the config and package.\n */\nfunction determineExpectedType(\n\tjson: PackageJson,\n\tconfig: PackageEsmTypeConfig,\n): {\n\texpectedType: \"module\" | \"commonjs\" | undefined;\n\tdetectionReason: string | undefined;\n} {\n\tif (config.requiredType !== undefined) {\n\t\treturn {\n\t\t\texpectedType: config.requiredType,\n\t\t\tdetectionReason: `Required type: ${config.requiredType}`,\n\t\t};\n\t}\n\n\tif (config.detectFromExports === true) {\n\t\tconst detection = detectTypeFromPackage(json);\n\t\treturn {\n\t\t\texpectedType: detection.type,\n\t\t\tdetectionReason: detection.reason,\n\t\t};\n\t}\n\n\treturn { expectedType: undefined, detectionReason: undefined };\n}\n\n/**\n * Build the error message for a type mismatch.\n */\nfunction buildErrorMessage(\n\tpackageName: string,\n\tcurrentType: string | undefined,\n\texpectedType: string,\n): string {\n\tif (currentType === undefined) {\n\t\treturn `Package \"${packageName}\" is missing the \"type\" field. Expected: \"type\": \"${expectedType}\"`;\n\t}\n\treturn `Package \"${packageName}\" has \"type\": \"${currentType}\" but expected \"type\": \"${expectedType}\"`;\n}\n\n/**\n * Apply the auto-fix for the type field.\n */\nasync function applyFix(\n\tjson: PackageJson,\n\tfile: string,\n\troot: string,\n\texpectedType: \"module\" | \"commonjs\",\n\tfailResult: PolicyFinding[],\n): Promise<PolicyFinding[]> {\n\tconst fixResult: PolicyFinding[] = failResult.map((finding) => ({\n\t\t...finding,\n\t\tfixStatus: \"failed\",\n\t}));\n\ttry {\n\t\tjson.type = expectedType;\n\t\tconst filePath = resolvePath(root, file);\n\t\tconst indent = await detectIndentation(filePath);\n\t\tawait writeJson(filePath, json, { spaces: indent });\n\t\tfor (const finding of fixResult) {\n\t\t\tfinding.fixStatus = \"fixed\";\n\t\t}\n\t} catch {\n\t\tfor (const finding of fixResult) {\n\t\t\tfinding.fixStatus = \"failed\";\n\t\t}\n\t\tfixResult.splice(\n\t\t\t0,\n\t\t\tfixResult.length,\n\t\t\t...[`Failed to update ${file}`].map((message) => ({\n\t\t\t\t...fixResult[0],\n\t\t\t\tmessage,\n\t\t\t})),\n\t\t);\n\t}\n\n\treturn fixResult;\n}\n\n/**\n * A policy that ensures the `type` field in package.json is correctly set.\n *\n * This policy helps maintain consistency in how packages declare their module format,\n * which is essential for proper module resolution in Node.js and bundlers.\n *\n * @remarks\n *\n * The policy can operate in two modes:\n *\n * 1. **Required Type**: Set `requiredType` to enforce a specific type for all packages\n * 2. **Detection**: Set `detectFromExports: true` to detect the expected type from\n * the package's exports or main field\n *\n * When `detectFromExports` is enabled, the policy looks for:\n * - `.mjs` extensions or `\"import\"` conditions → expects `\"module\"`\n * - `.cjs` extensions or `\"require\"` conditions → expects `\"commonjs\"`\n *\n * @example\n * ```typescript\n * import { makePolicy } from \"repopo\";\n * import { PackageEsmType } from \"repopo/policies\";\n *\n * // Require all packages to be ESM\n * makePolicy(PackageEsmType, { config: { requiredType: \"module\" } })\n *\n * // Or detect based on exports\n * makePolicy(PackageEsmType, { config: { detectFromExports: true } })\n * ```\n *\n * @public\n */\nexport const PackageEsmType = definePackagePolicy<\n\tPackageJson,\n\tPackageEsmTypeConfig | undefined\n>({\n\tname: \"PackageEsmType\",\n\trequiresConfig: true,\n\tdescription:\n\t\t\"Ensures the type field in package.json correctly indicates ESM or CommonJS module format.\",\n\thandler: async (json, { file, root, config, resolve }) => {\n\t\t// If no config provided, skip validation\n\t\tif (config === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst packageName = json.name;\n\n\t\t// Check if package should be skipped\n\t\tif (shouldSkipPackage(packageName, config)) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Determine the expected type\n\t\tconst { expectedType, detectionReason } = determineExpectedType(\n\t\t\tjson,\n\t\t\tconfig,\n\t\t);\n\n\t\t// Handle case where type cannot be detected\n\t\tif (expectedType === undefined) {\n\t\t\tif (config.onDetectionFailure === \"fail\") {\n\t\t\t\treturn [\n\t\t\t\t\t`Package \"${packageName}\": ${detectionReason ?? \"Could not detect module type\"}. Set \"type\" field explicitly or use \"requiredType\" config.`,\n\t\t\t\t].map((message) => ({ message }));\n\t\t\t}\n\t\t\t// \"skip\" and \"warn\" both pass validation\n\t\t\treturn [];\n\t\t}\n\n\t\t// Check if current type matches expected\n\t\tif (json.type === expectedType) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Build failure result\n\t\tconst failResult: PolicyFinding[] = [\n\t\t\tbuildErrorMessage(packageName as string, json.type, expectedType),\n\t\t].map((message) => ({\n\t\t\tmessage,\n\t\t\tfixStatus: \"available\",\n\t\t}));\n\t\tif (resolve) {\n\t\t\treturn applyFix(json, file, root, expectedType, failResult);\n\t\t}\n\n\t\treturn failResult;\n\t},\n});\n"]}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* };
|
|
17
17
|
* ```
|
|
18
18
|
*
|
|
19
|
-
* @
|
|
19
|
+
* @public
|
|
20
20
|
*/
|
|
21
21
|
export interface PackageFolderNameConfig {
|
|
22
22
|
/**
|
|
@@ -73,7 +73,7 @@ export interface PackageFolderNameConfig {
|
|
|
73
73
|
*
|
|
74
74
|
* For example:
|
|
75
75
|
* - `packages/my-lib/package.json` with name `my-lib` ✓
|
|
76
|
-
* - `packages/my-lib/package.json` with name `@myorg/my-lib` ✓ (if
|
|
76
|
+
* - `packages/my-lib/package.json` with name `@myorg/my-lib` ✓ (if `@myorg` is in `stripScopes`)
|
|
77
77
|
* - `packages/wrong-name/package.json` with name `my-lib` ✗
|
|
78
78
|
*
|
|
79
79
|
* @example
|
|
@@ -84,14 +84,16 @@ export interface PackageFolderNameConfig {
|
|
|
84
84
|
* const config: RepopoConfig = {
|
|
85
85
|
* policies: [
|
|
86
86
|
* makePolicy(PackageFolderName, {
|
|
87
|
-
*
|
|
88
|
-
*
|
|
87
|
+
* config: {
|
|
88
|
+
* stripScopes: ["@myorg", "@internal"],
|
|
89
|
+
* excludePackages: ["@myorg/special-case"],
|
|
90
|
+
* },
|
|
89
91
|
* }),
|
|
90
92
|
* ],
|
|
91
93
|
* };
|
|
92
94
|
* ```
|
|
93
95
|
*
|
|
94
|
-
* @
|
|
96
|
+
* @public
|
|
95
97
|
*/
|
|
96
|
-
export declare const PackageFolderName: import("../policy.js").
|
|
98
|
+
export declare const PackageFolderName: import("../policy.js").FilePolicyDefinition<PackageFolderNameConfig | undefined>;
|
|
97
99
|
//# sourceMappingURL=PackageFolderName.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PackageFolderName.d.ts","sourceRoot":"","sources":["../../src/policies/PackageFolderName.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,uBAAuB;IACvC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAEvB;;;;;;;;;;OAUG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAuCD
|
|
1
|
+
{"version":3,"file":"PackageFolderName.d.ts","sourceRoot":"","sources":["../../src/policies/PackageFolderName.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,uBAAuB;IACvC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAEvB;;;;;;;;;;OAUG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAuCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,iBAAiB,kFAgD5B,CAAC"}
|
|
@@ -46,7 +46,7 @@ function getExpectedFolderName(packageName, stripScopes) {
|
|
|
46
46
|
*
|
|
47
47
|
* For example:
|
|
48
48
|
* - `packages/my-lib/package.json` with name `my-lib` ✓
|
|
49
|
-
* - `packages/my-lib/package.json` with name `@myorg/my-lib` ✓ (if
|
|
49
|
+
* - `packages/my-lib/package.json` with name `@myorg/my-lib` ✓ (if `@myorg` is in `stripScopes`)
|
|
50
50
|
* - `packages/wrong-name/package.json` with name `my-lib` ✗
|
|
51
51
|
*
|
|
52
52
|
* @example
|
|
@@ -57,14 +57,16 @@ function getExpectedFolderName(packageName, stripScopes) {
|
|
|
57
57
|
* const config: RepopoConfig = {
|
|
58
58
|
* policies: [
|
|
59
59
|
* makePolicy(PackageFolderName, {
|
|
60
|
-
*
|
|
61
|
-
*
|
|
60
|
+
* config: {
|
|
61
|
+
* stripScopes: ["@myorg", "@internal"],
|
|
62
|
+
* excludePackages: ["@myorg/special-case"],
|
|
63
|
+
* },
|
|
62
64
|
* }),
|
|
63
65
|
* ],
|
|
64
66
|
* };
|
|
65
67
|
* ```
|
|
66
68
|
*
|
|
67
|
-
* @
|
|
69
|
+
* @public
|
|
68
70
|
*/
|
|
69
71
|
export const PackageFolderName = definePackagePolicy({
|
|
70
72
|
name: "PackageFolderName",
|
|
@@ -75,15 +77,15 @@ export const PackageFolderName = definePackagePolicy({
|
|
|
75
77
|
const packageName = json.name;
|
|
76
78
|
// Skip packages without a name
|
|
77
79
|
if (packageName === undefined) {
|
|
78
|
-
return
|
|
80
|
+
return [];
|
|
79
81
|
}
|
|
80
82
|
// Skip the root package (common in monorepos)
|
|
81
83
|
if (packageName === "root") {
|
|
82
|
-
return
|
|
84
|
+
return [];
|
|
83
85
|
}
|
|
84
86
|
// Skip explicitly excluded packages
|
|
85
87
|
if (effectiveConfig.excludePackages?.includes(packageName)) {
|
|
86
|
-
return
|
|
88
|
+
return [];
|
|
87
89
|
}
|
|
88
90
|
// Get the folder name (parent directory of package.json)
|
|
89
91
|
const folderName = path.basename(path.dirname(file));
|
|
@@ -91,17 +93,12 @@ export const PackageFolderName = definePackagePolicy({
|
|
|
91
93
|
const expectedFolderName = getExpectedFolderName(packageName, effectiveConfig.stripScopes ?? []);
|
|
92
94
|
// Compare folder name to expected name
|
|
93
95
|
if (folderName === expectedFolderName) {
|
|
94
|
-
return
|
|
96
|
+
return [];
|
|
95
97
|
}
|
|
96
98
|
// Mismatch - build error message
|
|
97
|
-
const failResult =
|
|
98
|
-
name
|
|
99
|
-
|
|
100
|
-
autoFixable: false, // Can't auto-fix folder names
|
|
101
|
-
errorMessages: [
|
|
102
|
-
`Package folder "${folderName}" does not match package name "${packageName}". Expected folder name: "${expectedFolderName}"`,
|
|
103
|
-
],
|
|
104
|
-
};
|
|
99
|
+
const failResult = [
|
|
100
|
+
`Package folder "${folderName}" does not match package name "${packageName}". Expected folder name: "${expectedFolderName}"`,
|
|
101
|
+
].map((message) => ({ message }));
|
|
105
102
|
return failResult;
|
|
106
103
|
},
|
|
107
104
|
});
|