repopo 0.7.1 → 0.9.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 +217 -6
- package/THIRD-PARTY-LICENSES.txt +152 -5
- package/esm/adapters/fluidFramework.d.ts +103 -0
- package/esm/adapters/fluidFramework.d.ts.map +1 -0
- package/esm/adapters/fluidFramework.js +124 -0
- package/esm/adapters/fluidFramework.js.map +1 -0
- package/esm/baseCommand.d.ts +1 -0
- package/esm/baseCommand.d.ts.map +1 -1
- package/esm/baseCommand.js +2 -0
- package/esm/baseCommand.js.map +1 -1
- package/esm/commands/check.d.ts.map +1 -1
- package/esm/commands/check.js +76 -50
- package/esm/commands/check.js.map +1 -1
- package/esm/commands/list.d.ts.map +1 -1
- package/esm/commands/list.js +3 -1
- package/esm/commands/list.js.map +1 -1
- package/esm/generators.d.ts +30 -2
- package/esm/generators.d.ts.map +1 -1
- package/esm/generators.js +31 -1
- package/esm/generators.js.map +1 -1
- package/esm/index.d.ts +14 -3
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +13 -2
- package/esm/index.js.map +1 -1
- package/esm/makePolicy.d.ts +31 -2
- package/esm/makePolicy.d.ts.map +1 -1
- package/esm/makePolicy.js +27 -13
- package/esm/makePolicy.js.map +1 -1
- package/esm/perf.d.ts +6 -2
- package/esm/perf.d.ts.map +1 -1
- package/esm/perf.js +5 -4
- package/esm/perf.js.map +1 -1
- package/esm/policies/HtmlFileHeaders.d.ts.map +1 -1
- package/esm/policies/HtmlFileHeaders.js +11 -7
- package/esm/policies/HtmlFileHeaders.js.map +1 -1
- package/esm/policies/JsTsFileHeaders.d.ts.map +1 -1
- package/esm/policies/JsTsFileHeaders.js +11 -7
- package/esm/policies/JsTsFileHeaders.js.map +1 -1
- package/esm/policies/LicenseFileExists.d.ts.map +1 -1
- package/esm/policies/LicenseFileExists.js +22 -16
- package/esm/policies/LicenseFileExists.js.map +1 -1
- package/esm/policies/NoJsFileExtensions.d.ts.map +1 -1
- package/esm/policies/NoJsFileExtensions.js +16 -9
- package/esm/policies/NoJsFileExtensions.js.map +1 -1
- package/esm/policies/NoLargeBinaryFiles.d.ts.map +1 -1
- package/esm/policies/NoLargeBinaryFiles.js +35 -29
- package/esm/policies/NoLargeBinaryFiles.js.map +1 -1
- package/esm/policies/NoPrivateWorkspaceDependencies.d.ts +37 -0
- package/esm/policies/NoPrivateWorkspaceDependencies.d.ts.map +1 -0
- package/esm/policies/NoPrivateWorkspaceDependencies.js +145 -0
- package/esm/policies/NoPrivateWorkspaceDependencies.js.map +1 -0
- package/esm/policies/PackageAllowedScopes.d.ts +88 -0
- package/esm/policies/PackageAllowedScopes.d.ts.map +1 -0
- package/esm/policies/PackageAllowedScopes.js +118 -0
- package/esm/policies/PackageAllowedScopes.js.map +1 -0
- package/esm/policies/PackageEsmType.d.ts +100 -0
- package/esm/policies/PackageEsmType.d.ts.map +1 -0
- package/esm/policies/PackageEsmType.js +261 -0
- package/esm/policies/PackageEsmType.js.map +1 -0
- package/esm/policies/PackageFolderName.d.ts +97 -0
- package/esm/policies/PackageFolderName.d.ts.map +1 -0
- package/esm/policies/PackageFolderName.js +108 -0
- package/esm/policies/PackageFolderName.js.map +1 -0
- package/esm/policies/PackageJsonProperties.d.ts.map +1 -1
- package/esm/policies/PackageJsonProperties.js +36 -30
- package/esm/policies/PackageJsonProperties.js.map +1 -1
- package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts.map +1 -1
- package/esm/policies/PackageJsonRepoDirectoryProperty.js +41 -37
- package/esm/policies/PackageJsonRepoDirectoryProperty.js.map +1 -1
- package/esm/policies/PackageJsonSorted.d.ts.map +1 -1
- package/esm/policies/PackageJsonSorted.js +40 -28
- package/esm/policies/PackageJsonSorted.js.map +1 -1
- package/esm/policies/PackageLicense.d.ts +61 -0
- package/esm/policies/PackageLicense.d.ts.map +1 -0
- package/esm/policies/PackageLicense.js +135 -0
- package/esm/policies/PackageLicense.js.map +1 -0
- package/esm/policies/PackagePrivateField.d.ts +124 -0
- package/esm/policies/PackagePrivateField.d.ts.map +1 -0
- package/esm/policies/PackagePrivateField.js +159 -0
- package/esm/policies/PackagePrivateField.js.map +1 -0
- package/esm/policies/PackageReadme.d.ts +77 -0
- package/esm/policies/PackageReadme.d.ts.map +1 -0
- package/esm/policies/PackageReadme.js +213 -0
- package/esm/policies/PackageReadme.js.map +1 -0
- package/esm/policies/PackageScripts.d.ts +180 -2
- package/esm/policies/PackageScripts.d.ts.map +1 -1
- package/esm/policies/PackageScripts.js +358 -34
- package/esm/policies/PackageScripts.js.map +1 -1
- package/esm/policies/PackageTestScripts.d.ts +100 -0
- package/esm/policies/PackageTestScripts.d.ts.map +1 -0
- package/esm/policies/PackageTestScripts.js +155 -0
- package/esm/policies/PackageTestScripts.js.map +1 -0
- package/esm/policies/RequiredGitignorePatterns.d.ts.map +1 -1
- package/esm/policies/RequiredGitignorePatterns.js +30 -19
- package/esm/policies/RequiredGitignorePatterns.js.map +1 -1
- package/esm/policies.d.ts +9 -1
- package/esm/policies.d.ts.map +1 -1
- package/esm/policies.js +10 -1
- package/esm/policies.js.map +1 -1
- package/esm/policy.d.ts +37 -8
- package/esm/policy.d.ts.map +1 -1
- package/esm/policy.js +18 -9
- package/esm/policy.js.map +1 -1
- package/esm/policyDefiners/defineFileHeaderPolicy.d.ts +43 -1
- package/esm/policyDefiners/defineFileHeaderPolicy.d.ts.map +1 -1
- package/esm/policyDefiners/defineFileHeaderPolicy.js +18 -5
- package/esm/policyDefiners/defineFileHeaderPolicy.js.map +1 -1
- package/esm/policyDefiners/definePackagePolicy.d.ts +43 -2
- package/esm/policyDefiners/definePackagePolicy.d.ts.map +1 -1
- package/esm/policyDefiners/definePackagePolicy.js +41 -5
- package/esm/policyDefiners/definePackagePolicy.js.map +1 -1
- package/esm/tsdoc-metadata.json +1 -1
- package/esm/utils/indentation.d.ts +73 -0
- package/esm/utils/indentation.d.ts.map +1 -0
- package/esm/utils/indentation.js +97 -0
- package/esm/utils/indentation.js.map +1 -0
- package/esm/utils/packageName.d.ts +71 -0
- package/esm/utils/packageName.d.ts.map +1 -0
- package/esm/utils/packageName.js +79 -0
- package/esm/utils/packageName.js.map +1 -0
- package/oclif.manifest.json +1 -1
- package/package.json +33 -16
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NoLargeBinaryFiles.js","sourceRoot":"","sources":["../../src/policies/NoLargeBinaryFiles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,IAAI,MAAM,OAAO,CAAC;AACzB,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AA2BxD;;GAEG;AACH,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAE1C;;GAEG;AACH,MAAM,0BAA0B,GAAG;IAClC,KAAK;IACL,MAAM;IACN,OAAO;IACP,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,MAAM;IACN,OAAO;IACP,SAAS;CACT,CAAC;AAEF;;;GAGG;AACH,SAAS,WAAW,CAAC,OAAe;IACnC,+CAA+C;IAC/C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC;IAC9D,wCAAwC;IACxC,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAClD,OAAO,IAAI,MAAM,CAAC,IAAI,YAAY,GAAG,CAAC,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAClB,QAAgB,EAChB,eAAyB,EACzB,iBAA2B;IAE3B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IAEjD,mBAAmB;IACnB,IAAI,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC;IACb,CAAC;IAED,6CAA6C;IAC7C,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;QACvC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;YACnC,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1B,OAAO,IAAI,CAAC;YACb,CAAC;QACF,CAAC;aAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACvC,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,KAAa;IACjC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QACjB,OAAO,KAAK,CAAC;IACd,CAAC;IACD,MAAM,CAAC,GAAG,IAAI,CAAC;IACf,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CACjB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EACzC,KAAK,CAAC,MAAM,GAAG,CAAC,CAChB,CAAC;IACF,MAAM,SAAS,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9C,OAAO,GAAG,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACnC,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAC9B,oBAAoB,
|
|
1
|
+
{"version":3,"file":"NoLargeBinaryFiles.js","sourceRoot":"","sources":["../../src/policies/NoLargeBinaryFiles.ts"],"names":[],"mappings":"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","sourcesContent":["import { statSync } from \"node:fs\";\nimport path from \"pathe\";\nimport { makePolicyDefinition } from \"../makePolicy.js\";\nimport type { PolicyDefinition, PolicyFailure } from \"../policy.js\";\n\n/**\n * Policy settings for the NoLargeBinaryFiles repo policy.\n *\n * @alpha\n */\nexport interface NoLargeBinaryFilesSettings {\n\t/**\n\t * Maximum file size in bytes. Defaults to 10MB.\n\t */\n\tmaxSizeBytes?: number;\n\n\t/**\n\t * File extensions to exclude from size checking.\n\t * Useful for known large files that should be allowed.\n\t */\n\texcludeExtensions?: string[];\n\n\t/**\n\t * File patterns to exclude from size checking.\n\t * Uses glob-style patterns.\n\t */\n\texcludePatterns?: string[];\n}\n\n/**\n * Default maximum file size (10MB in bytes).\n */\nconst DEFAULT_MAX_SIZE = 10 * 1024 * 1024;\n\n/**\n * Default file extensions that are typically safe to exclude from size limits.\n */\nconst DEFAULT_EXCLUDE_EXTENSIONS = [\n\t\".md\",\n\t\".txt\",\n\t\".json\",\n\t\".js\",\n\t\".ts\",\n\t\".jsx\",\n\t\".tsx\",\n\t\".css\",\n\t\".scss\",\n\t\".sass\",\n\t\".less\",\n\t\".html\",\n\t\".xml\",\n\t\".yml\",\n\t\".yaml\",\n\t\".toml\",\n\t\".ini\",\n\t\".conf\",\n\t\".config\",\n];\n\n/**\n * Convert a glob pattern to a regex pattern by escaping special characters\n * and converting * to .* for wildcard matching.\n */\nfunction globToRegex(pattern: string): RegExp {\n\t// Escape all regex special characters except *\n\tconst escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\t// Convert * to .* for wildcard matching\n\tconst regexPattern = escaped.replace(/\\*/g, \".*\");\n\treturn new RegExp(`^${regexPattern}$`);\n}\n\n/**\n * Check if a file matches any of the exclude patterns.\n */\nfunction isExcluded(\n\tfilePath: string,\n\texcludePatterns: string[],\n\texcludeExtensions: string[],\n): boolean {\n\tconst ext = path.extname(filePath).toLowerCase();\n\n\t// Check extensions\n\tif (excludeExtensions.includes(ext)) {\n\t\treturn true;\n\t}\n\n\t// Check patterns (simple glob-like matching)\n\tfor (const pattern of excludePatterns) {\n\t\tif (pattern.includes(\"*\")) {\n\t\t\tconst regex = globToRegex(pattern);\n\t\t\tif (regex.test(filePath)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else if (filePath.includes(pattern)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Format bytes in a human-readable format.\n */\nfunction formatBytes(bytes: number): string {\n\tif (bytes === 0) {\n\t\treturn \"0 B\";\n\t}\n\tconst k = 1024;\n\tconst sizes = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\"];\n\tconst i = Math.min(\n\t\tMath.floor(Math.log(bytes) / Math.log(k)),\n\t\tsizes.length - 1,\n\t);\n\tconst formatted = (bytes / k ** i).toFixed(1);\n\treturn `${formatted} ${sizes[i]}`;\n}\n\n/**\n * A repo policy that prevents large binary files from being committed to the repository.\n * Large files can bloat the repository and slow down clones. Consider using Git LFS for large assets.\n *\n * @alpha\n */\nexport const NoLargeBinaryFiles: PolicyDefinition<NoLargeBinaryFilesSettings> =\n\tmakePolicyDefinition({\n\t\tname: \"NoLargeBinaryFiles\",\n\t\tdescription:\n\t\t\t\"Prevents large binary files from being committed to avoid repository bloat; consider using Git LFS for large assets.\",\n\t\t// Match all files\n\t\tmatch: /.*/,\n\t\thandler: async ({ file, root, config }) => {\n\t\t\tconst maxSizeBytes = config?.maxSizeBytes ?? DEFAULT_MAX_SIZE;\n\t\t\tconst excludeExtensions =\n\t\t\t\tconfig?.excludeExtensions ?? DEFAULT_EXCLUDE_EXTENSIONS;\n\t\t\tconst excludePatterns = config?.excludePatterns ?? [];\n\n\t\t\t// Skip excluded files\n\t\t\tif (isExcluded(file, excludePatterns, excludeExtensions)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst filePath = path.resolve(root, file);\n\t\t\t\tconst stats = statSync(filePath);\n\n\t\t\t\t// Skip directories\n\t\t\t\tif (stats.isDirectory()) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif (stats.size > maxSizeBytes) {\n\t\t\t\t\tconst result: PolicyFailure = {\n\t\t\t\t\t\tname: NoLargeBinaryFiles.name,\n\t\t\t\t\t\tfile,\n\t\t\t\t\t\tautoFixable: false,\n\t\t\t\t\t\terrorMessages: [\n\t\t\t\t\t\t\t`File is too large: ${formatBytes(stats.size)} (max: ${formatBytes(maxSizeBytes)}). Consider using Git LFS or removing the file.`,\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t} catch (_error: unknown) {\n\t\t\t\t// File doesn't exist or can't be accessed, skip it\n\t\t\t\treturn true;\n\t\t\t}\n\t\t},\n\t});\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the NoPrivateWorkspaceDependencies policy.
|
|
3
|
+
*/
|
|
4
|
+
export interface NoPrivateWorkspaceDependenciesSettings {
|
|
5
|
+
/**
|
|
6
|
+
* Whether to check devDependencies in addition to dependencies.
|
|
7
|
+
* @default false
|
|
8
|
+
*/
|
|
9
|
+
checkDevDependencies?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Policy that prevents publishable packages from depending on private workspace packages.
|
|
13
|
+
*
|
|
14
|
+
* A package is considered "publishable" if it does not have `"private": true` in its package.json.
|
|
15
|
+
* Such packages cannot have `workspace:` dependencies on packages that are marked as private,
|
|
16
|
+
* because those dependencies won't be resolvable when the package is published to npm.
|
|
17
|
+
*
|
|
18
|
+
* This policy uses the workspace configuration (pnpm-workspace.yaml or package.json workspaces field)
|
|
19
|
+
* to locate workspace packages, rather than hardcoding directory conventions.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* // In repopo.config.ts
|
|
24
|
+
* import { NoPrivateWorkspaceDependencies } from "repopo/policies";
|
|
25
|
+
*
|
|
26
|
+
* makePolicy(NoPrivateWorkspaceDependencies, {
|
|
27
|
+
* checkDevDependencies: false, // Only check production dependencies (default)
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* // Or check both dependencies and devDependencies
|
|
31
|
+
* makePolicy(NoPrivateWorkspaceDependencies, {
|
|
32
|
+
* checkDevDependencies: true,
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare const NoPrivateWorkspaceDependencies: import("../policy.js").PolicyDefinition<NoPrivateWorkspaceDependenciesSettings | undefined>;
|
|
37
|
+
//# sourceMappingURL=NoPrivateWorkspaceDependencies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoPrivateWorkspaceDependencies.d.ts","sourceRoot":"","sources":["../../src/policies/NoPrivateWorkspaceDependencies.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,MAAM,WAAW,sCAAsC;IACtD;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAC/B;AA6ED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,8BAA8B,6FAyEzC,CAAC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
// Use default import + destructure for CJS/ESM interop
|
|
3
|
+
// (resolve-workspace-root is a bundled CJS module)
|
|
4
|
+
import resolveWorkspaceRoot from "resolve-workspace-root";
|
|
5
|
+
const { getWorkspaceGlobs } = resolveWorkspaceRoot;
|
|
6
|
+
import { globSync } from "tinyglobby";
|
|
7
|
+
import { definePackagePolicy } from "../policyDefiners/definePackagePolicy.js";
|
|
8
|
+
/**
|
|
9
|
+
* Cache for workspace package lookups to avoid repeated filesystem operations.
|
|
10
|
+
*/
|
|
11
|
+
const workspacePackageCache = new Map();
|
|
12
|
+
/**
|
|
13
|
+
* Builds a map of package name to package.json for all packages in the workspace.
|
|
14
|
+
* Uses the workspace configuration (pnpm-workspace.yaml or package.json workspaces) to find packages.
|
|
15
|
+
*/
|
|
16
|
+
function buildWorkspacePackageMap(root) {
|
|
17
|
+
// Check cache first
|
|
18
|
+
const cached = workspacePackageCache.get(root);
|
|
19
|
+
if (cached !== undefined) {
|
|
20
|
+
return cached;
|
|
21
|
+
}
|
|
22
|
+
const packageMap = new Map();
|
|
23
|
+
// Get workspace globs from pnpm-workspace.yaml or package.json
|
|
24
|
+
const workspaceGlobs = getWorkspaceGlobs(root);
|
|
25
|
+
if (workspaceGlobs === null) {
|
|
26
|
+
// Not a workspace - return empty map
|
|
27
|
+
workspacePackageCache.set(root, packageMap);
|
|
28
|
+
return packageMap;
|
|
29
|
+
}
|
|
30
|
+
// Find all package.json files matching the workspace globs
|
|
31
|
+
const packageGlobs = workspaceGlobs.map((g) => `${g}/package.json`);
|
|
32
|
+
const packageJsonPaths = globSync(packageGlobs, {
|
|
33
|
+
cwd: root,
|
|
34
|
+
ignore: ["**/node_modules/**"],
|
|
35
|
+
onlyFiles: true,
|
|
36
|
+
absolute: true,
|
|
37
|
+
});
|
|
38
|
+
// Load each package.json and map by name
|
|
39
|
+
for (const pkgPath of packageJsonPaths) {
|
|
40
|
+
try {
|
|
41
|
+
const content = readFileSync(pkgPath, "utf-8");
|
|
42
|
+
const pkg = JSON.parse(content);
|
|
43
|
+
if (pkg.name) {
|
|
44
|
+
packageMap.set(pkg.name, pkg);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Ignore parse errors
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
workspacePackageCache.set(root, packageMap);
|
|
52
|
+
return packageMap;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Looks up a workspace package by name using the workspace configuration.
|
|
56
|
+
*/
|
|
57
|
+
function findWorkspacePackage(depName, root) {
|
|
58
|
+
const packageMap = buildWorkspacePackageMap(root);
|
|
59
|
+
return packageMap.get(depName);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Checks if a dependency version uses the workspace protocol.
|
|
63
|
+
*/
|
|
64
|
+
function isWorkspaceDependency(version) {
|
|
65
|
+
return version?.startsWith("workspace:") ?? false;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Policy that prevents publishable packages from depending on private workspace packages.
|
|
69
|
+
*
|
|
70
|
+
* A package is considered "publishable" if it does not have `"private": true` in its package.json.
|
|
71
|
+
* Such packages cannot have `workspace:` dependencies on packages that are marked as private,
|
|
72
|
+
* because those dependencies won't be resolvable when the package is published to npm.
|
|
73
|
+
*
|
|
74
|
+
* This policy uses the workspace configuration (pnpm-workspace.yaml or package.json workspaces field)
|
|
75
|
+
* to locate workspace packages, rather than hardcoding directory conventions.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* // In repopo.config.ts
|
|
80
|
+
* import { NoPrivateWorkspaceDependencies } from "repopo/policies";
|
|
81
|
+
*
|
|
82
|
+
* makePolicy(NoPrivateWorkspaceDependencies, {
|
|
83
|
+
* checkDevDependencies: false, // Only check production dependencies (default)
|
|
84
|
+
* });
|
|
85
|
+
*
|
|
86
|
+
* // Or check both dependencies and devDependencies
|
|
87
|
+
* makePolicy(NoPrivateWorkspaceDependencies, {
|
|
88
|
+
* checkDevDependencies: true,
|
|
89
|
+
* });
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export const NoPrivateWorkspaceDependencies = definePackagePolicy({
|
|
93
|
+
name: "NoPrivateWorkspaceDependencies",
|
|
94
|
+
description: "Prevents publishable packages from depending on private workspace packages that won't be available on npm.",
|
|
95
|
+
// biome-ignore lint/correctness/useYield: no yield needed
|
|
96
|
+
handler: function* (json, { file, root, config }) {
|
|
97
|
+
// Private packages can depend on anything - they won't be published
|
|
98
|
+
if (json.private === true) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
const checkDevDeps = config?.checkDevDependencies ?? false;
|
|
102
|
+
// Collect dependencies to check
|
|
103
|
+
const depsToCheck = {
|
|
104
|
+
...(json.dependencies ?? {}),
|
|
105
|
+
};
|
|
106
|
+
if (checkDevDeps) {
|
|
107
|
+
Object.assign(depsToCheck, json.devDependencies ?? {});
|
|
108
|
+
}
|
|
109
|
+
const privateWorkspaceDeps = [];
|
|
110
|
+
const unresolvableDeps = [];
|
|
111
|
+
for (const [depName, version] of Object.entries(depsToCheck)) {
|
|
112
|
+
if (!isWorkspaceDependency(version)) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const depPackageJson = findWorkspacePackage(depName, root);
|
|
116
|
+
if (depPackageJson === undefined) {
|
|
117
|
+
// Could not find the package - might be a configuration issue
|
|
118
|
+
// We'll warn but not fail, as this could be a valid setup we don't understand
|
|
119
|
+
unresolvableDeps.push(depName);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (depPackageJson.private === true) {
|
|
123
|
+
privateWorkspaceDeps.push(depName);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const errorMessages = [];
|
|
127
|
+
if (privateWorkspaceDeps.length > 0) {
|
|
128
|
+
errorMessages.push(`Publishable package has workspace dependencies on private packages that won't be available on npm:\n\t${privateWorkspaceDeps.join("\n\t")}`);
|
|
129
|
+
}
|
|
130
|
+
if (unresolvableDeps.length > 0) {
|
|
131
|
+
errorMessages.push(`Could not resolve workspace dependencies (verify they exist):\n\t${unresolvableDeps.join("\n\t")}`);
|
|
132
|
+
}
|
|
133
|
+
if (errorMessages.length > 0) {
|
|
134
|
+
const failResult = {
|
|
135
|
+
name: NoPrivateWorkspaceDependencies.name,
|
|
136
|
+
file,
|
|
137
|
+
autoFixable: false,
|
|
138
|
+
errorMessages,
|
|
139
|
+
};
|
|
140
|
+
return failResult;
|
|
141
|
+
}
|
|
142
|
+
return true;
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
//# sourceMappingURL=NoPrivateWorkspaceDependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoPrivateWorkspaceDependencies.js","sourceRoot":"","sources":["../../src/policies/NoPrivateWorkspaceDependencies.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync } from \"node:fs\";\n// Use default import + destructure for CJS/ESM interop\n// (resolve-workspace-root is a bundled CJS module)\nimport resolveWorkspaceRoot from \"resolve-workspace-root\";\n\nconst { getWorkspaceGlobs } = resolveWorkspaceRoot;\n\nimport { globSync } from \"tinyglobby\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\n/**\n * Configuration for the NoPrivateWorkspaceDependencies policy.\n */\nexport interface NoPrivateWorkspaceDependenciesSettings {\n\t/**\n\t * Whether to check devDependencies in addition to dependencies.\n\t * @default false\n\t */\n\tcheckDevDependencies?: boolean;\n}\n\n/**\n * Cache for workspace package lookups to avoid repeated filesystem operations.\n */\nconst workspacePackageCache = new Map<\n\tstring,\n\tMap<string, PackageJson | undefined>\n>();\n\n/**\n * Builds a map of package name to package.json for all packages in the workspace.\n * Uses the workspace configuration (pnpm-workspace.yaml or package.json workspaces) to find packages.\n */\nfunction buildWorkspacePackageMap(\n\troot: string,\n): Map<string, PackageJson | undefined> {\n\t// Check cache first\n\tconst cached = workspacePackageCache.get(root);\n\tif (cached !== undefined) {\n\t\treturn cached;\n\t}\n\n\tconst packageMap = new Map<string, PackageJson | undefined>();\n\n\t// Get workspace globs from pnpm-workspace.yaml or package.json\n\tconst workspaceGlobs = getWorkspaceGlobs(root);\n\tif (workspaceGlobs === null) {\n\t\t// Not a workspace - return empty map\n\t\tworkspacePackageCache.set(root, packageMap);\n\t\treturn packageMap;\n\t}\n\n\t// Find all package.json files matching the workspace globs\n\tconst packageGlobs = workspaceGlobs.map((g) => `${g}/package.json`);\n\tconst packageJsonPaths = globSync(packageGlobs, {\n\t\tcwd: root,\n\t\tignore: [\"**/node_modules/**\"],\n\t\tonlyFiles: true,\n\t\tabsolute: true,\n\t});\n\n\t// Load each package.json and map by name\n\tfor (const pkgPath of packageJsonPaths) {\n\t\ttry {\n\t\t\tconst content = readFileSync(pkgPath, \"utf-8\");\n\t\t\tconst pkg = JSON.parse(content) as PackageJson;\n\t\t\tif (pkg.name) {\n\t\t\t\tpackageMap.set(pkg.name, pkg);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore parse errors\n\t\t}\n\t}\n\n\tworkspacePackageCache.set(root, packageMap);\n\treturn packageMap;\n}\n\n/**\n * Looks up a workspace package by name using the workspace configuration.\n */\nfunction findWorkspacePackage(\n\tdepName: string,\n\troot: string,\n): PackageJson | undefined {\n\tconst packageMap = buildWorkspacePackageMap(root);\n\treturn packageMap.get(depName);\n}\n\n/**\n * Checks if a dependency version uses the workspace protocol.\n */\nfunction isWorkspaceDependency(version: string | undefined): boolean {\n\treturn version?.startsWith(\"workspace:\") ?? false;\n}\n\n/**\n * Policy that prevents publishable packages from depending on private workspace packages.\n *\n * A package is considered \"publishable\" if it does not have `\"private\": true` in its package.json.\n * Such packages cannot have `workspace:` dependencies on packages that are marked as private,\n * because those dependencies won't be resolvable when the package is published to npm.\n *\n * This policy uses the workspace configuration (pnpm-workspace.yaml or package.json workspaces field)\n * to locate workspace packages, rather than hardcoding directory conventions.\n *\n * @example\n * ```typescript\n * // In repopo.config.ts\n * import { NoPrivateWorkspaceDependencies } from \"repopo/policies\";\n *\n * makePolicy(NoPrivateWorkspaceDependencies, {\n * checkDevDependencies: false, // Only check production dependencies (default)\n * });\n *\n * // Or check both dependencies and devDependencies\n * makePolicy(NoPrivateWorkspaceDependencies, {\n * checkDevDependencies: true,\n * });\n * ```\n */\nexport const NoPrivateWorkspaceDependencies = definePackagePolicy<\n\tPackageJson,\n\tNoPrivateWorkspaceDependenciesSettings | undefined\n>({\n\tname: \"NoPrivateWorkspaceDependencies\",\n\tdescription:\n\t\t\"Prevents publishable packages from depending on private workspace packages that won't be available on npm.\",\n\t// biome-ignore lint/correctness/useYield: no yield needed\n\thandler: function* (json, { file, root, config }) {\n\t\t// Private packages can depend on anything - they won't be published\n\t\tif (json.private === true) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst checkDevDeps = config?.checkDevDependencies ?? false;\n\n\t\t// Collect dependencies to check\n\t\tconst depsToCheck: Record<string, string | undefined> = {\n\t\t\t...(json.dependencies ?? {}),\n\t\t};\n\n\t\tif (checkDevDeps) {\n\t\t\tObject.assign(depsToCheck, json.devDependencies ?? {});\n\t\t}\n\n\t\tconst privateWorkspaceDeps: string[] = [];\n\t\tconst unresolvableDeps: string[] = [];\n\n\t\tfor (const [depName, version] of Object.entries(depsToCheck)) {\n\t\t\tif (!isWorkspaceDependency(version)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst depPackageJson = findWorkspacePackage(depName, root);\n\n\t\t\tif (depPackageJson === undefined) {\n\t\t\t\t// Could not find the package - might be a configuration issue\n\t\t\t\t// We'll warn but not fail, as this could be a valid setup we don't understand\n\t\t\t\tunresolvableDeps.push(depName);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (depPackageJson.private === true) {\n\t\t\t\tprivateWorkspaceDeps.push(depName);\n\t\t\t}\n\t\t}\n\n\t\tconst errorMessages: string[] = [];\n\n\t\tif (privateWorkspaceDeps.length > 0) {\n\t\t\terrorMessages.push(\n\t\t\t\t`Publishable package has workspace dependencies on private packages that won't be available on npm:\\n\\t${privateWorkspaceDeps.join(\"\\n\\t\")}`,\n\t\t\t);\n\t\t}\n\n\t\tif (unresolvableDeps.length > 0) {\n\t\t\terrorMessages.push(\n\t\t\t\t`Could not resolve workspace dependencies (verify they exist):\\n\\t${unresolvableDeps.join(\"\\n\\t\")}`,\n\t\t\t);\n\t\t}\n\n\t\tif (errorMessages.length > 0) {\n\t\t\tconst failResult: PolicyFailure = {\n\t\t\t\tname: NoPrivateWorkspaceDependencies.name,\n\t\t\t\tfile,\n\t\t\t\tautoFixable: false,\n\t\t\t\terrorMessages,\n\t\t\t};\n\t\t\treturn failResult;\n\t\t}\n\n\t\treturn true;\n\t},\n});\n"]}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the PackageAllowedScopes policy.
|
|
3
|
+
*
|
|
4
|
+
* This policy ensures packages in a monorepo use only approved scopes or package names.
|
|
5
|
+
* This prevents accidental introduction of new scopes and ensures naming consistency.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const config: PackageAllowedScopesConfig = {
|
|
10
|
+
* // Only packages in these scopes are allowed
|
|
11
|
+
* allowedScopes: ["@myorg", "@internal", "@experimental"],
|
|
12
|
+
* // These specific unscoped packages are also allowed
|
|
13
|
+
* unscopedPackages: ["my-legacy-tool", "special-package"],
|
|
14
|
+
* };
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @alpha
|
|
18
|
+
*/
|
|
19
|
+
export interface PackageAllowedScopesConfig {
|
|
20
|
+
/**
|
|
21
|
+
* A list of npm scopes that are allowed for packages in this repository.
|
|
22
|
+
*
|
|
23
|
+
* Scopes should start with `@` (e.g., `@myorg`). A package like `@myorg/foo`
|
|
24
|
+
* would match the scope `@myorg`.
|
|
25
|
+
*
|
|
26
|
+
* @remarks
|
|
27
|
+
*
|
|
28
|
+
* If a package's scope is not in this list and the package is not in
|
|
29
|
+
* `unscopedPackages`, the policy will fail.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* allowedScopes: ["@myorg", "@myorg-tools", "@myorg-internal"]
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
allowedScopes?: string[];
|
|
37
|
+
/**
|
|
38
|
+
* A list of unscoped package names that are explicitly allowed.
|
|
39
|
+
*
|
|
40
|
+
* Use this for legacy packages or special cases where an unscoped name is needed.
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
*
|
|
44
|
+
* Unscoped packages not in this list will cause the policy to fail.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* unscopedPackages: ["my-legacy-tool", "special-package"]
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
unscopedPackages?: string[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A policy that ensures packages use only allowed scopes and package names.
|
|
55
|
+
*
|
|
56
|
+
* This policy prevents accidental introduction of new npm scopes or unscoped packages
|
|
57
|
+
* in a monorepo. It helps maintain naming consistency and prevents typos or mistakes
|
|
58
|
+
* when creating new packages.
|
|
59
|
+
*
|
|
60
|
+
* @remarks
|
|
61
|
+
*
|
|
62
|
+
* The policy checks packages in the following order:
|
|
63
|
+
*
|
|
64
|
+
* 1. If the package is scoped (starts with `@`), check if its scope is in `allowedScopes`
|
|
65
|
+
* 2. If the package is unscoped, check if it's in `unscopedPackages`
|
|
66
|
+
* 3. If neither check passes, the policy fails
|
|
67
|
+
*
|
|
68
|
+
* The "root" package (common in monorepos) is automatically skipped.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* import { makePolicy } from "repopo";
|
|
73
|
+
* import { PackageAllowedScopes } from "repopo/policies";
|
|
74
|
+
*
|
|
75
|
+
* const config: RepopoConfig = {
|
|
76
|
+
* policies: [
|
|
77
|
+
* makePolicy(PackageAllowedScopes, {
|
|
78
|
+
* allowedScopes: ["@myorg", "@internal"],
|
|
79
|
+
* unscopedPackages: ["legacy-package"],
|
|
80
|
+
* }),
|
|
81
|
+
* ],
|
|
82
|
+
* };
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* @alpha
|
|
86
|
+
*/
|
|
87
|
+
export declare const PackageAllowedScopes: import("../policy.js").PolicyDefinition<PackageAllowedScopesConfig | undefined>;
|
|
88
|
+
//# sourceMappingURL=PackageAllowedScopes.d.ts.map
|
|
@@ -0,0 +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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,oBAAoB,iFAuD/B,CAAC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { definePackagePolicy } from "../policyDefiners/definePackagePolicy.js";
|
|
2
|
+
import { getPackageScope, isScoped } from "../utils/packageName.js";
|
|
3
|
+
/**
|
|
4
|
+
* Check if a package's scope is in the allowed list.
|
|
5
|
+
*
|
|
6
|
+
* @param packageName - The package name to check
|
|
7
|
+
* @param allowedScopes - List of allowed scopes
|
|
8
|
+
* @returns `true` if the package's scope is allowed
|
|
9
|
+
*/
|
|
10
|
+
function isScopeAllowed(packageName, allowedScopes) {
|
|
11
|
+
if (allowedScopes === undefined || allowedScopes.length === 0) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
const scope = getPackageScope(packageName);
|
|
15
|
+
if (scope === undefined) {
|
|
16
|
+
// Package is unscoped, so scope check doesn't apply
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
return allowedScopes.includes(scope);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Check if an unscoped package name is in the allowed list.
|
|
23
|
+
*
|
|
24
|
+
* @param packageName - The package name to check
|
|
25
|
+
* @param unscopedPackages - List of allowed unscoped package names
|
|
26
|
+
* @returns `true` if the unscoped package is allowed
|
|
27
|
+
*/
|
|
28
|
+
function isUnscopedPackageAllowed(packageName, unscopedPackages) {
|
|
29
|
+
if (unscopedPackages === undefined || unscopedPackages.length === 0) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
// Only applies to unscoped packages
|
|
33
|
+
if (isScoped(packageName)) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return unscopedPackages.includes(packageName);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A policy that ensures packages use only allowed scopes and package names.
|
|
40
|
+
*
|
|
41
|
+
* This policy prevents accidental introduction of new npm scopes or unscoped packages
|
|
42
|
+
* in a monorepo. It helps maintain naming consistency and prevents typos or mistakes
|
|
43
|
+
* when creating new packages.
|
|
44
|
+
*
|
|
45
|
+
* @remarks
|
|
46
|
+
*
|
|
47
|
+
* The policy checks packages in the following order:
|
|
48
|
+
*
|
|
49
|
+
* 1. If the package is scoped (starts with `@`), check if its scope is in `allowedScopes`
|
|
50
|
+
* 2. If the package is unscoped, check if it's in `unscopedPackages`
|
|
51
|
+
* 3. If neither check passes, the policy fails
|
|
52
|
+
*
|
|
53
|
+
* The "root" package (common in monorepos) is automatically skipped.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* import { makePolicy } from "repopo";
|
|
58
|
+
* import { PackageAllowedScopes } from "repopo/policies";
|
|
59
|
+
*
|
|
60
|
+
* const config: RepopoConfig = {
|
|
61
|
+
* policies: [
|
|
62
|
+
* makePolicy(PackageAllowedScopes, {
|
|
63
|
+
* allowedScopes: ["@myorg", "@internal"],
|
|
64
|
+
* unscopedPackages: ["legacy-package"],
|
|
65
|
+
* }),
|
|
66
|
+
* ],
|
|
67
|
+
* };
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* @alpha
|
|
71
|
+
*/
|
|
72
|
+
export const PackageAllowedScopes = definePackagePolicy({
|
|
73
|
+
name: "PackageAllowedScopes",
|
|
74
|
+
description: "Ensures packages use only allowed npm scopes and package names.",
|
|
75
|
+
// biome-ignore lint/correctness/useYield: no yield needed
|
|
76
|
+
handler: function* (json, { file, config }) {
|
|
77
|
+
// If no config provided, skip validation
|
|
78
|
+
if (config === undefined) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
const packageName = json.name;
|
|
82
|
+
// Skip packages without a name
|
|
83
|
+
if (packageName === undefined) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
// Skip the root package (common in monorepos)
|
|
87
|
+
if (packageName === "root") {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
// Check if the package uses an allowed scope
|
|
91
|
+
if (isScopeAllowed(packageName, config.allowedScopes)) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
// Check if the package is an allowed unscoped package
|
|
95
|
+
if (isUnscopedPackageAllowed(packageName, config.unscopedPackages)) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
// Package doesn't match any allowed pattern - build error message
|
|
99
|
+
const scope = getPackageScope(packageName);
|
|
100
|
+
let errorMessage;
|
|
101
|
+
if (scope !== undefined) {
|
|
102
|
+
// Package has an unexpected scope
|
|
103
|
+
errorMessage = `Package "${packageName}" uses scope "${scope}" which is not in the allowed scopes list. Allowed scopes: ${config.allowedScopes?.join(", ") ?? "(none)"}`;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
// Package is unscoped but not in the allowed list
|
|
107
|
+
errorMessage = `Package "${packageName}" is an unscoped package that is not in the allowed unscoped packages list. Allowed unscoped packages: ${config.unscopedPackages?.join(", ") ?? "(none)"}`;
|
|
108
|
+
}
|
|
109
|
+
const failResult = {
|
|
110
|
+
name: PackageAllowedScopes.name,
|
|
111
|
+
file,
|
|
112
|
+
autoFixable: false, // Can't auto-fix package names
|
|
113
|
+
errorMessages: [errorMessage],
|
|
114
|
+
};
|
|
115
|
+
return failResult;
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
//# sourceMappingURL=PackageAllowedScopes.js.map
|
|
@@ -0,0 +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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAGrD;IACD,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EACV,iEAAiE;IAClE,0DAA0D;IAC1D,OAAO,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;QACzC,yCAAyC;QACzC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC;QACb,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC;QAE9B,+BAA+B;QAC/B,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC;QACb,CAAC;QAED,8CAA8C;QAC9C,IAAI,WAAW,KAAK,MAAM,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC;QACb,CAAC;QAED,6CAA6C;QAC7C,IAAI,cAAc,CAAC,WAAW,EAAE,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;YACvD,OAAO,IAAI,CAAC;QACb,CAAC;QAED,sDAAsD;QACtD,IAAI,wBAAwB,CAAC,WAAW,EAAE,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACpE,OAAO,IAAI,CAAC;QACb,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;QAED,MAAM,UAAU,GAAkB;YACjC,IAAI,EAAE,oBAAoB,CAAC,IAAI;YAC/B,IAAI;YACJ,WAAW,EAAE,KAAK,EAAE,+BAA+B;YACnD,aAAa,EAAE,CAAC,YAAY,CAAC;SAC7B,CAAC;QACF,OAAO,UAAU,CAAC;IACnB,CAAC;CACD,CAAC,CAAC","sourcesContent":["import type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure } 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 * @alpha\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 * allowedScopes: [\"@myorg\", \"@internal\"],\n * unscopedPackages: [\"legacy-package\"],\n * }),\n * ],\n * };\n * ```\n *\n * @alpha\n */\nexport const PackageAllowedScopes = definePackagePolicy<\n\tPackageJson,\n\tPackageAllowedScopesConfig | undefined\n>({\n\tname: \"PackageAllowedScopes\",\n\tdescription:\n\t\t\"Ensures packages use only allowed npm scopes and package names.\",\n\t// biome-ignore lint/correctness/useYield: no yield needed\n\thandler: function* (json, { file, config }) {\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// Skip packages without a name\n\t\tif (packageName === undefined) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Skip the root package (common in monorepos)\n\t\tif (packageName === \"root\") {\n\t\t\treturn true;\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 true;\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 true;\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\n\t\tconst failResult: PolicyFailure = {\n\t\t\tname: PackageAllowedScopes.name,\n\t\t\tfile,\n\t\t\tautoFixable: false, // Can't auto-fix package names\n\t\t\terrorMessages: [errorMessage],\n\t\t};\n\t\treturn failResult;\n\t},\n});\n"]}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the PackageEsmType policy.
|
|
3
|
+
*
|
|
4
|
+
* This policy ensures the `type` field in package.json is correctly set
|
|
5
|
+
* to indicate whether the package is an ESM or CommonJS module.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const config: PackageEsmTypeConfig = {
|
|
10
|
+
* // Require ESM type field for all packages
|
|
11
|
+
* requiredType: "module",
|
|
12
|
+
* // Or detect based on exports/main field
|
|
13
|
+
* detectFromExports: true,
|
|
14
|
+
* };
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @alpha
|
|
18
|
+
*/
|
|
19
|
+
export interface PackageEsmTypeConfig {
|
|
20
|
+
/**
|
|
21
|
+
* The required `type` field value for all packages.
|
|
22
|
+
*
|
|
23
|
+
* - `"module"` - All packages must be ESM (use import/export)
|
|
24
|
+
* - `"commonjs"` - All packages must be CommonJS (use require)
|
|
25
|
+
* - `undefined` - Use detection logic based on exports/main
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
*
|
|
29
|
+
* If set, this overrides automatic detection. Use `detectFromExports`
|
|
30
|
+
* for more flexible per-package type detection.
|
|
31
|
+
*/
|
|
32
|
+
requiredType?: "module" | "commonjs";
|
|
33
|
+
/**
|
|
34
|
+
* Detect the expected `type` field from the exports or main field.
|
|
35
|
+
*
|
|
36
|
+
* When enabled, the policy analyzes the package's entry points:
|
|
37
|
+
* - If exports use `.mjs` or have `import` conditions → `"module"`
|
|
38
|
+
* - If exports use `.cjs` or have `require` conditions → `"commonjs"`
|
|
39
|
+
* - If main field uses `.mjs` → `"module"`
|
|
40
|
+
* - If main field uses `.cjs` → `"commonjs"`
|
|
41
|
+
*
|
|
42
|
+
* @defaultValue false
|
|
43
|
+
*/
|
|
44
|
+
detectFromExports?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Package names or scopes to exclude from validation.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* excludePackages: ["@myorg/legacy-package", "old-cjs-lib"]
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
excludePackages?: string[];
|
|
54
|
+
/**
|
|
55
|
+
* Behavior when module type cannot be detected from exports/main.
|
|
56
|
+
*
|
|
57
|
+
* - `"skip"` (default) - Skip validation for packages where type cannot be detected
|
|
58
|
+
* - `"warn"` - Pass validation but include a warning in the output
|
|
59
|
+
* - `"fail"` - Fail validation when type cannot be detected
|
|
60
|
+
*
|
|
61
|
+
* This only applies when `detectFromExports` is true and no `requiredType` is set.
|
|
62
|
+
*
|
|
63
|
+
* @defaultValue "skip"
|
|
64
|
+
*/
|
|
65
|
+
onDetectionFailure?: "skip" | "warn" | "fail";
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A policy that ensures the `type` field in package.json is correctly set.
|
|
69
|
+
*
|
|
70
|
+
* This policy helps maintain consistency in how packages declare their module format,
|
|
71
|
+
* which is essential for proper module resolution in Node.js and bundlers.
|
|
72
|
+
*
|
|
73
|
+
* @remarks
|
|
74
|
+
*
|
|
75
|
+
* The policy can operate in two modes:
|
|
76
|
+
*
|
|
77
|
+
* 1. **Required Type**: Set `requiredType` to enforce a specific type for all packages
|
|
78
|
+
* 2. **Detection**: Set `detectFromExports: true` to detect the expected type from
|
|
79
|
+
* the package's exports or main field
|
|
80
|
+
*
|
|
81
|
+
* When `detectFromExports` is enabled, the policy looks for:
|
|
82
|
+
* - `.mjs` extensions or `"import"` conditions → expects `"module"`
|
|
83
|
+
* - `.cjs` extensions or `"require"` conditions → expects `"commonjs"`
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* import { makePolicy } from "repopo";
|
|
88
|
+
* import { PackageEsmType } from "repopo/policies";
|
|
89
|
+
*
|
|
90
|
+
* // Require all packages to be ESM
|
|
91
|
+
* makePolicy(PackageEsmType, { requiredType: "module" })
|
|
92
|
+
*
|
|
93
|
+
* // Or detect based on exports
|
|
94
|
+
* makePolicy(PackageEsmType, { detectFromExports: true })
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @alpha
|
|
98
|
+
*/
|
|
99
|
+
export declare const PackageEsmType: import("../policy.js").PolicyDefinition<PackageEsmTypeConfig | undefined>;
|
|
100
|
+
//# sourceMappingURL=PackageEsmType.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PackageEsmType.d.ts","sourceRoot":"","sources":["../../src/policies/PackageEsmType.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;;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;AAyPD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,cAAc,2EAgEzB,CAAC"}
|