repopo 0.5.0 → 0.7.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.
Files changed (96) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/README.md +3 -5
  3. package/THIRD-PARTY-LICENSES.txt +6 -6
  4. package/esm/baseCommand.d.ts.map +1 -1
  5. package/esm/baseCommand.js +7 -9
  6. package/esm/baseCommand.js.map +1 -1
  7. package/esm/commands/check.d.ts +17 -6
  8. package/esm/commands/check.d.ts.map +1 -1
  9. package/esm/commands/check.js +162 -110
  10. package/esm/commands/check.js.map +1 -1
  11. package/esm/commands/list.d.ts.map +1 -1
  12. package/esm/commands/list.js +0 -1
  13. package/esm/commands/list.js.map +1 -1
  14. package/esm/config.d.ts +4 -15
  15. package/esm/config.d.ts.map +1 -1
  16. package/esm/config.js +3 -2
  17. package/esm/config.js.map +1 -1
  18. package/esm/context.d.ts +3 -3
  19. package/esm/context.d.ts.map +1 -1
  20. package/esm/context.js.map +1 -1
  21. package/esm/generators.d.ts +21 -0
  22. package/esm/generators.d.ts.map +1 -0
  23. package/esm/generators.js +2 -0
  24. package/esm/generators.js.map +1 -0
  25. package/esm/index.d.ts +5 -11
  26. package/esm/index.d.ts.map +1 -1
  27. package/esm/index.js +3 -9
  28. package/esm/index.js.map +1 -1
  29. package/esm/makePolicy.d.ts +9 -0
  30. package/esm/makePolicy.d.ts.map +1 -0
  31. package/esm/makePolicy.js +28 -0
  32. package/esm/makePolicy.js.map +1 -0
  33. package/esm/policies/HtmlFileHeaders.d.ts +2 -2
  34. package/esm/policies/HtmlFileHeaders.d.ts.map +1 -1
  35. package/esm/policies/HtmlFileHeaders.js +2 -2
  36. package/esm/policies/HtmlFileHeaders.js.map +1 -1
  37. package/esm/policies/JsTsFileHeaders.d.ts +2 -2
  38. package/esm/policies/JsTsFileHeaders.d.ts.map +1 -1
  39. package/esm/policies/JsTsFileHeaders.js +2 -2
  40. package/esm/policies/JsTsFileHeaders.js.map +1 -1
  41. package/esm/policies/LicenseFileExists.d.ts +20 -0
  42. package/esm/policies/LicenseFileExists.d.ts.map +1 -0
  43. package/esm/policies/LicenseFileExists.js +40 -0
  44. package/esm/policies/LicenseFileExists.js.map +1 -0
  45. package/esm/policies/NoJsFileExtensions.d.ts +2 -2
  46. package/esm/policies/NoJsFileExtensions.d.ts.map +1 -1
  47. package/esm/policies/NoJsFileExtensions.js +11 -15
  48. package/esm/policies/NoJsFileExtensions.js.map +1 -1
  49. package/esm/policies/NoLargeBinaryFiles.d.ts +30 -0
  50. package/esm/policies/NoLargeBinaryFiles.d.ts.map +1 -0
  51. package/esm/policies/NoLargeBinaryFiles.js +118 -0
  52. package/esm/policies/NoLargeBinaryFiles.js.map +1 -0
  53. package/esm/policies/PackageJsonProperties.d.ts +1 -1
  54. package/esm/policies/PackageJsonProperties.d.ts.map +1 -1
  55. package/esm/policies/PackageJsonProperties.js +3 -3
  56. package/esm/policies/PackageJsonProperties.js.map +1 -1
  57. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts +1 -1
  58. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts.map +1 -1
  59. package/esm/policies/PackageJsonRepoDirectoryProperty.js +24 -25
  60. package/esm/policies/PackageJsonRepoDirectoryProperty.js.map +1 -1
  61. package/esm/policies/PackageJsonSorted.d.ts +1 -1
  62. package/esm/policies/PackageJsonSorted.d.ts.map +1 -1
  63. package/esm/policies/PackageJsonSorted.js +3 -2
  64. package/esm/policies/PackageJsonSorted.js.map +1 -1
  65. package/esm/policies/PackageScripts.d.ts +25 -2
  66. package/esm/policies/PackageScripts.d.ts.map +1 -1
  67. package/esm/policies/PackageScripts.js +47 -10
  68. package/esm/policies/PackageScripts.js.map +1 -1
  69. package/esm/policies/RequiredGitignorePatterns.d.ts +24 -0
  70. package/esm/policies/RequiredGitignorePatterns.d.ts.map +1 -0
  71. package/esm/policies/RequiredGitignorePatterns.js +166 -0
  72. package/esm/policies/RequiredGitignorePatterns.js.map +1 -0
  73. package/esm/policies.d.ts +8 -3
  74. package/esm/policies.d.ts.map +1 -1
  75. package/esm/policies.js +8 -3
  76. package/esm/policies.js.map +1 -1
  77. package/esm/policy.d.ts +40 -13
  78. package/esm/policy.d.ts.map +1 -1
  79. package/esm/policy.js +18 -7
  80. package/esm/policy.js.map +1 -1
  81. package/esm/{policyGenerators/generateFileHeaderPolicy.d.ts → policyDefiners/defineFileHeaderPolicy.d.ts} +4 -4
  82. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts.map +1 -0
  83. package/esm/{policyGenerators/generateFileHeaderPolicy.js → policyDefiners/defineFileHeaderPolicy.js} +3 -3
  84. package/esm/policyDefiners/defineFileHeaderPolicy.js.map +1 -0
  85. package/esm/policyDefiners/definePackagePolicy.d.ts +15 -0
  86. package/esm/policyDefiners/definePackagePolicy.d.ts.map +1 -0
  87. package/esm/{policyGenerators/generatePackagePolicy.js → policyDefiners/definePackagePolicy.js} +2 -2
  88. package/esm/policyDefiners/definePackagePolicy.js.map +1 -0
  89. package/esm/tsdoc-metadata.json +1 -1
  90. package/oclif.manifest.json +1 -1
  91. package/package.json +36 -31
  92. package/esm/policyGenerators/generateFileHeaderPolicy.d.ts.map +0 -1
  93. package/esm/policyGenerators/generateFileHeaderPolicy.js.map +0 -1
  94. package/esm/policyGenerators/generatePackagePolicy.d.ts +0 -9
  95. package/esm/policyGenerators/generatePackagePolicy.d.ts.map +0 -1
  96. package/esm/policyGenerators/generatePackagePolicy.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"NoJsFileExtensions.js","sourceRoot":"","sources":["../../src/policies/NoJsFileExtensions.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAe;IAC7C,IAAI,EAAE,oBAAoB;IAC1B,KAAK,EAAE,mBAAmB;IAC1B,uDAAuD;IACvD,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QAC3B,qCAAqC;QACrC,MAAM,MAAM,GAAkB;YAC7B,IAAI,EAAE,kBAAkB,CAAC,IAAI;YAC7B,IAAI;YACJ,WAAW,EAAE,KAAK;YAClB,YAAY,EACX,iIAAiI;SAClI,CAAC;QACF,OAAO,MAAM,CAAC;IACf,CAAC;CACD,CAAC","sourcesContent":["import type { PolicyFailure, RepoPolicy } from \"../policy.js\";\n\n/**\n * A repo policy that checks for JavaScript source files that just use the .js file extension. Such files may be\n * interpreted by node as either CommonJS or ESM based on the `type` field in the nearest package.json file. This\n * can create unexpected behavior for JS files; changing the package.json nearest to one will change how the JS\n * is processed by node. Using explicit file extensions reduces ambiguity and ensures a CJS file isn't suddenly treated\n * like an ESM file.\n *\n * @alpha\n */\nexport const NoJsFileExtensions: RepoPolicy = {\n\tname: \"NoJsFileExtensions\",\n\tmatch: /(^|\\/)[^/]+\\.js$/i,\n\t// biome-ignore lint/suspicious/useAwait: <explanation>\n\thandler: async ({ file }) => {\n\t\t// Any match is considered a failure.\n\t\tconst result: PolicyFailure = {\n\t\t\tname: NoJsFileExtensions.name,\n\t\t\tfile,\n\t\t\tautoFixable: false,\n\t\t\terrorMessage:\n\t\t\t\t\"JavaScript files should have a .cjs or .mjs file extension based on the module format of the file. Rename the file accordingly.\",\n\t\t};\n\t\treturn result;\n\t},\n};\n"]}
1
+ {"version":3,"file":"NoJsFileExtensions.js","sourceRoot":"","sources":["../../src/policies/NoJsFileExtensions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAGxD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAqB,oBAAoB,CACvE,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;IAClB,qCAAqC;IACrC,MAAM,MAAM,GAAkB;QAC7B,IAAI,EAAE,kBAAkB,CAAC,IAAI;QAC7B,IAAI;QACJ,WAAW,EAAE,KAAK;QAClB,YAAY,EACX,iIAAiI;KAClI,CAAC;IACF,OAAO,MAAM,CAAC;AACf,CAAC,CACD,CAAC","sourcesContent":["import { makePolicyDefinition } from \"../makePolicy.js\";\nimport type { PolicyDefinition, PolicyFailure } from \"../policy.js\";\n\n/**\n * A repo policy that checks for JavaScript source files that just use the .js file extension. Such files may be\n * interpreted by node as either CommonJS or ESM based on the `type` field in the nearest package.json file. This\n * can create unexpected behavior for JS files; changing the package.json nearest to one will change how the JS\n * is processed by node. Using explicit file extensions reduces ambiguity and ensures a CJS file isn't suddenly treated\n * like an ESM file.\n *\n * @alpha\n */\nexport const NoJsFileExtensions: PolicyDefinition = makePolicyDefinition(\n\t\"NoJsFileExtensions\",\n\t/(^|\\/)[^/]+\\.js$/i,\n\tasync ({ file }) => {\n\t\t// Any match is considered a failure.\n\t\tconst result: PolicyFailure = {\n\t\t\tname: NoJsFileExtensions.name,\n\t\t\tfile,\n\t\t\tautoFixable: false,\n\t\t\terrorMessage:\n\t\t\t\t\"JavaScript files should have a .cjs or .mjs file extension based on the module format of the file. Rename the file accordingly.\",\n\t\t};\n\t\treturn result;\n\t},\n);\n"]}
@@ -0,0 +1,30 @@
1
+ import type { PolicyDefinition } from "../policy.js";
2
+ /**
3
+ * Policy settings for the NoLargeBinaryFiles repo policy.
4
+ *
5
+ * @alpha
6
+ */
7
+ export interface NoLargeBinaryFilesSettings {
8
+ /**
9
+ * Maximum file size in bytes. Defaults to 10MB.
10
+ */
11
+ maxSizeBytes?: number;
12
+ /**
13
+ * File extensions to exclude from size checking.
14
+ * Useful for known large files that should be allowed.
15
+ */
16
+ excludeExtensions?: string[];
17
+ /**
18
+ * File patterns to exclude from size checking.
19
+ * Uses glob-style patterns.
20
+ */
21
+ excludePatterns?: string[];
22
+ }
23
+ /**
24
+ * A repo policy that prevents large binary files from being committed to the repository.
25
+ * Large files can bloat the repository and slow down clones. Consider using Git LFS for large assets.
26
+ *
27
+ * @alpha
28
+ */
29
+ export declare const NoLargeBinaryFiles: PolicyDefinition<NoLargeBinaryFilesSettings>;
30
+ //# sourceMappingURL=NoLargeBinaryFiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NoLargeBinaryFiles.d.ts","sourceRoot":"","sources":["../../src/policies/NoLargeBinaryFiles.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAiB,MAAM,cAAc,CAAC;AAEpE;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IAC1C;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE7B;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AA2FD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,gBAAgB,CAAC,0BAA0B,CA0C1E,CAAC"}
@@ -0,0 +1,118 @@
1
+ import { statSync } from "node:fs";
2
+ import path from "pathe";
3
+ import { makePolicyDefinition } from "../makePolicy.js";
4
+ /**
5
+ * Default maximum file size (10MB in bytes).
6
+ */
7
+ const DEFAULT_MAX_SIZE = 10 * 1024 * 1024;
8
+ /**
9
+ * Default file extensions that are typically safe to exclude from size limits.
10
+ */
11
+ const DEFAULT_EXCLUDE_EXTENSIONS = [
12
+ ".md",
13
+ ".txt",
14
+ ".json",
15
+ ".js",
16
+ ".ts",
17
+ ".jsx",
18
+ ".tsx",
19
+ ".css",
20
+ ".scss",
21
+ ".sass",
22
+ ".less",
23
+ ".html",
24
+ ".xml",
25
+ ".yml",
26
+ ".yaml",
27
+ ".toml",
28
+ ".ini",
29
+ ".conf",
30
+ ".config",
31
+ ];
32
+ /**
33
+ * Convert a glob pattern to a regex pattern by escaping special characters
34
+ * and converting * to .* for wildcard matching.
35
+ */
36
+ function globToRegex(pattern) {
37
+ // Escape all regex special characters except *
38
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
39
+ // Convert * to .* for wildcard matching
40
+ const regexPattern = escaped.replace(/\*/g, ".*");
41
+ return new RegExp(`^${regexPattern}$`);
42
+ }
43
+ /**
44
+ * Check if a file matches any of the exclude patterns.
45
+ */
46
+ function isExcluded(filePath, excludePatterns, excludeExtensions) {
47
+ const ext = path.extname(filePath).toLowerCase();
48
+ // Check extensions
49
+ if (excludeExtensions.includes(ext)) {
50
+ return true;
51
+ }
52
+ // Check patterns (simple glob-like matching)
53
+ for (const pattern of excludePatterns) {
54
+ if (pattern.includes("*")) {
55
+ const regex = globToRegex(pattern);
56
+ if (regex.test(filePath)) {
57
+ return true;
58
+ }
59
+ }
60
+ else if (filePath.includes(pattern)) {
61
+ return true;
62
+ }
63
+ }
64
+ return false;
65
+ }
66
+ /**
67
+ * Format bytes in a human-readable format.
68
+ */
69
+ function formatBytes(bytes) {
70
+ if (bytes === 0) {
71
+ return "0 B";
72
+ }
73
+ const k = 1024;
74
+ const sizes = ["B", "KB", "MB", "GB", "TB"];
75
+ const i = Math.min(Math.floor(Math.log(bytes) / Math.log(k)), sizes.length - 1);
76
+ const formatted = (bytes / k ** i).toFixed(1);
77
+ return `${formatted} ${sizes[i]}`;
78
+ }
79
+ /**
80
+ * A repo policy that prevents large binary files from being committed to the repository.
81
+ * Large files can bloat the repository and slow down clones. Consider using Git LFS for large assets.
82
+ *
83
+ * @alpha
84
+ */
85
+ export const NoLargeBinaryFiles = makePolicyDefinition("NoLargeBinaryFiles",
86
+ // Match all files
87
+ /.*/, async ({ file, root, config }) => {
88
+ const maxSizeBytes = config?.maxSizeBytes ?? DEFAULT_MAX_SIZE;
89
+ const excludeExtensions = config?.excludeExtensions ?? DEFAULT_EXCLUDE_EXTENSIONS;
90
+ const excludePatterns = config?.excludePatterns ?? [];
91
+ // Skip excluded files
92
+ if (isExcluded(file, excludePatterns, excludeExtensions)) {
93
+ return true;
94
+ }
95
+ try {
96
+ const filePath = path.resolve(root, file);
97
+ const stats = statSync(filePath);
98
+ // Skip directories
99
+ if (stats.isDirectory()) {
100
+ return true;
101
+ }
102
+ if (stats.size > maxSizeBytes) {
103
+ const result = {
104
+ name: NoLargeBinaryFiles.name,
105
+ file,
106
+ autoFixable: false,
107
+ errorMessage: `File is too large: ${formatBytes(stats.size)} (max: ${formatBytes(maxSizeBytes)}). Consider using Git LFS or removing the file.`,
108
+ };
109
+ return result;
110
+ }
111
+ return true;
112
+ }
113
+ catch (_error) {
114
+ // File doesn't exist or can't be accessed, skip it
115
+ return true;
116
+ }
117
+ });
118
+ //# sourceMappingURL=NoLargeBinaryFiles.js.map
@@ -0,0 +1 @@
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\t\"NoLargeBinaryFiles\",\n\t\t// Match all files\n\t\t/.*/,\n\t\tasync ({ 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\terrorMessage: `File is too large: ${formatBytes(stats.size)} (max: ${formatBytes(maxSizeBytes)}). Consider using Git LFS or removing the file.`,\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"]}
@@ -15,5 +15,5 @@ export interface PackageJsonPropertiesSettings {
15
15
  *
16
16
  * @alpha
17
17
  */
18
- export declare const PackageJsonProperties: import("../policy.js").RepoPolicy<PackageJsonPropertiesSettings | undefined>;
18
+ export declare const PackageJsonProperties: import("../policy.js").PolicyDefinition<PackageJsonPropertiesSettings | undefined>;
19
19
  //# sourceMappingURL=PackageJsonProperties.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PackageJsonProperties.d.ts","sourceRoot":"","sources":["../../src/policies/PackageJsonProperties.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAM7C;;;;GAIG;AACH,MAAM,WAAW,6BAA6B;IAC7C;;OAEG;IACH,QAAQ,EAAE,WAAW,CAAC;CACtB;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,8EA4ChC,CAAC"}
1
+ {"version":3,"file":"PackageJsonProperties.d.ts","sourceRoot":"","sources":["../../src/policies/PackageJsonProperties.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAM7C;;;;GAIG;AACH,MAAM,WAAW,6BAA6B;IAC7C;;OAEG;IACH,QAAQ,EAAE,WAAW,CAAC;CACtB;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,oFA4ChC,CAAC"}
@@ -1,14 +1,14 @@
1
1
  import { defu } from "defu";
2
2
  import jsonfile from "jsonfile";
3
3
  import diff from "microdiff";
4
- import { generatePackagePolicy } from "../policyGenerators/generatePackagePolicy.js";
4
+ import { definePackagePolicy } from "../policyDefiners/definePackagePolicy.js";
5
5
  const { writeFile: writeJson } = jsonfile;
6
6
  /**
7
7
  * A RepoPolicy that checks that package.json properties in packages match expected values.
8
8
  *
9
9
  * @alpha
10
10
  */
11
- export const PackageJsonProperties = generatePackagePolicy("PackageJsonProperties", async (json, { file, config, resolve }) => {
11
+ export const PackageJsonProperties = definePackagePolicy("PackageJsonProperties", async (json, { file, config, resolve }) => {
12
12
  if (config === undefined) {
13
13
  return true;
14
14
  }
@@ -18,7 +18,7 @@ export const PackageJsonProperties = generatePackagePolicy("PackageJsonPropertie
18
18
  file,
19
19
  autoFixable: true,
20
20
  };
21
- const merged = defu(json, verbatim);
21
+ const merged = defu(verbatim, json);
22
22
  const result = diff(merged, json);
23
23
  const messages = [];
24
24
  for (const diffResult of result) {
@@ -1 +1 @@
1
- {"version":3,"file":"PackageJsonProperties.js","sourceRoot":"","sources":["../../src/policies/PackageJsonProperties.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AAErF,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,QAAQ,CAAC;AAc1C;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,qBAAqB,CAGxD,uBAAuB,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;IACpE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACb,CAAC;IACD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAE5B,MAAM,UAAU,GAAkB;QACjC,IAAI,EAAE,qBAAqB,CAAC,IAAI;QAChC,IAAI;QACJ,WAAW,EAAE,IAAI;KACjB,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAElC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,UAAU,IAAI,MAAM,EAAE,CAAC;QACjC,QAAQ,CAAC,IAAI,CACZ,2CAA2C,UAAU,CAAC,IAAI,IAAI,CAC9D,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,IAAI,OAAO,EAAE,CAAC;YACb,MAAM,SAAS,GAAoB;gBAClC,GAAG,UAAU;gBACb,QAAQ,EAAE,KAAK;aACf,CAAC;YAEF,MAAM,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAEhD,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC;YAC1B,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,2EAA2E;QAC3E,UAAU,CAAC,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,OAAO,UAAU,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CAAC,CAAC","sourcesContent":["import { defu } from \"defu\";\nimport jsonfile from \"jsonfile\";\nimport diff from \"microdiff\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure, PolicyFixResult } from \"../policy.js\";\nimport { generatePackagePolicy } from \"../policyGenerators/generatePackagePolicy.js\";\n\nconst { writeFile: writeJson } = jsonfile;\n\n/**\n * Policy settings for the PackageJsonProperties repo policy.\n *\n * @alpha\n */\nexport interface PackageJsonPropertiesSettings {\n\t/**\n\t * Sets a package.json property to the value provided. The value will be used verbatim.\n\t */\n\tverbatim: PackageJson;\n}\n\n/**\n * A RepoPolicy that checks that package.json properties in packages match expected values.\n *\n * @alpha\n */\nexport const PackageJsonProperties = generatePackagePolicy<\n\tPackageJson,\n\tPackageJsonPropertiesSettings | undefined\n>(\"PackageJsonProperties\", async (json, { file, config, resolve }) => {\n\tif (config === undefined) {\n\t\treturn true;\n\t}\n\tconst { verbatim } = config;\n\n\tconst failResult: PolicyFailure = {\n\t\tname: PackageJsonProperties.name,\n\t\tfile,\n\t\tautoFixable: true,\n\t};\n\n\tconst merged = defu(json, verbatim);\n\tconst result = diff(merged, json);\n\n\tconst messages: string[] = [];\n\tfor (const diffResult of result) {\n\t\tmessages.push(\n\t\t\t`Incorrect package.json field value for '${diffResult.path}'.`,\n\t\t);\n\t}\n\n\tif (messages.length > 0) {\n\t\tif (resolve) {\n\t\t\tconst fixResult: PolicyFixResult = {\n\t\t\t\t...failResult,\n\t\t\t\tresolved: false,\n\t\t\t};\n\n\t\t\tawait writeJson(file, merged, { spaces: \"\\t\" });\n\n\t\t\tfixResult.resolved = true;\n\t\t\treturn fixResult;\n\t\t}\n\n\t\t// There were errors, and we're not resolving them, so return a fail result\n\t\tfailResult.errorMessage = messages.join(\"\\n\");\n\t\treturn failResult;\n\t}\n\n\treturn true;\n});\n"]}
1
+ {"version":3,"file":"PackageJsonProperties.js","sourceRoot":"","sources":["../../src/policies/PackageJsonProperties.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAE/E,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,QAAQ,CAAC;AAc1C;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,mBAAmB,CAGtD,uBAAuB,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;IACpE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACb,CAAC;IACD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAE5B,MAAM,UAAU,GAAkB;QACjC,IAAI,EAAE,qBAAqB,CAAC,IAAI;QAChC,IAAI;QACJ,WAAW,EAAE,IAAI;KACjB,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAElC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,UAAU,IAAI,MAAM,EAAE,CAAC;QACjC,QAAQ,CAAC,IAAI,CACZ,2CAA2C,UAAU,CAAC,IAAI,IAAI,CAC9D,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,IAAI,OAAO,EAAE,CAAC;YACb,MAAM,SAAS,GAAoB;gBAClC,GAAG,UAAU;gBACb,QAAQ,EAAE,KAAK;aACf,CAAC;YAEF,MAAM,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAEhD,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC;YAC1B,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,2EAA2E;QAC3E,UAAU,CAAC,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,OAAO,UAAU,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CAAC,CAAC","sourcesContent":["import { defu } from \"defu\";\nimport jsonfile from \"jsonfile\";\nimport diff from \"microdiff\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure, PolicyFixResult } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\nconst { writeFile: writeJson } = jsonfile;\n\n/**\n * Policy settings for the PackageJsonProperties repo policy.\n *\n * @alpha\n */\nexport interface PackageJsonPropertiesSettings {\n\t/**\n\t * Sets a package.json property to the value provided. The value will be used verbatim.\n\t */\n\tverbatim: PackageJson;\n}\n\n/**\n * A RepoPolicy that checks that package.json properties in packages match expected values.\n *\n * @alpha\n */\nexport const PackageJsonProperties = definePackagePolicy<\n\tPackageJson,\n\tPackageJsonPropertiesSettings | undefined\n>(\"PackageJsonProperties\", async (json, { file, config, resolve }) => {\n\tif (config === undefined) {\n\t\treturn true;\n\t}\n\tconst { verbatim } = config;\n\n\tconst failResult: PolicyFailure = {\n\t\tname: PackageJsonProperties.name,\n\t\tfile,\n\t\tautoFixable: true,\n\t};\n\n\tconst merged = defu(verbatim, json);\n\tconst result = diff(merged, json);\n\n\tconst messages: string[] = [];\n\tfor (const diffResult of result) {\n\t\tmessages.push(\n\t\t\t`Incorrect package.json field value for '${diffResult.path}'.`,\n\t\t);\n\t}\n\n\tif (messages.length > 0) {\n\t\tif (resolve) {\n\t\t\tconst fixResult: PolicyFixResult = {\n\t\t\t\t...failResult,\n\t\t\t\tresolved: false,\n\t\t\t};\n\n\t\t\tawait writeJson(file, merged, { spaces: \"\\t\" });\n\n\t\t\tfixResult.resolved = true;\n\t\t\treturn fixResult;\n\t\t}\n\n\t\t// There were errors, and we're not resolving them, so return a fail result\n\t\tfailResult.errorMessage = messages.join(\"\\n\");\n\t\treturn failResult;\n\t}\n\n\treturn true;\n});\n"]}
@@ -4,5 +4,5 @@
4
4
  *
5
5
  * @alpha
6
6
  */
7
- export declare const PackageJsonRepoDirectoryProperty: import("../policy.js").RepoPolicy<undefined>;
7
+ export declare const PackageJsonRepoDirectoryProperty: import("../policy.js").PolicyDefinition<undefined>;
8
8
  //# sourceMappingURL=PackageJsonRepoDirectoryProperty.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PackageJsonRepoDirectoryProperty.d.ts","sourceRoot":"","sources":["../../src/policies/PackageJsonRepoDirectoryProperty.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,8CA+C3C,CAAC"}
1
+ {"version":3,"file":"PackageJsonRepoDirectoryProperty.d.ts","sourceRoot":"","sources":["../../src/policies/PackageJsonRepoDirectoryProperty.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,oDAgD3C,CAAC"}
@@ -1,14 +1,14 @@
1
1
  import assert from "node:assert/strict";
2
2
  import { updatePackageJsonFile } from "@fluid-tools/build-infrastructure";
3
3
  import path from "pathe";
4
- import { generatePackagePolicy } from "../policyGenerators/generatePackagePolicy.js";
4
+ import { definePackagePolicy } from "../policyDefiners/definePackagePolicy.js";
5
5
  /**
6
6
  * A RepoPolicy that checks that the repository.directory property in package.json is set correctly. If the repository
7
7
  * field is a string instead of an object the package will be ignored.
8
8
  *
9
9
  * @alpha
10
10
  */
11
- export const PackageJsonRepoDirectoryProperty = generatePackagePolicy("PackageJsonRepoDirectoryProperty", async (json, { file, root, resolve }) => {
11
+ export const PackageJsonRepoDirectoryProperty = definePackagePolicy("PackageJsonRepoDirectoryProperty", async (json, { file, root, resolve }) => {
12
12
  const failResult = {
13
13
  name: PackageJsonRepoDirectoryProperty.name,
14
14
  file,
@@ -21,31 +21,30 @@ export const PackageJsonRepoDirectoryProperty = generatePackagePolicy("PackageJs
21
21
  const pkgDir = path.dirname(file);
22
22
  const maybeDir = path.relative(root, pkgDir);
23
23
  const relativePkgDir = maybeDir === "" ? undefined : maybeDir;
24
- if (typeof json.repository === "object") {
25
- if (json.repository.directory !== relativePkgDir) {
26
- if (resolve) {
27
- try {
28
- updatePackageJsonFile(file, (json) => {
29
- assert(typeof json.repository === "object");
30
- if (relativePkgDir === undefined) {
31
- // biome-ignore lint/performance/noDelete: <explanation>
32
- delete json.repository.directory;
33
- }
34
- else {
35
- json.repository.directory = relativePkgDir;
36
- }
37
- });
38
- fixResult.resolved = true;
39
- }
40
- catch (error) {
41
- fixResult.resolved = false;
42
- fixResult.errorMessage = `${error.message}\n${error.stack}`;
43
- }
44
- return fixResult;
24
+ if (typeof json.repository === "object" &&
25
+ json.repository.directory !== relativePkgDir) {
26
+ if (resolve) {
27
+ try {
28
+ // biome-ignore lint/nursery/noShadow: no need to use shadowed variable
29
+ updatePackageJsonFile(file, (json) => {
30
+ assert(typeof json.repository === "object");
31
+ if (relativePkgDir === undefined) {
32
+ delete json.repository.directory;
33
+ }
34
+ else {
35
+ json.repository.directory = relativePkgDir;
36
+ }
37
+ });
38
+ fixResult.resolved = true;
45
39
  }
46
- failResult.errorMessage = `repository.directory value is wrong. Expected '${relativePkgDir}', got '${json.repository.directory}'`;
47
- return failResult;
40
+ catch (error) {
41
+ fixResult.resolved = false;
42
+ fixResult.errorMessage = `${error.message}\n${error.stack}`;
43
+ }
44
+ return fixResult;
48
45
  }
46
+ failResult.errorMessage = `repository.directory value is wrong. Expected '${relativePkgDir}', got '${json.repository.directory}'`;
47
+ return failResult;
49
48
  }
50
49
  return true;
51
50
  });
@@ -1 +1 @@
1
- {"version":3,"file":"PackageJsonRepoDirectoryProperty.js","sourceRoot":"","sources":["../../src/policies/PackageJsonRepoDirectoryProperty.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,IAAI,MAAM,OAAO,CAAC;AAGzB,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AAErF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,qBAAqB,CAGnE,kCAAkC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;IAC7E,MAAM,UAAU,GAAkB;QACjC,IAAI,EAAE,gCAAgC,CAAC,IAAI;QAC3C,IAAI;QACJ,WAAW,EAAE,IAAI;KACjB,CAAC;IAEF,MAAM,SAAS,GAAoB;QAClC,GAAG,UAAU;QACb,QAAQ,EAAE,KAAK;KACf,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7C,MAAM,cAAc,GAAG,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;IAE9D,IAAI,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;QACzC,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,KAAK,cAAc,EAAE,CAAC;YAClD,IAAI,OAAO,EAAE,CAAC;gBACb,IAAI,CAAC;oBACJ,qBAAqB,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;wBACpC,MAAM,CAAC,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC;wBAC5C,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;4BAClC,wDAAwD;4BACxD,OAAO,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;wBAClC,CAAC;6BAAM,CAAC;4BACP,IAAI,CAAC,UAAU,CAAC,SAAS,GAAG,cAAc,CAAC;wBAC5C,CAAC;oBACF,CAAC,CAAC,CAAC;oBACH,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC;gBAC3B,CAAC;gBAAC,OAAO,KAAc,EAAE,CAAC;oBACzB,SAAS,CAAC,QAAQ,GAAG,KAAK,CAAC;oBAC3B,SAAS,CAAC,YAAY,GAAG,GAAI,KAAe,CAAC,OAAO,KAClD,KAAe,CAAC,KAClB,EAAE,CAAC;gBACJ,CAAC;gBACD,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,UAAU,CAAC,YAAY,GAAG,kDAAkD,cAAc,WAAW,IAAI,CAAC,UAAU,CAAC,SAAS,GAAG,CAAC;YAClI,OAAO,UAAU,CAAC;QACnB,CAAC;IACF,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CAAC,CAAC","sourcesContent":["import assert from \"node:assert/strict\";\nimport { updatePackageJsonFile } from \"@fluid-tools/build-infrastructure\";\nimport path from \"pathe\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure, PolicyFixResult } from \"../policy.js\";\nimport { generatePackagePolicy } from \"../policyGenerators/generatePackagePolicy.js\";\n\n/**\n * A RepoPolicy that checks that the repository.directory property in package.json is set correctly. If the repository\n * field is a string instead of an object the package will be ignored.\n *\n * @alpha\n */\nexport const PackageJsonRepoDirectoryProperty = generatePackagePolicy<\n\tPackageJson,\n\tundefined\n>(\"PackageJsonRepoDirectoryProperty\", async (json, { file, root, resolve }) => {\n\tconst failResult: PolicyFailure = {\n\t\tname: PackageJsonRepoDirectoryProperty.name,\n\t\tfile,\n\t\tautoFixable: true,\n\t};\n\n\tconst fixResult: PolicyFixResult = {\n\t\t...failResult,\n\t\tresolved: false,\n\t};\n\n\tconst pkgDir = path.dirname(file);\n\tconst maybeDir = path.relative(root, pkgDir);\n\tconst relativePkgDir = maybeDir === \"\" ? undefined : maybeDir;\n\n\tif (typeof json.repository === \"object\") {\n\t\tif (json.repository.directory !== relativePkgDir) {\n\t\t\tif (resolve) {\n\t\t\t\ttry {\n\t\t\t\t\tupdatePackageJsonFile(file, (json) => {\n\t\t\t\t\t\tassert(typeof json.repository === \"object\");\n\t\t\t\t\t\tif (relativePkgDir === undefined) {\n\t\t\t\t\t\t\t// biome-ignore lint/performance/noDelete: <explanation>\n\t\t\t\t\t\t\tdelete json.repository.directory;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tjson.repository.directory = relativePkgDir;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tfixResult.resolved = true;\n\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\tfixResult.resolved = false;\n\t\t\t\t\tfixResult.errorMessage = `${(error as Error).message}\\n${\n\t\t\t\t\t\t(error as Error).stack\n\t\t\t\t\t}`;\n\t\t\t\t}\n\t\t\t\treturn fixResult;\n\t\t\t}\n\t\t\tfailResult.errorMessage = `repository.directory value is wrong. Expected '${relativePkgDir}', got '${json.repository.directory}'`;\n\t\t\treturn failResult;\n\t\t}\n\t}\n\n\treturn true;\n});\n"]}
1
+ {"version":3,"file":"PackageJsonRepoDirectoryProperty.js","sourceRoot":"","sources":["../../src/policies/PackageJsonRepoDirectoryProperty.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,IAAI,MAAM,OAAO,CAAC;AAGzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,mBAAmB,CAGjE,kCAAkC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;IAC7E,MAAM,UAAU,GAAkB;QACjC,IAAI,EAAE,gCAAgC,CAAC,IAAI;QAC3C,IAAI;QACJ,WAAW,EAAE,IAAI;KACjB,CAAC;IAEF,MAAM,SAAS,GAAoB;QAClC,GAAG,UAAU;QACb,QAAQ,EAAE,KAAK;KACf,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7C,MAAM,cAAc,GAAG,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;IAE9D,IACC,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ;QACnC,IAAI,CAAC,UAAU,CAAC,SAAS,KAAK,cAAc,EAC3C,CAAC;QACF,IAAI,OAAO,EAAE,CAAC;YACb,IAAI,CAAC;gBACJ,uEAAuE;gBACvE,qBAAqB,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;oBACpC,MAAM,CAAC,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC;oBAC5C,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;wBAClC,OAAO,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;oBAClC,CAAC;yBAAM,CAAC;wBACP,IAAI,CAAC,UAAU,CAAC,SAAS,GAAG,cAAc,CAAC;oBAC5C,CAAC;gBACF,CAAC,CAAC,CAAC;gBACH,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC;YAC3B,CAAC;YAAC,OAAO,KAAc,EAAE,CAAC;gBACzB,SAAS,CAAC,QAAQ,GAAG,KAAK,CAAC;gBAC3B,SAAS,CAAC,YAAY,GAAG,GAAI,KAAe,CAAC,OAAO,KAClD,KAAe,CAAC,KAClB,EAAE,CAAC;YACJ,CAAC;YACD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,UAAU,CAAC,YAAY,GAAG,kDAAkD,cAAc,WAAW,IAAI,CAAC,UAAU,CAAC,SAAS,GAAG,CAAC;QAClI,OAAO,UAAU,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CAAC,CAAC","sourcesContent":["import assert from \"node:assert/strict\";\nimport { updatePackageJsonFile } from \"@fluid-tools/build-infrastructure\";\nimport path from \"pathe\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure, PolicyFixResult } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\n/**\n * A RepoPolicy that checks that the repository.directory property in package.json is set correctly. If the repository\n * field is a string instead of an object the package will be ignored.\n *\n * @alpha\n */\nexport const PackageJsonRepoDirectoryProperty = definePackagePolicy<\n\tPackageJson,\n\tundefined\n>(\"PackageJsonRepoDirectoryProperty\", async (json, { file, root, resolve }) => {\n\tconst failResult: PolicyFailure = {\n\t\tname: PackageJsonRepoDirectoryProperty.name,\n\t\tfile,\n\t\tautoFixable: true,\n\t};\n\n\tconst fixResult: PolicyFixResult = {\n\t\t...failResult,\n\t\tresolved: false,\n\t};\n\n\tconst pkgDir = path.dirname(file);\n\tconst maybeDir = path.relative(root, pkgDir);\n\tconst relativePkgDir = maybeDir === \"\" ? undefined : maybeDir;\n\n\tif (\n\t\ttypeof json.repository === \"object\" &&\n\t\tjson.repository.directory !== relativePkgDir\n\t) {\n\t\tif (resolve) {\n\t\t\ttry {\n\t\t\t\t// biome-ignore lint/nursery/noShadow: no need to use shadowed variable\n\t\t\t\tupdatePackageJsonFile(file, (json) => {\n\t\t\t\t\tassert(typeof json.repository === \"object\");\n\t\t\t\t\tif (relativePkgDir === undefined) {\n\t\t\t\t\t\tdelete json.repository.directory;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tjson.repository.directory = relativePkgDir;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tfixResult.resolved = true;\n\t\t\t} catch (error: unknown) {\n\t\t\t\tfixResult.resolved = false;\n\t\t\t\tfixResult.errorMessage = `${(error as Error).message}\\n${\n\t\t\t\t\t(error as Error).stack\n\t\t\t\t}`;\n\t\t\t}\n\t\t\treturn fixResult;\n\t\t}\n\t\tfailResult.errorMessage = `repository.directory value is wrong. Expected '${relativePkgDir}', got '${json.repository.directory}'`;\n\t\treturn failResult;\n\t}\n\n\treturn true;\n});\n"]}
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * @alpha
5
5
  */
6
- export declare const PackageJsonSorted: import("../policy.js").RepoPolicy<undefined>;
6
+ export declare const PackageJsonSorted: import("../policy.js").PolicyDefinition<undefined>;
7
7
  //# sourceMappingURL=PackageJsonSorted.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PackageJsonSorted.d.ts","sourceRoot":"","sources":["../../src/policies/PackageJsonSorted.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,8CAsC7B,CAAC"}
1
+ {"version":3,"file":"PackageJsonSorted.d.ts","sourceRoot":"","sources":["../../src/policies/PackageJsonSorted.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,oDAuC7B,CAAC"}
@@ -1,12 +1,12 @@
1
1
  import { updatePackageJsonFile } from "@tylerbu/cli-api";
2
2
  import { sortPackageJson } from "sort-package-json";
3
- import { generatePackagePolicy } from "../policyGenerators/generatePackagePolicy.js";
3
+ import { definePackagePolicy } from "../policyDefiners/definePackagePolicy.js";
4
4
  /**
5
5
  * A repo policy that checks if package.json files in the repo are sorted using sort-package-json.
6
6
  *
7
7
  * @alpha
8
8
  */
9
- export const PackageJsonSorted = generatePackagePolicy("PackageJsonSorted", async (json, { file, resolve }) => {
9
+ export const PackageJsonSorted = definePackagePolicy("PackageJsonSorted", async (json, { file, resolve }) => {
10
10
  const sortedJson = sortPackageJson(json);
11
11
  const isSorted = JSON.stringify(sortedJson) === JSON.stringify(json);
12
12
  if (isSorted) {
@@ -14,6 +14,7 @@ export const PackageJsonSorted = generatePackagePolicy("PackageJsonSorted", asyn
14
14
  }
15
15
  if (resolve) {
16
16
  try {
17
+ // biome-ignore lint/nursery/noShadow: no need to use the shadowed variable
17
18
  await updatePackageJsonFile(file, (json) => json, { sort: true });
18
19
  const result = {
19
20
  name: PackageJsonSorted.name,
@@ -1 +1 @@
1
- {"version":3,"file":"PackageJsonSorted.js","sourceRoot":"","sources":["../../src/policies/PackageJsonSorted.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AAErF;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,qBAAqB,CACrD,mBAAmB,EACnB,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;IACjC,MAAM,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAErE,IAAI,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACb,IAAI,CAAC;YACJ,MAAM,qBAAqB,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAClE,MAAM,MAAM,GAAoB;gBAC/B,IAAI,EAAE,iBAAiB,CAAC,IAAI;gBAC5B,IAAI;gBACJ,QAAQ,EAAE,IAAI;aACd,CAAC;YACF,OAAO,MAAM,CAAC;QACf,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACzB,MAAM,MAAM,GAAoB;gBAC/B,IAAI,EAAE,iBAAiB,CAAC,IAAI;gBAC5B,IAAI;gBACJ,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,IAAI;gBACjB,YAAY,EAAG,KAAe,CAAC,OAAO;aACtC,CAAC;YACF,OAAO,MAAM,CAAC;QACf,CAAC;IACF,CAAC;SAAM,CAAC;QACP,MAAM,MAAM,GAAkB;YAC7B,IAAI,EAAE,iBAAiB,CAAC,IAAI;YAC5B,IAAI;YACJ,WAAW,EAAE,IAAI;SACjB,CAAC;QACF,OAAO,MAAM,CAAC;IACf,CAAC;AACF,CAAC,CACD,CAAC","sourcesContent":["import { updatePackageJsonFile } from \"@tylerbu/cli-api\";\nimport { sortPackageJson } from \"sort-package-json\";\nimport type { PolicyFailure, PolicyFixResult } from \"../policy.js\";\nimport { generatePackagePolicy } from \"../policyGenerators/generatePackagePolicy.js\";\n\n/**\n * A repo policy that checks if package.json files in the repo are sorted using sort-package-json.\n *\n * @alpha\n */\nexport const PackageJsonSorted = generatePackagePolicy(\n\t\"PackageJsonSorted\",\n\tasync (json, { file, resolve }) => {\n\t\tconst sortedJson = sortPackageJson(json);\n\t\tconst isSorted = JSON.stringify(sortedJson) === JSON.stringify(json);\n\n\t\tif (isSorted) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (resolve) {\n\t\t\ttry {\n\t\t\t\tawait updatePackageJsonFile(file, (json) => json, { sort: true });\n\t\t\t\tconst result: PolicyFixResult = {\n\t\t\t\t\tname: PackageJsonSorted.name,\n\t\t\t\t\tfile,\n\t\t\t\t\tresolved: true,\n\t\t\t\t};\n\t\t\t\treturn result;\n\t\t\t} catch (error: unknown) {\n\t\t\t\tconst result: PolicyFixResult = {\n\t\t\t\t\tname: PackageJsonSorted.name,\n\t\t\t\t\tfile,\n\t\t\t\t\tresolved: false,\n\t\t\t\t\tautoFixable: true,\n\t\t\t\t\terrorMessage: (error as Error).message,\n\t\t\t\t};\n\t\t\t\treturn result;\n\t\t\t}\n\t\t} else {\n\t\t\tconst result: PolicyFailure = {\n\t\t\t\tname: PackageJsonSorted.name,\n\t\t\t\tfile,\n\t\t\t\tautoFixable: true,\n\t\t\t};\n\t\t\treturn result;\n\t\t}\n\t},\n);\n"]}
1
+ {"version":3,"file":"PackageJsonSorted.js","sourceRoot":"","sources":["../../src/policies/PackageJsonSorted.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAE/E;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,mBAAmB,CACnD,mBAAmB,EACnB,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;IACjC,MAAM,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAErE,IAAI,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACb,IAAI,CAAC;YACJ,2EAA2E;YAC3E,MAAM,qBAAqB,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAClE,MAAM,MAAM,GAAoB;gBAC/B,IAAI,EAAE,iBAAiB,CAAC,IAAI;gBAC5B,IAAI;gBACJ,QAAQ,EAAE,IAAI;aACd,CAAC;YACF,OAAO,MAAM,CAAC;QACf,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACzB,MAAM,MAAM,GAAoB;gBAC/B,IAAI,EAAE,iBAAiB,CAAC,IAAI;gBAC5B,IAAI;gBACJ,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,IAAI;gBACjB,YAAY,EAAG,KAAe,CAAC,OAAO;aACtC,CAAC;YACF,OAAO,MAAM,CAAC;QACf,CAAC;IACF,CAAC;SAAM,CAAC;QACP,MAAM,MAAM,GAAkB;YAC7B,IAAI,EAAE,iBAAiB,CAAC,IAAI;YAC5B,IAAI;YACJ,WAAW,EAAE,IAAI;SACjB,CAAC;QACF,OAAO,MAAM,CAAC;IACf,CAAC;AACF,CAAC,CACD,CAAC","sourcesContent":["import { updatePackageJsonFile } from \"@tylerbu/cli-api\";\nimport { sortPackageJson } from \"sort-package-json\";\nimport type { PolicyFailure, PolicyFixResult } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\n/**\n * A repo policy that checks if package.json files in the repo are sorted using sort-package-json.\n *\n * @alpha\n */\nexport const PackageJsonSorted = definePackagePolicy(\n\t\"PackageJsonSorted\",\n\tasync (json, { file, resolve }) => {\n\t\tconst sortedJson = sortPackageJson(json);\n\t\tconst isSorted = JSON.stringify(sortedJson) === JSON.stringify(json);\n\n\t\tif (isSorted) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (resolve) {\n\t\t\ttry {\n\t\t\t\t// biome-ignore lint/nursery/noShadow: no need to use the shadowed variable\n\t\t\t\tawait updatePackageJsonFile(file, (json) => json, { sort: true });\n\t\t\t\tconst result: PolicyFixResult = {\n\t\t\t\t\tname: PackageJsonSorted.name,\n\t\t\t\t\tfile,\n\t\t\t\t\tresolved: true,\n\t\t\t\t};\n\t\t\t\treturn result;\n\t\t\t} catch (error: unknown) {\n\t\t\t\tconst result: PolicyFixResult = {\n\t\t\t\t\tname: PackageJsonSorted.name,\n\t\t\t\t\tfile,\n\t\t\t\t\tresolved: false,\n\t\t\t\t\tautoFixable: true,\n\t\t\t\t\terrorMessage: (error as Error).message,\n\t\t\t\t};\n\t\t\t\treturn result;\n\t\t\t}\n\t\t} else {\n\t\t\tconst result: PolicyFailure = {\n\t\t\t\tname: PackageJsonSorted.name,\n\t\t\t\tfile,\n\t\t\t\tautoFixable: true,\n\t\t\t};\n\t\t\treturn result;\n\t\t}\n\t},\n);\n"]}
@@ -1,7 +1,30 @@
1
1
  /**
2
- * A RepoPolicy that checks that package.json properties in packages match expected values.
2
+ * Policy settings for the PackageScripts repo policy.
3
3
  *
4
4
  * @alpha
5
5
  */
6
- export declare const PackageScripts: import("../policy.js").RepoPolicy<undefined>;
6
+ export interface PackageScriptsSettings {
7
+ /**
8
+ * List of script names that must be present in package.json scripts.
9
+ */
10
+ must?: string[];
11
+ /**
12
+ * List of mutually exclusive script groups. Each group is an array of script names
13
+ * where at most one script from the group can be present.
14
+ *
15
+ * Packages can have zero scripts from the group (all optional), but cannot have
16
+ * multiple scripts from the same group.
17
+ *
18
+ * @example
19
+ * // Allow "test:unit" OR "test:vitest" OR neither, but not both
20
+ * mutuallyExclusive: [["test:unit", "test:vitest"]]
21
+ */
22
+ mutuallyExclusive?: string[][];
23
+ }
24
+ /**
25
+ * A RepoPolicy that validates package.json scripts based on configurable rules.
26
+ *
27
+ * @alpha
28
+ */
29
+ export declare const PackageScripts: import("../policy.js").PolicyDefinition<PackageScriptsSettings | undefined>;
7
30
  //# sourceMappingURL=PackageScripts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PackageScripts.d.ts","sourceRoot":"","sources":["../../src/policies/PackageScripts.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,eAAO,MAAM,cAAc,8CA+B1B,CAAC"}
1
+ {"version":3,"file":"PackageScripts.d.ts","sourceRoot":"","sources":["../../src/policies/PackageScripts.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACtC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAEhB;;;;;;;;;;OAUG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;CAC/B;AAgDD;;;;GAIG;AACH,eAAO,MAAM,cAAc,6EAoCzB,CAAC"}
@@ -1,23 +1,60 @@
1
- import { generatePackagePolicy } from "../policyGenerators/generatePackagePolicy.js";
2
- const expectedScripts = ["build", "clean"];
1
+ import { definePackagePolicy } from "../policyDefiners/definePackagePolicy.js";
3
2
  /**
4
- * A RepoPolicy that checks that package.json properties in packages match expected values.
3
+ * Validates required scripts and returns error messages for missing scripts.
4
+ */
5
+ function validateRequiredScripts(must, scripts) {
6
+ const missingScripts = [];
7
+ for (const scriptName of must) {
8
+ if (!(scripts && Object.hasOwn(scripts, scriptName))) {
9
+ missingScripts.push(scriptName);
10
+ }
11
+ }
12
+ if (missingScripts.length > 0) {
13
+ return [`Missing required scripts:\n\t${missingScripts.join("\n\t")}`];
14
+ }
15
+ return [];
16
+ }
17
+ /**
18
+ * Validates mutually exclusive script groups and returns error messages for violations.
19
+ */
20
+ function validateMutuallyExclusiveScripts(groups, scripts) {
21
+ const errors = [];
22
+ for (const group of groups) {
23
+ const presentScripts = group.filter((scriptName) => scripts && Object.hasOwn(scripts, scriptName));
24
+ // Only fail if MORE than one script from the group is present
25
+ if (presentScripts.length > 1) {
26
+ errors.push(`Scripts are mutually exclusive, but found ${presentScripts.length}: ${presentScripts.join(", ")}`);
27
+ }
28
+ }
29
+ return errors;
30
+ }
31
+ /**
32
+ * A RepoPolicy that validates package.json scripts based on configurable rules.
5
33
  *
6
34
  * @alpha
7
35
  */
8
- export const PackageScripts = generatePackagePolicy("PackageScripts", async (json, { file }) => {
36
+ export const PackageScripts = definePackagePolicy("PackageScripts", async (json, { file, config }) => {
9
37
  const failResult = {
10
38
  name: PackageScripts.name,
11
39
  file,
12
40
  autoFixable: false,
13
41
  };
14
- const hasScriptsField = Object.prototype.hasOwnProperty.call(json, "scripts");
15
- const missingScripts = [];
16
- if (hasScriptsField) {
17
- missingScripts.push(...expectedScripts.filter((script) => !Object.prototype.hasOwnProperty.call(json.scripts, script)));
42
+ if (config === undefined) {
43
+ return true;
18
44
  }
19
- if (missingScripts.length > 0) {
20
- failResult.errorMessage = `missing the following scripts: \n\t${missingScripts.join("\n\t")}`;
45
+ const hasScriptsField = Object.hasOwn(json, "scripts");
46
+ const scripts = hasScriptsField ? json.scripts : {};
47
+ const errorMessages = [];
48
+ // Validate required scripts
49
+ if (config.must && config.must.length > 0) {
50
+ errorMessages.push(...validateRequiredScripts(config.must, scripts));
51
+ }
52
+ // Validate mutually exclusive script groups
53
+ if (config.mutuallyExclusive && config.mutuallyExclusive.length > 0) {
54
+ errorMessages.push(...validateMutuallyExclusiveScripts(config.mutuallyExclusive, scripts));
55
+ }
56
+ if (errorMessages.length > 0) {
57
+ failResult.errorMessage = errorMessages.join("\n\n");
21
58
  return failResult;
22
59
  }
23
60
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"PackageScripts.js","sourceRoot":"","sources":["../../src/policies/PackageScripts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AAErF,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,OAAO,CAAU,CAAC;AAEpD;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,qBAAqB,CAClD,gBAAgB,EAChB,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;IACxB,MAAM,UAAU,GAAkB;QACjC,IAAI,EAAE,cAAc,CAAC,IAAI;QACzB,IAAI;QACJ,WAAW,EAAE,KAAK;KAClB,CAAC;IAEF,MAAM,eAAe,GAAG,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAC3D,IAAI,EACJ,SAAS,CACT,CAAC;IAEF,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,IAAI,eAAe,EAAE,CAAC;QACrB,cAAc,CAAC,IAAI,CAClB,GAAG,eAAe,CAAC,MAAM,CACxB,CAAC,MAAM,EAAE,EAAE,CACV,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAC5D,CACD,CAAC;IACH,CAAC;IAED,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,UAAU,CAAC,YAAY,GAAG,sCAAsC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9F,OAAO,UAAU,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CACD,CAAC","sourcesContent":["import type { PolicyFailure } from \"../policy.js\";\nimport { generatePackagePolicy } from \"../policyGenerators/generatePackagePolicy.js\";\n\nconst expectedScripts = [\"build\", \"clean\"] as const;\n\n/**\n * A RepoPolicy that checks that package.json properties in packages match expected values.\n *\n * @alpha\n */\nexport const PackageScripts = generatePackagePolicy(\n\t\"PackageScripts\",\n\tasync (json, { file }) => {\n\t\tconst failResult: PolicyFailure = {\n\t\t\tname: PackageScripts.name,\n\t\t\tfile,\n\t\t\tautoFixable: false,\n\t\t};\n\n\t\tconst hasScriptsField = Object.prototype.hasOwnProperty.call(\n\t\t\tjson,\n\t\t\t\"scripts\",\n\t\t);\n\n\t\tconst missingScripts: string[] = [];\n\t\tif (hasScriptsField) {\n\t\t\tmissingScripts.push(\n\t\t\t\t...expectedScripts.filter(\n\t\t\t\t\t(script) =>\n\t\t\t\t\t\t!Object.prototype.hasOwnProperty.call(json.scripts, script),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tif (missingScripts.length > 0) {\n\t\t\tfailResult.errorMessage = `missing the following scripts: \\n\\t${missingScripts.join(\"\\n\\t\")}`;\n\t\t\treturn failResult;\n\t\t}\n\n\t\treturn true;\n\t},\n);\n"]}
1
+ {"version":3,"file":"PackageScripts.js","sourceRoot":"","sources":["../../src/policies/PackageScripts.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AA2B/E;;GAEG;AACH,SAAS,uBAAuB,CAC/B,IAAc,EACd,OAA+B;IAE/B,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,KAAK,MAAM,UAAU,IAAI,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC;YACtD,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACjC,CAAC;IACF,CAAC;IAED,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,gCAAgC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,OAAO,EAAE,CAAC;AACX,CAAC;AAED;;GAEG;AACH,SAAS,gCAAgC,CACxC,MAAkB,EAClB,OAA+B;IAE/B,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAClC,CAAC,UAAU,EAAE,EAAE,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAC7D,CAAC;QAEF,8DAA8D;QAC9D,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/B,MAAM,CAAC,IAAI,CACV,6CAA6C,cAAc,CAAC,MAAM,KAAK,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAClG,CAAC;QACH,CAAC;IACF,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,mBAAmB,CAG/C,gBAAgB,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;IACpD,MAAM,UAAU,GAAkB;QACjC,IAAI,EAAE,cAAc,CAAC,IAAI;QACzB,IAAI;QACJ,WAAW,EAAE,KAAK;KAClB,CAAC;IAEF,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACpD,MAAM,aAAa,GAAa,EAAE,CAAC;IAEnC,4BAA4B;IAC5B,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,aAAa,CAAC,IAAI,CAAC,GAAG,uBAAuB,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,4CAA4C;IAC5C,IAAI,MAAM,CAAC,iBAAiB,IAAI,MAAM,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrE,aAAa,CAAC,IAAI,CACjB,GAAG,gCAAgC,CAAC,MAAM,CAAC,iBAAiB,EAAE,OAAO,CAAC,CACtE,CAAC;IACH,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,UAAU,CAAC,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrD,OAAO,UAAU,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CAAC,CAAC","sourcesContent":["import type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\n/**\n * Policy settings for the PackageScripts repo policy.\n *\n * @alpha\n */\nexport interface PackageScriptsSettings {\n\t/**\n\t * List of script names that must be present in package.json scripts.\n\t */\n\tmust?: string[];\n\n\t/**\n\t * List of mutually exclusive script groups. Each group is an array of script names\n\t * where at most one script from the group can be present.\n\t *\n\t * Packages can have zero scripts from the group (all optional), but cannot have\n\t * multiple scripts from the same group.\n\t *\n\t * @example\n\t * // Allow \"test:unit\" OR \"test:vitest\" OR neither, but not both\n\t * mutuallyExclusive: [[\"test:unit\", \"test:vitest\"]]\n\t */\n\tmutuallyExclusive?: string[][];\n}\n\n/**\n * Validates required scripts and returns error messages for missing scripts.\n */\nfunction validateRequiredScripts(\n\tmust: string[],\n\tscripts: PackageJson[\"scripts\"],\n): string[] {\n\tconst missingScripts: string[] = [];\n\tfor (const scriptName of must) {\n\t\tif (!(scripts && Object.hasOwn(scripts, scriptName))) {\n\t\t\tmissingScripts.push(scriptName);\n\t\t}\n\t}\n\n\tif (missingScripts.length > 0) {\n\t\treturn [`Missing required scripts:\\n\\t${missingScripts.join(\"\\n\\t\")}`];\n\t}\n\n\treturn [];\n}\n\n/**\n * Validates mutually exclusive script groups and returns error messages for violations.\n */\nfunction validateMutuallyExclusiveScripts(\n\tgroups: string[][],\n\tscripts: PackageJson[\"scripts\"],\n): string[] {\n\tconst errors: string[] = [];\n\n\tfor (const group of groups) {\n\t\tconst presentScripts = group.filter(\n\t\t\t(scriptName) => scripts && Object.hasOwn(scripts, scriptName),\n\t\t);\n\n\t\t// Only fail if MORE than one script from the group is present\n\t\tif (presentScripts.length > 1) {\n\t\t\terrors.push(\n\t\t\t\t`Scripts are mutually exclusive, but found ${presentScripts.length}: ${presentScripts.join(\", \")}`,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn errors;\n}\n\n/**\n * A RepoPolicy that validates package.json scripts based on configurable rules.\n *\n * @alpha\n */\nexport const PackageScripts = definePackagePolicy<\n\tPackageJson,\n\tPackageScriptsSettings | undefined\n>(\"PackageScripts\", async (json, { file, config }) => {\n\tconst failResult: PolicyFailure = {\n\t\tname: PackageScripts.name,\n\t\tfile,\n\t\tautoFixable: false,\n\t};\n\n\tif (config === undefined) {\n\t\treturn true;\n\t}\n\n\tconst hasScriptsField = Object.hasOwn(json, \"scripts\");\n\tconst scripts = hasScriptsField ? json.scripts : {};\n\tconst errorMessages: string[] = [];\n\n\t// Validate required scripts\n\tif (config.must && config.must.length > 0) {\n\t\terrorMessages.push(...validateRequiredScripts(config.must, scripts));\n\t}\n\n\t// Validate mutually exclusive script groups\n\tif (config.mutuallyExclusive && config.mutuallyExclusive.length > 0) {\n\t\terrorMessages.push(\n\t\t\t...validateMutuallyExclusiveScripts(config.mutuallyExclusive, scripts),\n\t\t);\n\t}\n\n\tif (errorMessages.length > 0) {\n\t\tfailResult.errorMessage = errorMessages.join(\"\\n\\n\");\n\t\treturn failResult;\n\t}\n\n\treturn true;\n});\n"]}
@@ -0,0 +1,24 @@
1
+ import type { PolicyDefinition } from "../policy.js";
2
+ /**
3
+ * Policy settings for the RequiredGitignorePatterns repo policy.
4
+ *
5
+ * @alpha
6
+ */
7
+ export interface RequiredGitignorePatternsSettings {
8
+ /**
9
+ * Array of patterns that must be present in .gitignore.
10
+ * Each pattern can be a string or an object with pattern and comment.
11
+ */
12
+ patterns: Array<string | {
13
+ pattern: string;
14
+ comment?: string;
15
+ }>;
16
+ }
17
+ /**
18
+ * A repo policy that ensures .gitignore contains required patterns to prevent
19
+ * committing sensitive files, dependencies, and build artifacts.
20
+ *
21
+ * @alpha
22
+ */
23
+ export declare const RequiredGitignorePatterns: PolicyDefinition<RequiredGitignorePatternsSettings>;
24
+ //# sourceMappingURL=RequiredGitignorePatterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequiredGitignorePatterns.d.ts","sourceRoot":"","sources":["../../src/policies/RequiredGitignorePatterns.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACX,gBAAgB,EAGhB,MAAM,cAAc,CAAC;AAEtB;;;;GAIG;AACH,MAAM,WAAW,iCAAiC;IACjD;;;OAGG;IACH,QAAQ,EAAE,KAAK,CAAC,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChE;AAmMD;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,EAAE,gBAAgB,CAAC,iCAAiC,CAcxF,CAAC"}