repopo 0.12.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 +53 -0
- package/README.md +50 -90
- package/THIRD-PARTY-LICENSES.txt +169 -11
- package/bin/dev.js +0 -0
- 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.map +1 -1
- package/esm/baseCommand.js +2 -2
- package/esm/baseCommand.js.map +1 -1
- package/esm/commands/check-native.d.ts +3 -3
- package/esm/commands/check-native.d.ts.map +1 -1
- package/esm/commands/check-native.js +26 -7
- package/esm/commands/check-native.js.map +1 -1
- package/esm/commands/check.d.ts +6 -21
- package/esm/commands/check.d.ts.map +1 -1
- package/esm/commands/check.js +73 -153
- package/esm/commands/check.js.map +1 -1
- package/esm/commands/list.d.ts.map +1 -1
- package/esm/commands/list.js +2 -1
- 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 +8 -1
- package/esm/context.d.ts.map +1 -1
- package/esm/context.js +8 -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 -16
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +3 -17
- package/esm/index.js.map +1 -1
- package/esm/makePolicy.d.ts +20 -100
- package/esm/makePolicy.d.ts.map +1 -1
- package/esm/makePolicy.js +44 -132
- package/esm/makePolicy.js.map +1 -1
- package/esm/perf.d.ts +5 -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 +4 -4
- package/esm/policies/CargoLicenceValidated.d.ts.map +1 -1
- package/esm/policies/CargoLicenceValidated.js +9 -7
- package/esm/policies/CargoLicenceValidated.js.map +1 -1
- package/esm/policies/CargoLintsConfigured.d.ts +4 -4
- package/esm/policies/CargoLintsConfigured.d.ts.map +1 -1
- package/esm/policies/CargoLintsConfigured.js +19 -15
- package/esm/policies/CargoLintsConfigured.js.map +1 -1
- package/esm/policies/CargoLockPolicy.d.ts +4 -4
- package/esm/policies/CargoLockPolicy.d.ts.map +1 -1
- package/esm/policies/CargoLockPolicy.js +15 -11
- package/esm/policies/CargoLockPolicy.js.map +1 -1
- package/esm/policies/CargoTomlRequired.d.ts +5 -5
- package/esm/policies/CargoTomlRequired.d.ts.map +1 -1
- package/esm/policies/CargoTomlRequired.js +7 -7
- package/esm/policies/CargoTomlRequired.js.map +1 -1
- package/esm/policies/CargoTomlSorted.d.ts +4 -4
- package/esm/policies/CargoTomlSorted.d.ts.map +1 -1
- package/esm/policies/CargoTomlSorted.js +21 -17
- package/esm/policies/CargoTomlSorted.js.map +1 -1
- package/esm/policies/ConditionalScripts.d.ts +10 -8
- package/esm/policies/ConditionalScripts.d.ts.map +1 -1
- package/esm/policies/ConditionalScripts.js +24 -22
- 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 +15 -18
- package/esm/policies/ExactScripts.js.map +1 -1
- package/esm/policies/GleamDepVersions.d.ts +5 -5
- package/esm/policies/GleamDepVersions.d.ts.map +1 -1
- package/esm/policies/GleamDepVersions.js +5 -5
- package/esm/policies/GleamDepVersions.js.map +1 -1
- package/esm/policies/GleamDocExists.d.ts +4 -4
- package/esm/policies/GleamDocExists.d.ts.map +1 -1
- package/esm/policies/GleamDocExists.js +6 -6
- package/esm/policies/GleamDocExists.js.map +1 -1
- package/esm/policies/GleamInternalModulesConfigured.d.ts +4 -4
- package/esm/policies/GleamInternalModulesConfigured.d.ts.map +1 -1
- package/esm/policies/GleamInternalModulesConfigured.js +8 -6
- package/esm/policies/GleamInternalModulesConfigured.js.map +1 -1
- package/esm/policies/GleamLicenceConfigured.d.ts +4 -4
- package/esm/policies/GleamLicenceConfigured.d.ts.map +1 -1
- package/esm/policies/GleamLicenceConfigured.js +8 -6
- package/esm/policies/GleamLicenceConfigured.js.map +1 -1
- package/esm/policies/GleamManifestCommitted.d.ts +10 -3
- package/esm/policies/GleamManifestCommitted.d.ts.map +1 -1
- package/esm/policies/GleamManifestCommitted.js +10 -9
- package/esm/policies/GleamManifestCommitted.js.map +1 -1
- package/esm/policies/GleamMonorepoConsistency.d.ts +13 -5
- package/esm/policies/GleamMonorepoConsistency.d.ts.map +1 -1
- package/esm/policies/GleamMonorepoConsistency.js +10 -10
- package/esm/policies/GleamMonorepoConsistency.js.map +1 -1
- package/esm/policies/GleamNameRestrictions.d.ts +4 -4
- package/esm/policies/GleamNameRestrictions.d.ts.map +1 -1
- package/esm/policies/GleamNameRestrictions.js +6 -6
- package/esm/policies/GleamNameRestrictions.js.map +1 -1
- package/esm/policies/GleamNoPathDepsInPublished.d.ts +4 -4
- package/esm/policies/GleamNoPathDepsInPublished.d.ts.map +1 -1
- package/esm/policies/GleamNoPathDepsInPublished.js +6 -6
- package/esm/policies/GleamNoPathDepsInPublished.js.map +1 -1
- package/esm/policies/GleamPathDepsValid.d.ts +3 -3
- package/esm/policies/GleamPathDepsValid.d.ts.map +1 -1
- package/esm/policies/GleamPathDepsValid.js +5 -5
- package/esm/policies/GleamPathDepsValid.js.map +1 -1
- package/esm/policies/GleamProjectStructure.d.ts +11 -4
- package/esm/policies/GleamProjectStructure.d.ts.map +1 -1
- package/esm/policies/GleamProjectStructure.js +7 -8
- package/esm/policies/GleamProjectStructure.js.map +1 -1
- package/esm/policies/GleamSharedDependencyVersions.d.ts +12 -4
- package/esm/policies/GleamSharedDependencyVersions.d.ts.map +1 -1
- package/esm/policies/GleamSharedDependencyVersions.js +10 -10
- package/esm/policies/GleamSharedDependencyVersions.js.map +1 -1
- package/esm/policies/GleamTomlRequired.d.ts +4 -4
- package/esm/policies/GleamTomlRequired.d.ts.map +1 -1
- package/esm/policies/GleamTomlRequired.js +5 -5
- package/esm/policies/GleamTomlRequired.js.map +1 -1
- package/esm/policies/GleamTomlSorted.d.ts +4 -4
- package/esm/policies/GleamTomlSorted.d.ts.map +1 -1
- package/esm/policies/GleamTomlSorted.js +21 -17
- package/esm/policies/GleamTomlSorted.js.map +1 -1
- package/esm/policies/GleamVersionConstraint.d.ts +4 -4
- package/esm/policies/GleamVersionConstraint.d.ts.map +1 -1
- package/esm/policies/GleamVersionConstraint.js +14 -10
- package/esm/policies/GleamVersionConstraint.js.map +1 -1
- package/esm/policies/HtmlFileHeaders.d.ts +4 -2
- package/esm/policies/HtmlFileHeaders.d.ts.map +1 -1
- package/esm/policies/HtmlFileHeaders.js +1 -1
- 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 +9 -3
- package/esm/policies/NoBuildDirectory.d.ts.map +1 -1
- package/esm/policies/NoBuildDirectory.js +8 -13
- package/esm/policies/NoBuildDirectory.js.map +1 -1
- 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 +9 -3
- package/esm/policies/NoTargetArtifacts.d.ts.map +1 -1
- package/esm/policies/NoTargetArtifacts.js +9 -14
- package/esm/policies/NoTargetArtifacts.js.map +1 -1
- package/esm/policies/NoUnsafeWithoutJustification.d.ts +11 -4
- package/esm/policies/NoUnsafeWithoutJustification.d.ts.map +1 -1
- package/esm/policies/NoUnsafeWithoutJustification.js +8 -9
- package/esm/policies/NoUnsafeWithoutJustification.js.map +1 -1
- package/esm/policies/NoWildcardDependencies.d.ts +5 -5
- package/esm/policies/NoWildcardDependencies.d.ts.map +1 -1
- package/esm/policies/NoWildcardDependencies.js +6 -6
- package/esm/policies/NoWildcardDependencies.js.map +1 -1
- 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 +31 -31
- 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 +6 -17
- 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 +28 -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 +15 -30
- 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 +31 -52
- 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 +31 -23
- 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 +22 -59
- 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 +39 -36
- 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 +14 -16
- package/esm/policies/PackageTestScripts.js.map +1 -1
- package/esm/policies/PublicApiDocumented.d.ts +4 -4
- package/esm/policies/PublicApiDocumented.d.ts.map +1 -1
- package/esm/policies/PublicApiDocumented.js +10 -8
- package/esm/policies/PublicApiDocumented.js.map +1 -1
- 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 +24 -24
- package/esm/policies/RequiredScripts.js.map +1 -1
- package/esm/policies/RustDocExists.d.ts +4 -4
- package/esm/policies/RustDocExists.d.ts.map +1 -1
- package/esm/policies/RustDocExists.js +6 -6
- package/esm/policies/RustDocExists.js.map +1 -1
- package/esm/policies/RustToolchainExists.d.ts +11 -4
- package/esm/policies/RustToolchainExists.d.ts.map +1 -1
- package/esm/policies/RustToolchainExists.js +10 -9
- package/esm/policies/RustToolchainExists.js.map +1 -1
- package/esm/policies/RustfmtConfigExists.d.ts +11 -4
- package/esm/policies/RustfmtConfigExists.d.ts.map +1 -1
- package/esm/policies/RustfmtConfigExists.js +10 -9
- package/esm/policies/RustfmtConfigExists.js.map +1 -1
- 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 +9 -4
- package/esm/policies/SharedDependencyVersions.d.ts.map +1 -1
- package/esm/policies/SharedDependencyVersions.js +28 -20
- package/esm/policies/SharedDependencyVersions.js.map +1 -1
- package/esm/policies/WorkspaceInheritance.d.ts +11 -4
- package/esm/policies/WorkspaceInheritance.d.ts.map +1 -1
- package/esm/policies/WorkspaceInheritance.js +10 -11
- package/esm/policies/WorkspaceInheritance.js.map +1 -1
- package/esm/policies/WorkspaceMembersValid.d.ts +11 -4
- package/esm/policies/WorkspaceMembersValid.d.ts.map +1 -1
- package/esm/policies/WorkspaceMembersValid.js +10 -11
- package/esm/policies/WorkspaceMembersValid.js.map +1 -1
- package/esm/policies/constants.d.ts.map +1 -1
- package/esm/policies/constants.js +1 -1
- package/esm/policies/constants.js.map +1 -1
- package/esm/policies.d.ts +13 -5
- package/esm/policies.d.ts.map +1 -1
- package/esm/policies.js +12 -5
- package/esm/policies.js.map +1 -1
- package/esm/policy.d.ts +61 -289
- 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 +25 -9
- package/esm/policyDefiners/defineCargoPolicy.d.ts.map +1 -1
- package/esm/policyDefiners/defineCargoPolicy.js +10 -28
- package/esm/policyDefiners/defineCargoPolicy.js.map +1 -1
- package/esm/policyDefiners/defineFileHeaderPolicy.d.ts +27 -14
- package/esm/policyDefiners/defineFileHeaderPolicy.d.ts.map +1 -1
- package/esm/policyDefiners/defineFileHeaderPolicy.js +16 -35
- package/esm/policyDefiners/defineFileHeaderPolicy.js.map +1 -1
- package/esm/policyDefiners/defineGleamPolicy.d.ts +25 -9
- package/esm/policyDefiners/defineGleamPolicy.d.ts.map +1 -1
- package/esm/policyDefiners/defineGleamPolicy.js +10 -27
- package/esm/policyDefiners/defineGleamPolicy.js.map +1 -1
- 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 +4 -12
- package/esm/policyDefiners/spdxValidator.d.ts.map +1 -1
- package/esm/policyDefiners/spdxValidator.js +26 -14
- package/esm/policyDefiners/spdxValidator.js.map +1 -1
- 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 +72 -47
- package/esm/runner.d.ts.map +1 -1
- package/esm/runner.js +153 -138
- package/esm/runner.js.map +1 -1
- 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 +19 -2
- package/package.json +42 -27
- package/scripts/benchmark.mjs +341 -0
- package/sidecar/sidecar.mjs +348 -417
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { isAbsolute, normalize, relative, resolve } from "pathe";
|
|
2
|
+
function normalizeRoot(root) {
|
|
3
|
+
return normalize(resolve(root));
|
|
4
|
+
}
|
|
5
|
+
function isPathWithinRoot(rootPath, candidatePath) {
|
|
6
|
+
const relativePath = normalize(relative(rootPath, candidatePath));
|
|
7
|
+
if (relativePath === "" || relativePath === ".") {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
return (!isAbsolute(relativePath) &&
|
|
11
|
+
relativePath !== ".." &&
|
|
12
|
+
!relativePath.startsWith("../"));
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Resolves a candidate file path against the repository root and verifies it does not escape that root.
|
|
16
|
+
*/
|
|
17
|
+
export function resolveRepoFilePath(root, filePath) {
|
|
18
|
+
if (filePath.trim().length === 0) {
|
|
19
|
+
throw new Error("File path cannot be empty.");
|
|
20
|
+
}
|
|
21
|
+
const rootPath = normalizeRoot(root);
|
|
22
|
+
const candidatePath = normalize(resolve(rootPath, filePath));
|
|
23
|
+
if (!isPathWithinRoot(rootPath, candidatePath)) {
|
|
24
|
+
throw new Error(`File path must be within repository root. Received: ${filePath}`);
|
|
25
|
+
}
|
|
26
|
+
return candidatePath;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Converts an input path into a normalized repository-relative path after validating root containment.
|
|
30
|
+
*/
|
|
31
|
+
export function normalizeRepoRelativeFilePath(root, filePath) {
|
|
32
|
+
const rootPath = normalizeRoot(root);
|
|
33
|
+
const absolutePath = resolveRepoFilePath(rootPath, filePath);
|
|
34
|
+
const relativePath = normalize(relative(rootPath, absolutePath)).replace(/\\/g, "/");
|
|
35
|
+
if (relativePath === "" || relativePath === ".") {
|
|
36
|
+
throw new Error("File path resolves to repository root instead of a file.");
|
|
37
|
+
}
|
|
38
|
+
return relativePath;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=safePaths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safePaths.js","sourceRoot":"","sources":["../../src/utils/safePaths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEjE,SAAS,aAAa,CAAC,IAAY;IAClC,OAAO,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,gBAAgB,CAAC,QAAgB,EAAE,aAAqB;IAChE,MAAM,YAAY,GAAG,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC;IAClE,IAAI,YAAY,KAAK,EAAE,IAAI,YAAY,KAAK,GAAG,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,CACN,CAAC,UAAU,CAAC,YAAY,CAAC;QACzB,YAAY,KAAK,IAAI;QACrB,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,CAC/B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,QAAgB;IACjE,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,aAAa,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE7D,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CACd,uDAAuD,QAAQ,EAAE,CACjE,CAAC;IACH,CAAC;IAED,OAAO,aAAa,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,6BAA6B,CAC5C,IAAY,EACZ,QAAgB;IAEhB,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,YAAY,GAAG,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC7D,MAAM,YAAY,GAAG,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,OAAO,CACvE,KAAK,EACL,GAAG,CACH,CAAC;IAEF,IAAI,YAAY,KAAK,EAAE,IAAI,YAAY,KAAK,GAAG,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC7E,CAAC;IAED,OAAO,YAAY,CAAC;AACrB,CAAC","sourcesContent":["import { isAbsolute, normalize, relative, resolve } from \"pathe\";\n\nfunction normalizeRoot(root: string): string {\n\treturn normalize(resolve(root));\n}\n\nfunction isPathWithinRoot(rootPath: string, candidatePath: string): boolean {\n\tconst relativePath = normalize(relative(rootPath, candidatePath));\n\tif (relativePath === \"\" || relativePath === \".\") {\n\t\treturn true;\n\t}\n\treturn (\n\t\t!isAbsolute(relativePath) &&\n\t\trelativePath !== \"..\" &&\n\t\t!relativePath.startsWith(\"../\")\n\t);\n}\n\n/**\n * Resolves a candidate file path against the repository root and verifies it does not escape that root.\n */\nexport function resolveRepoFilePath(root: string, filePath: string): string {\n\tif (filePath.trim().length === 0) {\n\t\tthrow new Error(\"File path cannot be empty.\");\n\t}\n\n\tconst rootPath = normalizeRoot(root);\n\tconst candidatePath = normalize(resolve(rootPath, filePath));\n\n\tif (!isPathWithinRoot(rootPath, candidatePath)) {\n\t\tthrow new Error(\n\t\t\t`File path must be within repository root. Received: ${filePath}`,\n\t\t);\n\t}\n\n\treturn candidatePath;\n}\n\n/**\n * Converts an input path into a normalized repository-relative path after validating root containment.\n */\nexport function normalizeRepoRelativeFilePath(\n\troot: string,\n\tfilePath: string,\n): string {\n\tconst rootPath = normalizeRoot(root);\n\tconst absolutePath = resolveRepoFilePath(rootPath, filePath);\n\tconst relativePath = normalize(relative(rootPath, absolutePath)).replace(\n\t\t/\\\\/g,\n\t\t\"/\",\n\t);\n\n\tif (relativePath === \"\" || relativePath === \".\") {\n\t\tthrow new Error(\"File path resolves to repository root instead of a file.\");\n\t}\n\n\treturn relativePath;\n}\n"]}
|
package/oclif.manifest.json
CHANGED
|
@@ -3,8 +3,16 @@
|
|
|
3
3
|
"check-native": {
|
|
4
4
|
"aliases": [],
|
|
5
5
|
"args": {},
|
|
6
|
-
"description": "Runs the Rust-based repopo-core engine with the Node.js sidecar.
|
|
6
|
+
"description": "Runs the Rust-based repopo-core engine with the Node.js sidecar. Rust handles file matching, scheduling and reporting; the sidecar shares per-policy contracts with 'check'. Repository policies always run with the full repository inventory, including with --stdin. With --fix, repository policies can modify files outside the stdin selection.",
|
|
7
7
|
"flags": {
|
|
8
|
+
"concurrency": {
|
|
9
|
+
"description": "Maximum concurrent files in read-only checks. Fixes remain sequential.",
|
|
10
|
+
"name": "concurrency",
|
|
11
|
+
"default": 8,
|
|
12
|
+
"hasDynamicHelp": false,
|
|
13
|
+
"multiple": false,
|
|
14
|
+
"type": "option"
|
|
15
|
+
},
|
|
8
16
|
"fix": {
|
|
9
17
|
"aliases": [
|
|
10
18
|
"resolve"
|
|
@@ -100,6 +108,7 @@
|
|
|
100
108
|
"check": {
|
|
101
109
|
"aliases": [],
|
|
102
110
|
"args": {},
|
|
111
|
+
"description": "File policies check selected files. Repository policies always run with the full repository file inventory, including with --stdin. With --fix, repository policies can modify files outside the stdin selection.",
|
|
103
112
|
"flags": {
|
|
104
113
|
"verbose": {
|
|
105
114
|
"char": "v",
|
|
@@ -124,6 +133,14 @@
|
|
|
124
133
|
"allowNo": false,
|
|
125
134
|
"type": "boolean"
|
|
126
135
|
},
|
|
136
|
+
"concurrency": {
|
|
137
|
+
"description": "Maximum concurrent files in read-only checks. Fixes remain sequential.",
|
|
138
|
+
"name": "concurrency",
|
|
139
|
+
"default": 8,
|
|
140
|
+
"hasDynamicHelp": false,
|
|
141
|
+
"multiple": false,
|
|
142
|
+
"type": "option"
|
|
143
|
+
},
|
|
127
144
|
"fix": {
|
|
128
145
|
"aliases": [
|
|
129
146
|
"resolve"
|
|
@@ -222,5 +239,5 @@
|
|
|
222
239
|
]
|
|
223
240
|
}
|
|
224
241
|
},
|
|
225
|
-
"version": "0.
|
|
242
|
+
"version": "0.13.0"
|
|
226
243
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "repopo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Enforce policies on all or some of the files in a git repository.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"policy",
|
|
@@ -63,47 +63,48 @@
|
|
|
63
63
|
"repositoryPrefix": "<%- repo %>/blob/main/packages/repopo/<%- commandPath %>"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@fluid-tools/build-infrastructure": "~0.
|
|
67
|
-
"@oclif/core": "^
|
|
68
|
-
"@oclif/plugin-help": "^
|
|
69
|
-
"@rushstack/node-core-library": "^5.
|
|
66
|
+
"@fluid-tools/build-infrastructure": "~0.68.0",
|
|
67
|
+
"@oclif/core": "^5.1.9",
|
|
68
|
+
"@oclif/plugin-help": "^7.0.5",
|
|
69
|
+
"@rushstack/node-core-library": "^5.25.1",
|
|
70
|
+
"@tylerbu/cli-api": "^0.11.0",
|
|
71
|
+
"@tylerbu/fundamentals": "^0.3.0",
|
|
72
|
+
"@tylerbu/lilconfig-loader-ts": "^0.1.3",
|
|
70
73
|
"consola": "^3.4.2",
|
|
71
74
|
"defu": "^6.1.7",
|
|
72
|
-
"effection": "^4.0
|
|
75
|
+
"effection": "^4.2.0",
|
|
73
76
|
"jsonfile": "^6.2.1",
|
|
74
|
-
"lilconfig": "^3.1.
|
|
75
|
-
"microdiff": "^1.
|
|
77
|
+
"lilconfig": "^3.1.4",
|
|
78
|
+
"microdiff": "^1.6.0",
|
|
76
79
|
"pathe": "^2.0.3",
|
|
77
80
|
"picocolors": "^1.1.1",
|
|
78
|
-
"picomatch": "^4.0.
|
|
81
|
+
"picomatch": "^4.0.7",
|
|
79
82
|
"resolve-workspace-root": "^2.0.1",
|
|
80
|
-
"simple-git": "^
|
|
83
|
+
"simple-git": "^4.0.2",
|
|
81
84
|
"tinyglobby": "^0.2.17",
|
|
82
|
-
"
|
|
83
|
-
"@tylerbu/fundamentals": "^0.3.0",
|
|
84
|
-
"@tylerbu/lilconfig-loader-ts": "^0.1.3"
|
|
85
|
+
"type-fest": "^5.10.0"
|
|
85
86
|
},
|
|
86
87
|
"devDependencies": {
|
|
87
88
|
"@biomejs/biome": "2.3.8",
|
|
88
|
-
"@microsoft/api-
|
|
89
|
-
"@
|
|
90
|
-
"@oclif/
|
|
89
|
+
"@microsoft/api-documenter": "^7.30.18",
|
|
90
|
+
"@microsoft/api-extractor": "^7.59.4",
|
|
91
|
+
"@oclif/plugin-command-snapshot": "^6.0.7",
|
|
92
|
+
"@oclif/test": "^5.0.3",
|
|
91
93
|
"@types/jsonfile": "^6.1.4",
|
|
92
|
-
"@types/node": "^
|
|
94
|
+
"@types/node": "^26.6.5",
|
|
93
95
|
"@types/picomatch": "^4.0.3",
|
|
94
96
|
"@types/spdx-correct": "^3.1.3",
|
|
95
97
|
"@types/tmp": "^0.2.6",
|
|
96
|
-
"@vitest/coverage-v8": "^
|
|
97
|
-
"generate-license-file": "^4.2.
|
|
98
|
-
"oclif": "^
|
|
98
|
+
"@vitest/coverage-v8": "^5.0.5",
|
|
99
|
+
"generate-license-file": "^4.2.5",
|
|
100
|
+
"oclif": "^6.0.10",
|
|
99
101
|
"rimraf": "^6.1.3",
|
|
100
|
-
"smol-toml": "^1.
|
|
102
|
+
"smol-toml": "^1.9.1",
|
|
101
103
|
"spdx-correct": "^3.2.0",
|
|
102
104
|
"tmp-promise": "^3.0.3",
|
|
103
105
|
"ts-node": "^10.9.2",
|
|
104
|
-
"type-fest": "^5.8.0",
|
|
105
106
|
"typescript": "~6.0.3",
|
|
106
|
-
"vitest": "^
|
|
107
|
+
"vitest": "^5.0.5"
|
|
107
108
|
},
|
|
108
109
|
"peerDependencies": {
|
|
109
110
|
"smol-toml": "^1.0.0",
|
|
@@ -126,12 +127,26 @@
|
|
|
126
127
|
"build": {
|
|
127
128
|
"executor": "nx:noop"
|
|
128
129
|
},
|
|
129
|
-
"ci": {}
|
|
130
|
+
"ci": {},
|
|
131
|
+
"build:readme": {
|
|
132
|
+
"inputs": [
|
|
133
|
+
"sharedGlobals",
|
|
134
|
+
"{projectRoot}/package.json",
|
|
135
|
+
"{projectRoot}/oclif.manifest.json",
|
|
136
|
+
"{projectRoot}/README.md",
|
|
137
|
+
"{workspaceRoot}/packages/repopo-docs/src/content/docs/cli-reference.md"
|
|
138
|
+
],
|
|
139
|
+
"outputs": [
|
|
140
|
+
"{projectRoot}/README.md",
|
|
141
|
+
"{projectRoot}/docs/**",
|
|
142
|
+
"{workspaceRoot}/packages/repopo-docs/src/content/docs/cli-reference.md"
|
|
143
|
+
]
|
|
144
|
+
}
|
|
130
145
|
}
|
|
131
146
|
},
|
|
132
147
|
"scripts": {
|
|
133
|
-
"api:markdown": "api-documenter markdown -i _temp/api-extractor -o _temp/docs",
|
|
134
|
-
"build:api": "api-extractor run --local",
|
|
148
|
+
"api:markdown": "rimraf _temp/docs && api-documenter markdown -i _temp/api-extractor/root -o _temp/docs/root && api-documenter markdown -i _temp/api-extractor/api -o _temp/docs/api && api-documenter markdown -i _temp/api-extractor/policies -o _temp/docs/policies",
|
|
149
|
+
"build:api": "rimraf _temp/api-extractor/root _temp/api-extractor/api _temp/api-extractor/policies && api-extractor run --local && api-extractor run --local --config api-extractor.api.json && api-extractor run --local --config api-extractor.policies.json",
|
|
135
150
|
"build:compile": "tsc --project ./tsconfig.json",
|
|
136
151
|
"build:manifest": "oclif manifest",
|
|
137
152
|
"build:readme": "concurrently npm:readme:*",
|
|
@@ -150,7 +165,7 @@
|
|
|
150
165
|
"readme:main": "oclif readme --no-aliases",
|
|
151
166
|
"release:license": "generate-license-file -c ../../.generatelicensefile.cjs",
|
|
152
167
|
"test": "vitest run",
|
|
153
|
-
"test:coverage": "vitest run --coverage",
|
|
168
|
+
"test:coverage": "mkdir -p .coverage/vitest/.tmp && vitest run --coverage",
|
|
154
169
|
"test:snapshots": "./bin/dev.js snapshot:compare --filepath test/commands/__snapshots__/commands.json",
|
|
155
170
|
"test:watch": "vitest"
|
|
156
171
|
}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { randomInt } from "node:crypto";
|
|
3
|
+
import { access, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { arch, cpus, platform, release, tmpdir } from "node:os";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
+
import { parseArgs } from "node:util";
|
|
7
|
+
import { dirname, join, resolve } from "pathe";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Measure through process exit, including startup and stdin transfer.
|
|
11
|
+
* @param {string[]} command
|
|
12
|
+
* @param {string} cwd
|
|
13
|
+
* @param {string} [input]
|
|
14
|
+
* @returns {Promise<{milliseconds: number, stdout: string}>}
|
|
15
|
+
*/
|
|
16
|
+
export async function measure(command, cwd, input = "") {
|
|
17
|
+
const start = performance.now();
|
|
18
|
+
return new Promise((resolvePromise, reject) => {
|
|
19
|
+
const child = spawn(command[0], command.slice(1), { cwd });
|
|
20
|
+
let stdout = "";
|
|
21
|
+
let stderr = "";
|
|
22
|
+
child.stdout.setEncoding("utf8").on("data", (data) => {
|
|
23
|
+
stdout += data;
|
|
24
|
+
});
|
|
25
|
+
child.stderr.setEncoding("utf8").on("data", (data) => {
|
|
26
|
+
stderr += data;
|
|
27
|
+
});
|
|
28
|
+
child.on("error", reject);
|
|
29
|
+
// A process that exits early may close stdin before consuming the snapshot.
|
|
30
|
+
child.stdin.on("error", (error) => {
|
|
31
|
+
if (error.code !== "EPIPE") {
|
|
32
|
+
reject(error);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
child.on("close", (code, signal) => {
|
|
36
|
+
if (code !== 0) {
|
|
37
|
+
reject(
|
|
38
|
+
new Error(
|
|
39
|
+
`${JSON.stringify(command)} exited with ${signal ?? code}\n${stdout}${stderr}`,
|
|
40
|
+
),
|
|
41
|
+
);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
resolvePromise({ milliseconds: performance.now() - start, stdout });
|
|
45
|
+
});
|
|
46
|
+
child.stdin.end(input);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Each round runs every case once, in shuffled order, without concurrency.
|
|
52
|
+
* @param {{scenario: string, engine: string, command: string[], input: string}[]} cases
|
|
53
|
+
* @param {{cwd: string, warmup: number, runs: number}} options
|
|
54
|
+
*/
|
|
55
|
+
export async function runRounds(cases, { cwd, warmup, runs }) {
|
|
56
|
+
const samples = [];
|
|
57
|
+
for (let round = -warmup; round < runs; round++) {
|
|
58
|
+
const ordered = [...cases];
|
|
59
|
+
for (let i = ordered.length - 1; i > 0; i--) {
|
|
60
|
+
const j = randomInt(i + 1);
|
|
61
|
+
[ordered[i], ordered[j]] = [ordered[j], ordered[i]];
|
|
62
|
+
}
|
|
63
|
+
for (const [order, entry] of ordered.entries()) {
|
|
64
|
+
const { milliseconds } = await measure(entry.command, cwd, entry.input);
|
|
65
|
+
if (round >= 0) {
|
|
66
|
+
samples.push({
|
|
67
|
+
scenario: entry.scenario,
|
|
68
|
+
engine: entry.engine,
|
|
69
|
+
round,
|
|
70
|
+
order,
|
|
71
|
+
milliseconds,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
console.log(
|
|
76
|
+
`${round < 0 ? "Warmup" : "Timed"} round ${round < 0 ? round + warmup + 1 : round + 1} complete`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
return samples;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** @param {number[]} values */
|
|
83
|
+
export function summarize(values) {
|
|
84
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
85
|
+
if (sorted.length === 0) {
|
|
86
|
+
throw new Error("Cannot summarize an empty sample.");
|
|
87
|
+
}
|
|
88
|
+
const quantile = (fraction) => {
|
|
89
|
+
const index = (sorted.length - 1) * fraction;
|
|
90
|
+
const lower = Math.floor(index);
|
|
91
|
+
return (
|
|
92
|
+
sorted[lower] +
|
|
93
|
+
(sorted[Math.ceil(index)] - sorted[lower]) * (index - lower)
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
const mean = values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
97
|
+
return {
|
|
98
|
+
median: quantile(0.5),
|
|
99
|
+
mean,
|
|
100
|
+
stddev:
|
|
101
|
+
values.length < 2
|
|
102
|
+
? 0
|
|
103
|
+
: Math.sqrt(
|
|
104
|
+
values.reduce((sum, value) => sum + (value - mean) ** 2, 0) /
|
|
105
|
+
(values.length - 1),
|
|
106
|
+
),
|
|
107
|
+
p25: quantile(0.25),
|
|
108
|
+
p75: quantile(0.75),
|
|
109
|
+
min: sorted[0],
|
|
110
|
+
max: sorted.at(-1),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function main() {
|
|
115
|
+
const { values } = parseArgs({
|
|
116
|
+
options: {
|
|
117
|
+
quick: { type: "boolean" },
|
|
118
|
+
runs: { type: "string" },
|
|
119
|
+
warmup: { type: "string" },
|
|
120
|
+
json: { type: "string" },
|
|
121
|
+
scenario: { type: "string", multiple: true },
|
|
122
|
+
help: { type: "boolean" },
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
if (values.help) {
|
|
126
|
+
console.log(
|
|
127
|
+
"Usage: benchmark.sh [--quick] [--runs N] [--warmup N] [--json PATH] [--scenario NAME ...]",
|
|
128
|
+
);
|
|
129
|
+
console.log(
|
|
130
|
+
"Scenarios: startup, empty, inventory-stdin, inventory-git, config, matching, noop, real-stdin, real-git",
|
|
131
|
+
);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const runs = Number(values.runs ?? (values.quick ? 3 : 10));
|
|
135
|
+
const warmup = Number(values.warmup ?? (values.quick ? 1 : 3));
|
|
136
|
+
if (
|
|
137
|
+
!Number.isInteger(runs) ||
|
|
138
|
+
runs < 1 ||
|
|
139
|
+
!Number.isInteger(warmup) ||
|
|
140
|
+
warmup < 0
|
|
141
|
+
) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
"--runs must be a positive integer; --warmup must be a non-negative integer.",
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
147
|
+
const cwd = resolve(packageRoot, "../..");
|
|
148
|
+
const cli = join(packageRoot, "bin/run.js");
|
|
149
|
+
const binary = join(
|
|
150
|
+
packageRoot,
|
|
151
|
+
"crates/core/target/release",
|
|
152
|
+
platform() === "win32" ? "repopo-core.exe" : "repopo-core",
|
|
153
|
+
);
|
|
154
|
+
await access(join(packageRoot, "esm/commands/check.js"));
|
|
155
|
+
try {
|
|
156
|
+
await access(binary);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
"Build the release engine first: cargo build --release --manifest-path packages/repopo/crates/core/Cargo.toml",
|
|
160
|
+
{ cause: error },
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
let bunVersion = null;
|
|
164
|
+
try {
|
|
165
|
+
bunVersion = (await measure(["bun", "--version"], cwd)).stdout.trim();
|
|
166
|
+
} catch (error) {
|
|
167
|
+
if (error.code !== "ENOENT") {
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
console.log("Bun not found; skipping Bun variants.");
|
|
171
|
+
}
|
|
172
|
+
const inventory = (
|
|
173
|
+
await measure(
|
|
174
|
+
["git", "ls-files", "-co", "-z", "--exclude-standard", "--full-name"],
|
|
175
|
+
cwd,
|
|
176
|
+
)
|
|
177
|
+
).stdout;
|
|
178
|
+
const files = inventory.split("\0").filter(Boolean);
|
|
179
|
+
if (files.some((file) => /[\r\n]/.test(file))) {
|
|
180
|
+
throw new Error(
|
|
181
|
+
"The stdin benchmark cannot represent filenames containing newlines.",
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
const snapshot = `${files.join("\n")}\n`;
|
|
185
|
+
const directory = await mkdtemp(join(tmpdir(), "repopo-benchmark-"));
|
|
186
|
+
try {
|
|
187
|
+
const empty = join(directory, "empty.mjs");
|
|
188
|
+
const miss = join(directory, "miss.mjs");
|
|
189
|
+
const noop = join(directory, "noop.mjs");
|
|
190
|
+
await writeFile(empty, "export default { policies: [] };\n");
|
|
191
|
+
for (const [path, pattern] of [
|
|
192
|
+
[miss, "/^$/"],
|
|
193
|
+
[noop, "/./"],
|
|
194
|
+
]) {
|
|
195
|
+
await writeFile(
|
|
196
|
+
path,
|
|
197
|
+
`
|
|
198
|
+
import { policy } from ${JSON.stringify(pathToFileURL(join(packageRoot, "esm/makePolicy.js")).href)};
|
|
199
|
+
export default { policies: Array.from({ length: 20 }, (_, i) => policy({
|
|
200
|
+
name: "Benchmark" + i,
|
|
201
|
+
description: "Synthetic benchmark policy",
|
|
202
|
+
match: ${pattern},
|
|
203
|
+
handler: async () => true,
|
|
204
|
+
})) };
|
|
205
|
+
`,
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
const scenarios = [
|
|
209
|
+
{ name: "startup", args: null, input: "" },
|
|
210
|
+
{ name: "empty", args: ["--config", empty, "--stdin"], input: "" },
|
|
211
|
+
{
|
|
212
|
+
name: "inventory-stdin",
|
|
213
|
+
args: ["--config", empty, "--stdin"],
|
|
214
|
+
input: snapshot,
|
|
215
|
+
},
|
|
216
|
+
{ name: "inventory-git", args: ["--config", empty], input: "" },
|
|
217
|
+
{ name: "config", args: ["--config", miss, "--stdin"], input: "" },
|
|
218
|
+
{
|
|
219
|
+
name: "matching",
|
|
220
|
+
args: ["--config", miss, "--stdin"],
|
|
221
|
+
input: snapshot,
|
|
222
|
+
},
|
|
223
|
+
{ name: "noop", args: ["--config", noop, "--stdin"], input: snapshot },
|
|
224
|
+
{ name: "real-stdin", args: ["--stdin"], input: snapshot },
|
|
225
|
+
{ name: "real-git", args: [], input: "" },
|
|
226
|
+
];
|
|
227
|
+
for (const name of values.scenario ?? []) {
|
|
228
|
+
if (!scenarios.some((scenario) => scenario.name === name)) {
|
|
229
|
+
throw new Error(`Unknown scenario: ${name}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const engines = [
|
|
233
|
+
{ name: "typescript", prefix: [process.execPath, cli], args: ["check"] },
|
|
234
|
+
...["node", ...(bunVersion ? ["bun"] : [])].flatMap((runtime) => [
|
|
235
|
+
{
|
|
236
|
+
name: `core-${runtime}`,
|
|
237
|
+
prefix: [binary],
|
|
238
|
+
args: [
|
|
239
|
+
"check",
|
|
240
|
+
"--sidecar-path",
|
|
241
|
+
join(packageRoot, "sidecar/sidecar.mjs"),
|
|
242
|
+
"--runtime",
|
|
243
|
+
runtime,
|
|
244
|
+
],
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
name: `cli-${runtime}`,
|
|
248
|
+
prefix: [process.execPath, cli],
|
|
249
|
+
args: ["check-native", "--binary-path", binary, "--runtime", runtime],
|
|
250
|
+
},
|
|
251
|
+
]),
|
|
252
|
+
];
|
|
253
|
+
const cases = scenarios
|
|
254
|
+
.filter(
|
|
255
|
+
(scenario) =>
|
|
256
|
+
!values.scenario || values.scenario.includes(scenario.name),
|
|
257
|
+
)
|
|
258
|
+
.flatMap((scenario) =>
|
|
259
|
+
engines.map((engine) => ({
|
|
260
|
+
scenario: scenario.name,
|
|
261
|
+
engine: engine.name,
|
|
262
|
+
command: [
|
|
263
|
+
...engine.prefix,
|
|
264
|
+
...(scenario.args === null
|
|
265
|
+
? ["--help"]
|
|
266
|
+
: [...engine.args, "--quiet", ...scenario.args]),
|
|
267
|
+
],
|
|
268
|
+
input: scenario.input,
|
|
269
|
+
})),
|
|
270
|
+
);
|
|
271
|
+
console.log(
|
|
272
|
+
`${files.length} files; ${cases.length} cases; ${warmup} warmups + ${runs} timed rounds. Any nonzero exit aborts.`,
|
|
273
|
+
);
|
|
274
|
+
const samples = await runRounds(cases, { cwd, runs, warmup });
|
|
275
|
+
const results = cases.map((entry) => ({
|
|
276
|
+
scenario: entry.scenario,
|
|
277
|
+
engine: entry.engine,
|
|
278
|
+
...summarize(
|
|
279
|
+
samples
|
|
280
|
+
.filter(
|
|
281
|
+
(sample) =>
|
|
282
|
+
sample.scenario === entry.scenario &&
|
|
283
|
+
sample.engine === entry.engine,
|
|
284
|
+
)
|
|
285
|
+
.map((sample) => sample.milliseconds),
|
|
286
|
+
),
|
|
287
|
+
}));
|
|
288
|
+
console.table(
|
|
289
|
+
results.map(({ scenario, engine, median, mean, stddev, p25, p75 }) => ({
|
|
290
|
+
scenario,
|
|
291
|
+
engine,
|
|
292
|
+
"median ms": median.toFixed(1),
|
|
293
|
+
"mean ms": mean.toFixed(1),
|
|
294
|
+
"sd ms": stddev.toFixed(1),
|
|
295
|
+
"p25 ms": p25.toFixed(1),
|
|
296
|
+
"p75 ms": p75.toFixed(1),
|
|
297
|
+
})),
|
|
298
|
+
);
|
|
299
|
+
if (values.json) {
|
|
300
|
+
await writeFile(
|
|
301
|
+
resolve(values.json),
|
|
302
|
+
`${JSON.stringify(
|
|
303
|
+
{
|
|
304
|
+
metadata: {
|
|
305
|
+
timestamp: new Date().toISOString(),
|
|
306
|
+
cwd,
|
|
307
|
+
node: process.version,
|
|
308
|
+
bun: bunVersion,
|
|
309
|
+
platform: platform(),
|
|
310
|
+
release: release(),
|
|
311
|
+
arch: arch(),
|
|
312
|
+
cpu: cpus()[0]?.model,
|
|
313
|
+
files: files.length,
|
|
314
|
+
syntheticPolicies: 20,
|
|
315
|
+
runs,
|
|
316
|
+
warmup,
|
|
317
|
+
units: "milliseconds",
|
|
318
|
+
},
|
|
319
|
+
cases,
|
|
320
|
+
samples,
|
|
321
|
+
results,
|
|
322
|
+
},
|
|
323
|
+
null,
|
|
324
|
+
2,
|
|
325
|
+
)}\n`,
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
} finally {
|
|
329
|
+
await rm(directory, { recursive: true, force: true });
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (
|
|
334
|
+
process.argv[1] &&
|
|
335
|
+
resolve(process.argv[1]) === fileURLToPath(import.meta.url)
|
|
336
|
+
) {
|
|
337
|
+
main().catch((error) => {
|
|
338
|
+
console.error(error);
|
|
339
|
+
process.exitCode = 1;
|
|
340
|
+
});
|
|
341
|
+
}
|