repopo 0.5.0 → 0.6.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 (81) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +3 -5
  3. package/THIRD-PARTY-LICENSES.txt +2 -2
  4. package/esm/baseCommand.d.ts.map +1 -1
  5. package/esm/baseCommand.js +7 -8
  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 +134 -94
  10. package/esm/commands/check.js.map +1 -1
  11. package/esm/config.d.ts +4 -15
  12. package/esm/config.d.ts.map +1 -1
  13. package/esm/config.js +3 -2
  14. package/esm/config.js.map +1 -1
  15. package/esm/context.d.ts +3 -3
  16. package/esm/context.d.ts.map +1 -1
  17. package/esm/context.js.map +1 -1
  18. package/esm/generators.d.ts +21 -0
  19. package/esm/generators.d.ts.map +1 -0
  20. package/esm/generators.js +2 -0
  21. package/esm/generators.js.map +1 -0
  22. package/esm/index.d.ts +5 -11
  23. package/esm/index.d.ts.map +1 -1
  24. package/esm/index.js +3 -9
  25. package/esm/index.js.map +1 -1
  26. package/esm/makePolicy.d.ts +9 -0
  27. package/esm/makePolicy.d.ts.map +1 -0
  28. package/esm/makePolicy.js +28 -0
  29. package/esm/makePolicy.js.map +1 -0
  30. package/esm/policies/HtmlFileHeaders.d.ts +2 -2
  31. package/esm/policies/HtmlFileHeaders.d.ts.map +1 -1
  32. package/esm/policies/HtmlFileHeaders.js +2 -2
  33. package/esm/policies/HtmlFileHeaders.js.map +1 -1
  34. package/esm/policies/JsTsFileHeaders.d.ts +2 -2
  35. package/esm/policies/JsTsFileHeaders.d.ts.map +1 -1
  36. package/esm/policies/JsTsFileHeaders.js +2 -2
  37. package/esm/policies/JsTsFileHeaders.js.map +1 -1
  38. package/esm/policies/NoJsFileExtensions.d.ts +2 -2
  39. package/esm/policies/NoJsFileExtensions.d.ts.map +1 -1
  40. package/esm/policies/NoJsFileExtensions.js +13 -15
  41. package/esm/policies/NoJsFileExtensions.js.map +1 -1
  42. package/esm/policies/PackageJsonProperties.d.ts +1 -1
  43. package/esm/policies/PackageJsonProperties.d.ts.map +1 -1
  44. package/esm/policies/PackageJsonProperties.js +3 -3
  45. package/esm/policies/PackageJsonProperties.js.map +1 -1
  46. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts +1 -1
  47. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts.map +1 -1
  48. package/esm/policies/PackageJsonRepoDirectoryProperty.js +2 -2
  49. package/esm/policies/PackageJsonRepoDirectoryProperty.js.map +1 -1
  50. package/esm/policies/PackageJsonSorted.d.ts +1 -1
  51. package/esm/policies/PackageJsonSorted.d.ts.map +1 -1
  52. package/esm/policies/PackageJsonSorted.js +2 -2
  53. package/esm/policies/PackageJsonSorted.js.map +1 -1
  54. package/esm/policies/PackageScripts.d.ts +1 -1
  55. package/esm/policies/PackageScripts.d.ts.map +1 -1
  56. package/esm/policies/PackageScripts.js +2 -2
  57. package/esm/policies/PackageScripts.js.map +1 -1
  58. package/esm/policies.d.ts +4 -3
  59. package/esm/policies.d.ts.map +1 -1
  60. package/esm/policies.js +4 -3
  61. package/esm/policies.js.map +1 -1
  62. package/esm/policy.d.ts +40 -13
  63. package/esm/policy.d.ts.map +1 -1
  64. package/esm/policy.js +18 -7
  65. package/esm/policy.js.map +1 -1
  66. package/esm/{policyGenerators/generateFileHeaderPolicy.d.ts → policyDefiners/defineFileHeaderPolicy.d.ts} +4 -4
  67. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts.map +1 -0
  68. package/esm/{policyGenerators/generateFileHeaderPolicy.js → policyDefiners/defineFileHeaderPolicy.js} +3 -3
  69. package/esm/policyDefiners/defineFileHeaderPolicy.js.map +1 -0
  70. package/esm/policyDefiners/definePackagePolicy.d.ts +15 -0
  71. package/esm/policyDefiners/definePackagePolicy.d.ts.map +1 -0
  72. package/esm/{policyGenerators/generatePackagePolicy.js → policyDefiners/definePackagePolicy.js} +2 -2
  73. package/esm/policyDefiners/definePackagePolicy.js.map +1 -0
  74. package/esm/tsdoc-metadata.json +1 -1
  75. package/oclif.manifest.json +1 -1
  76. package/package.json +10 -12
  77. package/esm/policyGenerators/generateFileHeaderPolicy.d.ts.map +0 -1
  78. package/esm/policyGenerators/generateFileHeaderPolicy.js.map +0 -1
  79. package/esm/policyGenerators/generatePackagePolicy.d.ts +0 -9
  80. package/esm/policyGenerators/generatePackagePolicy.d.ts.map +0 -1
  81. package/esm/policyGenerators/generatePackagePolicy.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # repopo
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Configuration changes _[`#224`](https://github.com/tylerbutler/tools-monorepo/pull/224) [`2b7db34`](https://github.com/tylerbutler/tools-monorepo/commit/2b7db343d74ab2e518ab2f232f47ea365ca784b8) [@tylerbutler](https://github.com/tylerbutler)_
8
+
9
+ The configuration for repopo has changed a lot in this release. The goal is to improve the typing of config and make it
10
+ easier to configure things in one place.
11
+
12
+ Policies are now declared as `PolicyDefinition`, and are then combined with a configuration (if the policy has
13
+ configuration) using `makePolicy` to form a `PolicyInstance`, which is the primary type used internally.
14
+
15
+ Generators now generate `PolicyDefinition`s, and can be used directly inline with `makePolicy`.
16
+
17
+ - Export policies from /policies entrypoint only _[`#224`](https://github.com/tylerbutler/tools-monorepo/pull/224) [`2b7db34`](https://github.com/tylerbutler/tools-monorepo/commit/2b7db343d74ab2e518ab2f232f47ea365ca784b8) [@tylerbutler](https://github.com/tylerbutler)_
18
+
19
+ Policies included with repopo are now exported from `repopo/policies`.
20
+
21
+ ### Patch Changes
22
+
23
+ - Update package metadata _[`#221`](https://github.com/tylerbutler/tools-monorepo/pull/221) [`9e5225a`](https://github.com/tylerbutler/tools-monorepo/commit/9e5225abfb67af1575af13dff60830d8da28eafd) [@tylerbutler](https://github.com/tylerbutler)_
24
+
25
+ <details><summary>Updated 2 dependencies</summary>
26
+
27
+ <small>
28
+
29
+ [`9e5225a`](https://github.com/tylerbutler/tools-monorepo/commit/9e5225abfb67af1575af13dff60830d8da28eafd)
30
+
31
+ </small>
32
+
33
+ - `@tylerbu/fundamentals@0.2.2`
34
+ - `@tylerbu/cli-api@0.7.2`
35
+
36
+ </details>
37
+
3
38
  ## 0.5.0
4
39
 
5
40
  ### Minor Changes
package/README.md CHANGED
@@ -24,14 +24,12 @@ By default, all files in the repo are checked. You can exclude files completely
24
24
  d `excludeFiles` setting. It should be an array of strings/regular expressions. Paths that match any of these
25
25
  expressions will be completely excluded from all policies.
26
26
 
27
- You can exclude files from individual policies as well. To do this, set the `excludePoliciesForFiles` setting. It should
28
- be an object with keys that match policy names. The value is an array of strings/regular expressions. Paths that match
29
- any of these expressions will be excluded from that policy only.
27
+ You can exclude files from individual policies as well by configuring the `excludeFiles` setting when calling
28
+ `makePolicy`.
30
29
 
31
30
  ## Configuring individual policies
32
31
 
33
- Individual policies can be configured using the `policySettings` setting. Use the policy name as the key, with the
34
- policy settings as the value.
32
+ Individual policies can be configured by passing configuration settings to a `PolicyDefinition` in `makePolicy`.
35
33
 
36
34
  # Included policies
37
35
 
@@ -27,7 +27,7 @@ OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHE
27
27
 
28
28
  The following npm package may be included in this product:
29
29
 
30
- - @rushstack/node-core-library@5.13.0
30
+ - @rushstack/node-core-library@5.13.1
31
31
 
32
32
  This package contains the following license:
33
33
 
@@ -124,7 +124,7 @@ MIT
124
124
 
125
125
  The following npm packages may be included in this product:
126
126
 
127
- - @oclif/core@4.2.10
127
+ - @oclif/core@4.3.0
128
128
  - @oclif/plugin-help@6.2.27
129
129
 
130
130
  These packages each contain the following license:
@@ -1 +1 @@
1
- {"version":3,"file":"baseCommand.d.ts","sourceRoot":"","sources":["../src/baseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,KAAK,SAAS,EAAa,MAAM,YAAY,CAAC;AACvD,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAyB,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAIhF;;GAEG;AACH,8BAAsB,iBAAiB,CACrC,CAAC,SAAS,OAAO,iBAAiB,GAAG;IACpC,IAAI,EAAE,OAAO,iBAAiB,CAAC,IAAI,CAAC;IACpC,KAAK,EAAE,OAAO,iBAAiB,CAAC,KAAK,CAAC;CACtC,CAEF,SAAQ,iBAAiB,CAAC,CAAC,EAAE,YAAY,CACzC,YAAW,kBAAkB,CAAC,oBAAoB,CAAC,EAAE,WAAW;IAEhE,UAAmB,aAAa,eAAuB;IAEvD,gBAAyB,KAAK;gCAXK,wBACjB,wCACD,wBAChB;MAUU;IAEX,OAAO,CAAC,IAAI,CAAwB;IACpC,IAAW,GAAG,IAAI,SAAS,CAK1B;IAEqB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA8B3C,OAAO,CAAC,QAAQ,CAAmC;IAGtC,UAAU,IAAI,OAAO,CAAC,oBAAoB,CAAC;CAMxD"}
1
+ {"version":3,"file":"baseCommand.d.ts","sourceRoot":"","sources":["../src/baseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,KAAK,SAAS,EAAa,MAAM,YAAY,CAAC;AACvD,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAyB,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAKhF;;GAEG;AACH,8BAAsB,iBAAiB,CACrC,CAAC,SAAS,OAAO,iBAAiB,GAAG;IACpC,IAAI,EAAE,OAAO,iBAAiB,CAAC,IAAI,CAAC;IACpC,KAAK,EAAE,OAAO,iBAAiB,CAAC,KAAK,CAAC;CACtC,CAEF,SAAQ,iBAAiB,CAAC,CAAC,EAAE,YAAY,CACzC,YAAW,kBAAkB,CAAC,oBAAoB,CAAC,EAAE,WAAW;IAEhE,UAAmB,aAAa,eAAuB;IAEvD,gBAAyB,KAAK;gCAb2D,wBAE5E,wCACD,wBAAwB;MAYzB;IAEX,OAAO,CAAC,IAAI,CAAwB;IACpC,IAAW,GAAG,IAAI,SAAS,CAK1B;IAEqB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB3C,OAAO,CAAC,QAAQ,CAAmC;IAGtC,UAAU,IAAI,OAAO,CAAC,oBAAoB,CAAC;CAMxD"}
@@ -2,6 +2,7 @@ import { CommandWithConfig, } from "@tylerbu/cli-api";
2
2
  import { findGitRootSync } from "@tylerbu/fundamentals/git";
3
3
  import { simpleGit } from "simple-git";
4
4
  import { DefaultPolicyConfig } from "./config.js";
5
+ import { makePolicy } from "./makePolicy.js";
5
6
  import { newPerfStats } from "./perf.js";
6
7
  import { DefaultPolicies } from "./policy.js";
7
8
  /**
@@ -22,19 +23,17 @@ export class BaseRepopoCommand extends CommandWithConfig {
22
23
  async init() {
23
24
  await super.init();
24
25
  const excludeFiles = this.commandConfig?.excludeFiles?.map((e) => new RegExp(e, "i")) ?? [];
25
- const excludePoliciesForFilesRaw = this.commandConfig?.excludePoliciesForFiles;
26
26
  const excludePoliciesForFiles = new Map();
27
- if (excludePoliciesForFilesRaw) {
28
- for (const [policyName, filters] of Object.entries(excludePoliciesForFilesRaw)) {
29
- const regexes = filters.map((e) => new RegExp(e, "i"));
30
- excludePoliciesForFiles.set(policyName, regexes);
31
- }
27
+ for (const policy of this.commandConfig?.policies ?? []) {
28
+ const regexes = policy.excludeFiles?.map((e) => new RegExp(e, "i")) ?? [];
29
+ excludePoliciesForFiles.set(policy.name, regexes);
32
30
  }
33
31
  const gitRoot = findGitRootSync();
34
32
  this._git = simpleGit({ baseDir: gitRoot });
35
33
  this._context = {
36
- excludeFiles,
37
- policies: this.commandConfig?.policies ?? DefaultPolicies,
34
+ excludeFromAll: excludeFiles,
35
+ policies: this.commandConfig?.policies ??
36
+ DefaultPolicies.map((p) => makePolicy(p)),
38
37
  excludePoliciesForFiles,
39
38
  gitRoot,
40
39
  perfStats: newPerfStats(),
@@ -1 +1 @@
1
- {"version":3,"file":"baseCommand.js","sourceRoot":"","sources":["../src/baseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,GAGjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAkB,SAAS,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAqB,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;GAEG;AACH,MAAM,OAAgB,iBAMrB,SAAQ,iBAAkC;IAGvB,aAAa,GAAG,mBAAmB,CAAC;IAEvD,MAAM,CAAmB,KAAK,GAAG;QAChC,GAAG,iBAAiB,CAAC,KAAK;KACjB,CAAC;IAEH,IAAI,CAAwB;IACpC,IAAW,GAAG;QACb,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IAEe,KAAK,CAAC,IAAI;QACzB,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QAEnB,MAAM,YAAY,GACjB,IAAI,CAAC,aAAa,EAAE,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAExE,MAAM,0BAA0B,GAC/B,IAAI,CAAC,aAAa,EAAE,uBAAuB,CAAC;QAE7C,MAAM,uBAAuB,GAA0B,IAAI,GAAG,EAAE,CAAC;QACjE,IAAI,0BAA0B,EAAE,CAAC;YAChC,KAAK,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CACjD,0BAA0B,CAC1B,EAAE,CAAC;gBACH,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;gBACvD,uBAAuB,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAClD,CAAC;QACF,CAAC;QAED,MAAM,OAAO,GAAG,eAAe,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ,GAAG;YACf,YAAY;YACZ,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,IAAI,eAAe;YACzD,uBAAuB;YACvB,OAAO;YACP,SAAS,EAAE,YAAY,EAAE;SACzB,CAAC;IACH,CAAC;IAEO,QAAQ,CAAmC;IAEnD,yEAAyE;IAClE,KAAK,CAAC,UAAU;QACtB,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC","sourcesContent":["import {\n\tCommandWithConfig,\n\ttype CommandWithContext,\n\ttype RequiresGit,\n} from \"@tylerbu/cli-api\";\nimport { findGitRootSync } from \"@tylerbu/fundamentals/git\";\nimport { type SimpleGit, simpleGit } from \"simple-git\";\nimport { DefaultPolicyConfig, type RepopoConfig } from \"./config.js\";\nimport type { ExcludedPolicyFileMap, RepopoCommandContext } from \"./context.js\";\nimport { newPerfStats } from \"./perf.js\";\nimport { DefaultPolicies } from \"./policy.js\";\n\n/**\n * This class is the base for all repopo commands. It contains common flags and config loading.\n */\nexport abstract class BaseRepopoCommand<\n\t\tT extends typeof BaseRepopoCommand & {\n\t\t\targs: typeof CommandWithConfig.args;\n\t\t\tflags: typeof CommandWithConfig.flags;\n\t\t},\n\t>\n\textends CommandWithConfig<T, RepopoConfig>\n\timplements CommandWithContext<RepopoCommandContext>, RequiresGit\n{\n\tprotected override defaultConfig = DefaultPolicyConfig;\n\n\tstatic override readonly flags = {\n\t\t...CommandWithConfig.flags,\n\t} as const;\n\n\tprivate _git: SimpleGit | undefined;\n\tpublic get git(): SimpleGit {\n\t\tif (this._git === undefined) {\n\t\t\tthrow new Error(\"git property is undefined\");\n\t\t}\n\t\treturn this._git;\n\t}\n\n\tpublic override async init(): Promise<void> {\n\t\tawait super.init();\n\n\t\tconst excludeFiles: RegExp[] =\n\t\t\tthis.commandConfig?.excludeFiles?.map((e) => new RegExp(e, \"i\")) ?? [];\n\n\t\tconst excludePoliciesForFilesRaw =\n\t\t\tthis.commandConfig?.excludePoliciesForFiles;\n\n\t\tconst excludePoliciesForFiles: ExcludedPolicyFileMap = new Map();\n\t\tif (excludePoliciesForFilesRaw) {\n\t\t\tfor (const [policyName, filters] of Object.entries(\n\t\t\t\texcludePoliciesForFilesRaw,\n\t\t\t)) {\n\t\t\t\tconst regexes = filters.map((e) => new RegExp(e, \"i\"));\n\t\t\t\texcludePoliciesForFiles.set(policyName, regexes);\n\t\t\t}\n\t\t}\n\n\t\tconst gitRoot = findGitRootSync();\n\t\tthis._git = simpleGit({ baseDir: gitRoot });\n\t\tthis._context = {\n\t\t\texcludeFiles,\n\t\t\tpolicies: this.commandConfig?.policies ?? DefaultPolicies,\n\t\t\texcludePoliciesForFiles,\n\t\t\tgitRoot,\n\t\t\tperfStats: newPerfStats(),\n\t\t};\n\t}\n\n\tprivate _context: RepopoCommandContext | undefined;\n\n\t// biome-ignore lint/suspicious/useAwait: interface defines this as async\n\tpublic async getContext(): Promise<RepopoCommandContext> {\n\t\tif (this._context === undefined) {\n\t\t\tthrow new Error(\"Context not initialized.\");\n\t\t}\n\t\treturn this._context;\n\t}\n}\n"]}
1
+ {"version":3,"file":"baseCommand.js","sourceRoot":"","sources":["../src/baseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,GAGjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAkB,SAAS,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAqB,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;GAEG;AACH,MAAM,OAAgB,iBAMrB,SAAQ,iBAAkC;IAGvB,aAAa,GAAG,mBAAmB,CAAC;IAEvD,MAAM,CAAmB,KAAK,GAAG;QAChC,GAAG,iBAAiB,CAAC,KAAK;KACjB,CAAC;IAEH,IAAI,CAAwB;IACpC,IAAW,GAAG;QACb,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IAEe,KAAK,CAAC,IAAI;QACzB,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QAEnB,MAAM,YAAY,GACjB,IAAI,CAAC,aAAa,EAAE,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAExE,MAAM,uBAAuB,GAA0B,IAAI,GAAG,EAAE,CAAC;QACjE,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,aAAa,EAAE,QAAQ,IAAI,EAAE,EAAE,CAAC;YACzD,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;YAC1E,uBAAuB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACnD,CAAC;QAED,MAAM,OAAO,GAAG,eAAe,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ,GAAG;YACf,cAAc,EAAE,YAAY;YAC5B,QAAQ,EACP,IAAI,CAAC,aAAa,EAAE,QAAQ;gBAC5B,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC1C,uBAAuB;YACvB,OAAO;YACP,SAAS,EAAE,YAAY,EAAE;SACzB,CAAC;IACH,CAAC;IAEO,QAAQ,CAAmC;IAEnD,yEAAyE;IAClE,KAAK,CAAC,UAAU;QACtB,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC","sourcesContent":["import {\n\tCommandWithConfig,\n\ttype CommandWithContext,\n\ttype RequiresGit,\n} from \"@tylerbu/cli-api\";\nimport { findGitRootSync } from \"@tylerbu/fundamentals/git\";\nimport { type SimpleGit, simpleGit } from \"simple-git\";\nimport { DefaultPolicyConfig, type RepopoConfig } from \"./config.js\";\nimport type { ExcludedPolicyFileMap, RepopoCommandContext } from \"./context.js\";\nimport { makePolicy } from \"./makePolicy.js\";\nimport { newPerfStats } from \"./perf.js\";\nimport { DefaultPolicies } from \"./policy.js\";\n\n/**\n * This class is the base for all repopo commands. It contains common flags and config loading.\n */\nexport abstract class BaseRepopoCommand<\n\t\tT extends typeof BaseRepopoCommand & {\n\t\t\targs: typeof CommandWithConfig.args;\n\t\t\tflags: typeof CommandWithConfig.flags;\n\t\t},\n\t>\n\textends CommandWithConfig<T, RepopoConfig>\n\timplements CommandWithContext<RepopoCommandContext>, RequiresGit\n{\n\tprotected override defaultConfig = DefaultPolicyConfig;\n\n\tstatic override readonly flags = {\n\t\t...CommandWithConfig.flags,\n\t} as const;\n\n\tprivate _git: SimpleGit | undefined;\n\tpublic get git(): SimpleGit {\n\t\tif (this._git === undefined) {\n\t\t\tthrow new Error(\"git property is undefined\");\n\t\t}\n\t\treturn this._git;\n\t}\n\n\tpublic override async init(): Promise<void> {\n\t\tawait super.init();\n\n\t\tconst excludeFiles: RegExp[] =\n\t\t\tthis.commandConfig?.excludeFiles?.map((e) => new RegExp(e, \"i\")) ?? [];\n\n\t\tconst excludePoliciesForFiles: ExcludedPolicyFileMap = new Map();\n\t\tfor (const policy of this.commandConfig?.policies ?? []) {\n\t\t\tconst regexes = policy.excludeFiles?.map((e) => new RegExp(e, \"i\")) ?? [];\n\t\t\texcludePoliciesForFiles.set(policy.name, regexes);\n\t\t}\n\n\t\tconst gitRoot = findGitRootSync();\n\t\tthis._git = simpleGit({ baseDir: gitRoot });\n\t\tthis._context = {\n\t\t\texcludeFromAll: excludeFiles,\n\t\t\tpolicies:\n\t\t\t\tthis.commandConfig?.policies ??\n\t\t\t\tDefaultPolicies.map((p) => makePolicy(p)),\n\t\t\texcludePoliciesForFiles,\n\t\t\tgitRoot,\n\t\t\tperfStats: newPerfStats(),\n\t\t};\n\t}\n\n\tprivate _context: RepopoCommandContext | undefined;\n\n\t// biome-ignore lint/suspicious/useAwait: interface defines this as async\n\tpublic async getContext(): Promise<RepopoCommandContext> {\n\t\tif (this._context === undefined) {\n\t\t\tthrow new Error(\"Context not initialized.\");\n\t\t}\n\t\treturn this._context;\n\t}\n}\n"]}
@@ -19,18 +19,29 @@ export declare class CheckPolicy<T extends typeof BaseRepopoCommand & {
19
19
  readonly stdin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
20
20
  };
21
21
  run(): Promise<void>;
22
- private executeAllPolicies;
23
22
  /**
24
- * Routes files to their handlers and resolvers by regex testing their full paths. If a file fails a policy that has a
25
- * resolver, the resolver will be invoked as well. Synchronizes the output, exit codes, and resolve
26
- * decision for all handlers.
23
+ * Executes all policies against the provided paths.
24
+ *
25
+ * @param pathsToCheck - All paths that should be checked. Paths should be relative to the repository root.
26
+ * @param context - The context.
27
27
  */
28
- private routeToHandlers;
29
- private runPolicyOnFile;
28
+ private checkAllFiles;
30
29
  /**
31
30
  * Given a string that represents a path to a file in the repo, determines if the file should be checked, and if so,
32
31
  * routes the file to the appropriate handlers.
32
+ *
33
+ * @param relPath - A git repo-relative path to a file.
33
34
  */
34
35
  private checkOrExcludeFile;
36
+ private routeToPolicies;
37
+ private runPolicyOnFile;
38
+ private isPolicyExcluded;
39
+ private executePolicyHandler;
40
+ private handlePolicyResult;
41
+ private handleFixResult;
42
+ private handleFailureResult;
43
+ private attemptResolution;
44
+ private logPolicyFailure;
45
+ private logMessages;
35
46
  }
36
47
  //# sourceMappingURL=check.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAKtD;;;;;;;;GAQG;AACH,qBAAa,WAAW,CACvB,CAAC,SAAS,OAAO,iBAAiB,GAAG;IACpC,IAAI,EAAE,OAAO,WAAW,CAAC,IAAI,CAAC;IAC9B,KAAK,EAAE,OAAO,WAAW,CAAC,KAAK,CAAC;CAChC,CACA,SAAQ,iBAAiB,CAAC,CAAC,CAAC;IAC7B,gBAAyB,OAAO,iEAC+B;IAE/D,gBAAyB,KAAK;gCAhBkB,wBAAuB,wCAAwC,wBAE/F;;;MA0BL;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;YAmC5B,kBAAkB;IAehC;;;;OAIG;YACW,eAAe;YAwBf,eAAe;IAkG7B;;;OAGG;YACW,kBAAkB;CAwBhC"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAYtD;;;;;;;;GAQG;AACH,qBAAa,WAAW,CACvB,CAAC,SAAS,OAAO,iBAAiB,GAAG;IACpC,IAAI,EAAE,OAAO,WAAW,CAAC,IAAI,CAAC;IAC9B,KAAK,EAAE,OAAO,WAAW,CAAC,KAAK,CAAC;CAChC,CACA,SAAQ,iBAAiB,CAAC,CAAC,CAAC;IAC7B,gBAAyB,OAAO,iEAC+B;IAE/D,gBAAyB,KAAK;gCAjBiB,wBAAwB,wCACvE,wBAAsB;;;MA4BX;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAwD1C;;;;;OAKG;YACW,aAAa;IAe3B;;;;;OAKG;YACW,kBAAkB;YAkBlB,eAAe;YA4Bf,eAAe;IAsC7B,OAAO,CAAC,gBAAgB;YAYV,oBAAoB;YAsBpB,kBAAkB;IAwBhC,OAAO,CAAC,eAAe;YAoBT,mBAAmB;YAyBnB,iBAAiB;IAyB/B,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,WAAW;CAOnB"}
@@ -1,11 +1,10 @@
1
1
  import { EOL as newline } from "node:os";
2
2
  import { Flags } from "@oclif/core";
3
3
  import { StringBuilder } from "@rushstack/node-core-library";
4
- import path from "pathe";
5
4
  import chalk from "picocolors";
6
5
  import { BaseRepopoCommand } from "../baseCommand.js";
7
6
  import { logStats, runWithPerf } from "../perf.js";
8
- import { isPolicyFixResult } from "../policy.js";
7
+ import { isPolicyFixResult, } from "../policy.js";
9
8
  /**
10
9
  * This tool enforces policies across the code base via a series of handler functions. The handler functions are
11
10
  * associated with a regular expression, and all files matching that expression are passed to the handler function.
@@ -44,133 +43,174 @@ export class CheckPolicy extends BaseRepopoCommand {
44
43
  if (this.flags.stdin) {
45
44
  const stdInput = await readStdin();
46
45
  if (stdInput !== undefined) {
47
- filePathsToCheck.push(...stdInput.split("\n"));
46
+ filePathsToCheck.push(...stdInput
47
+ .replace(
48
+ // normalize slashes in case they're windows paths
49
+ /\\/g, "/")
50
+ .split("\n"));
48
51
  }
49
52
  }
50
53
  else {
51
- const gitFiles = (await this.git.raw("ls-files", "-co", "--exclude-standard", "--full-name")) ?? "";
52
- filePathsToCheck.push(...gitFiles.split("\n"));
54
+ const gitFiles = (await this.git.raw("ls-files",
55
+ // include staged files and untracked files
56
+ "-co",
57
+ // exclude gitignored files and other standard ignore rules
58
+ "--exclude-standard",
59
+ // Outputs paths relative to the root of the repository, regardless of the current working directory.
60
+ "--full-name")) ?? "";
61
+ filePathsToCheck.push(...gitFiles
62
+ .replace(
63
+ // normalize slashes in case they're windows paths
64
+ /\\/g, "/")
65
+ .split("\n"));
53
66
  }
54
- await this.executeAllPolicies(filePathsToCheck);
67
+ const context = await this.getContext();
68
+ await this.checkAllFiles(filePathsToCheck, context);
55
69
  }
56
- async executeAllPolicies(pathsToCheck) {
57
- const commandContext = await this.getContext();
70
+ /**
71
+ * Executes all policies against the provided paths.
72
+ *
73
+ * @param pathsToCheck - All paths that should be checked. Paths should be relative to the repository root.
74
+ * @param context - The context.
75
+ */
76
+ async checkAllFiles(pathsToCheck, context) {
58
77
  try {
59
78
  for (const pathToCheck of pathsToCheck) {
60
- // eslint-disable-next-line no-await-in-loop
61
- await this.checkOrExcludeFile(pathToCheck, commandContext);
79
+ await this.checkOrExcludeFile(pathToCheck, context);
62
80
  }
63
81
  }
64
82
  finally {
65
83
  if (!this.flags.quiet) {
66
- logStats(commandContext.perfStats, this);
84
+ logStats(context.perfStats, this);
67
85
  }
68
86
  }
69
87
  }
70
88
  /**
71
- * Routes files to their handlers and resolvers by regex testing their full paths. If a file fails a policy that has a
72
- * resolver, the resolver will be invoked as well. Synchronizes the output, exit codes, and resolve
73
- * decision for all handlers.
89
+ * Given a string that represents a path to a file in the repo, determines if the file should be checked, and if so,
90
+ * routes the file to the appropriate handlers.
91
+ *
92
+ * @param relPath - A git repo-relative path to a file.
74
93
  */
75
- async routeToHandlers(file, commandContext) {
76
- const { policies, gitRoot } = commandContext;
77
- // Use the repo-relative path so that regexes that specify string start (^) will match repo paths.
78
- // Replace \ in result with / in case OS is Windows.
79
- const relPath = path.relative(gitRoot, file).replace(/\\/g, "/");
80
- const filteredPolicies = policies.filter((handler) => handler.match.test(relPath));
81
- const resultsP = [];
82
- for (const policy of filteredPolicies) {
83
- resultsP.push(this.runPolicyOnFile(relPath, policy));
84
- }
85
- await Promise.all(resultsP);
94
+ async checkOrExcludeFile(relPath, context) {
95
+ const { perfStats } = context;
96
+ perfStats.count++;
97
+ try {
98
+ await this.routeToPolicies(relPath, context);
99
+ }
100
+ catch (error) {
101
+ throw new Error(`Error routing ${relPath} to handler: ${error}\nStack:\n${error.stack}`);
102
+ }
103
+ perfStats.processed++;
86
104
  }
87
- // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: FIXME
88
- async runPolicyOnFile(relPath,
89
- // policies: RepoPolicy[],
90
- policy) {
91
- const context = await this.getContext();
105
+ async routeToPolicies(relPath, context) {
106
+ const { policies, excludeFromAll } = context;
107
+ // Check exclusions
108
+ if (excludeFromAll.some((regex) => regex.test(relPath))) {
109
+ this.verbose(`Excluded all handlers: ${relPath}`);
110
+ return; // Early return for excluded files
111
+ }
112
+ // Run all matching policies
113
+ const matchingPolicies = policies.filter((policy) => policy.match.test(relPath));
114
+ // for(const policy of matchingPolicies) {
115
+ // bars.addFile(policy.name,
116
+ // }
117
+ await Promise.all(matchingPolicies.map(async (policy) => {
118
+ return await this.runPolicyOnFile(relPath, policy, context);
119
+ }));
120
+ }
121
+ async runPolicyOnFile(relPath, policy, context) {
92
122
  const { excludePoliciesForFiles, perfStats, gitRoot } = context;
93
- // doing exclusion per handler
94
- const exclusions = excludePoliciesForFiles.get(policy.name);
95
- if (exclusions !== undefined &&
96
- !exclusions.every((regex) => !regex.test(relPath))) {
123
+ // Check if the policy is excluded for the file
124
+ if (this.isPolicyExcluded(relPath, policy, excludePoliciesForFiles)) {
97
125
  this.verbose(`Excluded from '${policy.name}' policy: ${relPath}`);
98
126
  return;
99
127
  }
100
- const result = await runWithPerf(policy.name, "handle", perfStats, async () => policy.handler({
101
- file: relPath,
102
- root: gitRoot,
103
- resolve: this.flags.fix,
104
- config: this.commandConfig?.perPolicyConfig?.[policy.name
105
- // biome-ignore lint/suspicious/noExplicitAny: FIXME
106
- ],
107
- }));
128
+ try {
129
+ // Execute the policy handler
130
+ const result = await this.executePolicyHandler(relPath, policy, perfStats, gitRoot);
131
+ // Handle the result of the policy execution
132
+ await this.handlePolicyResult(result, relPath, policy, perfStats, gitRoot);
133
+ }
134
+ catch (error) {
135
+ // Log and rethrow the error for higher-level handling
136
+ this.error(`Error executing policy '${policy.name}' for file '${relPath}': ${error}`);
137
+ }
138
+ }
139
+ isPolicyExcluded(relPath, policy, excludePoliciesForFiles) {
140
+ return (excludePoliciesForFiles
141
+ .get(policy.name)
142
+ ?.some((regex) => regex.test(relPath)) ?? false);
143
+ }
144
+ async executePolicyHandler(relPath, policy, perfStats, gitRoot) {
145
+ try {
146
+ return await runWithPerf(policy.name, "handle", perfStats, () => policy.handler({
147
+ file: relPath,
148
+ root: gitRoot,
149
+ resolve: this.flags.fix,
150
+ config: policy.config,
151
+ }));
152
+ }
153
+ catch (error) {
154
+ this.error(`Error in policy handler '${policy.name}' for file '${relPath}': ${error}`);
155
+ }
156
+ }
157
+ async handlePolicyResult(result, relPath, policy, perfStats, gitRoot) {
108
158
  if (result === true) {
109
159
  return;
110
160
  }
111
- const messages = new StringBuilder();
112
161
  if (isPolicyFixResult(result)) {
113
- if (result.resolved) {
114
- messages.append(`Resolved ${policy.name} policy failure for file: ${result.file}`);
115
- }
116
- else {
117
- messages.append(`Error when trying to fix ${policy.name} policy failure in ${result.file}`);
118
- process.exitCode = 1;
119
- }
162
+ this.handleFixResult(result, policy);
120
163
  }
121
164
  else {
122
- // result must be a PolicyFailureResult; check if there is a standalone resolver.
123
- const { resolver } = policy;
124
- if (this.flags.fix && resolver !== undefined) {
125
- // Resolve the failure
126
- messages.append(`${newline}attempting to resolve: ${relPath}`);
127
- const resolveResult = await runWithPerf(policy.name, "resolve", perfStats, async () => resolver({ file: relPath, root: gitRoot }));
128
- if (resolveResult.errorMessage !== undefined &&
129
- resolveResult.errorMessage !== "") {
130
- messages.append(newline + resolveResult.errorMessage);
131
- }
132
- if (!resolveResult.resolved) {
133
- process.exitCode = 1;
134
- }
135
- }
136
- else {
137
- // No resolver, or fix is false, so we're in the full failure case.
138
- const autoFixable = result.autoFixable
139
- ? chalk.green(" (autofixable)")
140
- : "";
141
- messages.append(`'${chalk.bold(policy.name)}' policy failure${autoFixable}: ${result.file}`);
142
- messages.append(result.errorMessage === undefined
143
- ? ""
144
- : `${newline}\t${result.errorMessage}`);
145
- process.exitCode = 1;
146
- }
165
+ await this.handleFailureResult(result, relPath, policy, perfStats, gitRoot);
147
166
  }
148
- if ((process.exitCode ?? 0) === 0) {
149
- this.info(messages.toString());
167
+ }
168
+ handleFixResult(result, policy) {
169
+ const messages = new StringBuilder();
170
+ if (result.resolved) {
171
+ messages.append(`Resolved ${policy.name} policy failure for file: ${result.file}`);
150
172
  }
151
173
  else {
152
- this.warning(messages.toString());
174
+ messages.append(`Error fixing ${policy.name} policy failure in ${result.file}`);
175
+ process.exitCode = 1;
153
176
  }
177
+ this.logMessages(messages);
154
178
  }
155
- /**
156
- * Given a string that represents a path to a file in the repo, determines if the file should be checked, and if so,
157
- * routes the file to the appropriate handlers.
158
- */
159
- async checkOrExcludeFile(inputPath, commandContext) {
160
- const { excludeFiles: exclusions, gitRoot, perfStats } = commandContext;
161
- const filePath = path.join(gitRoot, inputPath).trim().replace(/\\/g, "/");
162
- perfStats.count++;
163
- if (!exclusions.every((value) => !value.test(inputPath))) {
164
- this.verbose(`Excluded all handlers: ${inputPath}`);
165
- return;
179
+ async handleFailureResult(result, relPath, policy, perfStats, gitRoot) {
180
+ const messages = new StringBuilder();
181
+ if (this.flags.fix && policy.resolver) {
182
+ await this.attemptResolution(relPath, policy, policy.resolver, perfStats, gitRoot, messages);
166
183
  }
167
- try {
168
- await this.routeToHandlers(filePath, commandContext);
184
+ else {
185
+ this.logPolicyFailure(result, policy, messages);
169
186
  }
170
- catch (error) {
171
- throw new Error(`Error routing ${filePath} to handler: ${error}\nStack:\n${error.stack}`);
187
+ this.logMessages(messages);
188
+ }
189
+ async attemptResolution(relPath, policy, resolver, perfStats, gitRoot, messages) {
190
+ messages.append(`${newline}Attempting to resolve: ${relPath}`);
191
+ const resolveResult = await runWithPerf(policy.name, "resolve", perfStats, () => resolver({ file: relPath, root: gitRoot }));
192
+ if (!resolveResult.resolved) {
193
+ process.exitCode = 1;
194
+ }
195
+ if (resolveResult.errorMessage) {
196
+ messages.append(newline + resolveResult.errorMessage);
197
+ }
198
+ }
199
+ logPolicyFailure(result, policy, messages) {
200
+ const autoFixable = result.autoFixable ? chalk.green(" (autofixable)") : "";
201
+ messages.append(`'${chalk.bold(policy.name)}' policy failure${autoFixable}: ${result.file}`);
202
+ if (result.errorMessage) {
203
+ messages.append(`${newline}\t${result.errorMessage}`);
204
+ }
205
+ process.exitCode = 1;
206
+ }
207
+ logMessages(messages) {
208
+ if ((process.exitCode ?? 0) === 0) {
209
+ this.info(messages.toString());
210
+ }
211
+ else {
212
+ this.warning(messages.toString());
172
213
  }
173
- perfStats.processed++;
174
214
  }
175
215
  }
176
216
  async function readStdin() {
@@ -1 +1 @@
1
- {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"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","sourcesContent":["import { EOL as newline } from \"node:os\";\nimport { Flags } from \"@oclif/core\";\nimport { StringBuilder } from \"@rushstack/node-core-library\";\nimport path from \"pathe\";\nimport chalk from \"picocolors\";\n\nimport { BaseRepopoCommand } from \"../baseCommand.js\";\nimport type { RepopoCommandContext } from \"../context.js\";\nimport { logStats, runWithPerf } from \"../perf.js\";\nimport { type RepoPolicy, isPolicyFixResult } from \"../policy.js\";\n\n/**\n * This tool enforces policies across the code base via a series of handler functions. The handler functions are\n * associated with a regular expression, and all files matching that expression are passed to the handler function.\n *\n * By default, the list of files to check comes from `git ls-files. You can also pipe in file names from stdin. For\n * example:\n *\n * `git ls-files -co --exclude-standard --full-name | repopo check --stdin --verbose`\n */\nexport class CheckPolicy<\n\tT extends typeof BaseRepopoCommand & {\n\t\targs: typeof CheckPolicy.args;\n\t\tflags: typeof CheckPolicy.flags;\n\t},\n> extends BaseRepopoCommand<T> {\n\tstatic override readonly summary =\n\t\t\"Checks and applies policies to the files in the repository.\";\n\n\tstatic override readonly flags = {\n\t\tfix: Flags.boolean({\n\t\t\taliases: [\"resolve\"],\n\t\t\tdescription: \"Fix errors if possible.\",\n\t\t\trequired: false,\n\t\t\tchar: \"f\",\n\t\t}),\n\t\tstdin: Flags.boolean({\n\t\t\tdescription: \"Read list of files from stdin.\",\n\t\t\trequired: false,\n\t\t}),\n\t\t...BaseRepopoCommand.flags,\n\t} as const;\n\n\tpublic override async run(): Promise<void> {\n\t\tif (this.flags.fix) {\n\t\t\tthis.info(\"Resolving errors if possible.\");\n\t\t}\n\n\t\tconst config = this.commandConfig;\n\t\tconst policies = config?.policies ?? [];\n\t\tthis.verbose(`${policies.length} policies loaded.`);\n\t\tfor (const h of policies) {\n\t\t\tthis.verbose(h.name);\n\t\t}\n\n\t\tconst filePathsToCheck: string[] = [];\n\n\t\tif (this.flags.stdin) {\n\t\t\tconst stdInput = await readStdin();\n\n\t\t\tif (stdInput !== undefined) {\n\t\t\t\tfilePathsToCheck.push(...stdInput.split(\"\\n\"));\n\t\t\t}\n\t\t} else {\n\t\t\tconst gitFiles =\n\t\t\t\t(await this.git.raw(\n\t\t\t\t\t\"ls-files\",\n\t\t\t\t\t\"-co\",\n\t\t\t\t\t\"--exclude-standard\",\n\t\t\t\t\t\"--full-name\",\n\t\t\t\t)) ?? \"\";\n\n\t\t\tfilePathsToCheck.push(...gitFiles.split(\"\\n\"));\n\t\t}\n\n\t\tawait this.executeAllPolicies(filePathsToCheck);\n\t}\n\n\tprivate async executeAllPolicies(pathsToCheck: string[]): Promise<void> {\n\t\tconst commandContext: RepopoCommandContext = await this.getContext();\n\n\t\ttry {\n\t\t\tfor (const pathToCheck of pathsToCheck) {\n\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\tawait this.checkOrExcludeFile(pathToCheck, commandContext);\n\t\t\t}\n\t\t} finally {\n\t\t\tif (!this.flags.quiet) {\n\t\t\t\tlogStats(commandContext.perfStats, this);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Routes files to their handlers and resolvers by regex testing their full paths. If a file fails a policy that has a\n\t * resolver, the resolver will be invoked as well. Synchronizes the output, exit codes, and resolve\n\t * decision for all handlers.\n\t */\n\tprivate async routeToHandlers(\n\t\tfile: string,\n\t\tcommandContext: RepopoCommandContext,\n\t): Promise<void> {\n\t\tconst { policies, gitRoot } = commandContext;\n\n\t\t// Use the repo-relative path so that regexes that specify string start (^) will match repo paths.\n\t\t// Replace \\ in result with / in case OS is Windows.\n\t\tconst relPath = path.relative(gitRoot, file).replace(/\\\\/g, \"/\");\n\n\t\tconst filteredPolicies = policies.filter((handler) =>\n\t\t\thandler.match.test(relPath),\n\t\t);\n\n\t\tconst resultsP: Promise<void>[] = [];\n\n\t\tfor (const policy of filteredPolicies) {\n\t\t\tresultsP.push(this.runPolicyOnFile(relPath, policy));\n\t\t}\n\n\t\tawait Promise.all(resultsP);\n\t}\n\n\t// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: FIXME\n\tprivate async runPolicyOnFile(\n\t\trelPath: string,\n\t\t// policies: RepoPolicy[],\n\t\tpolicy: RepoPolicy,\n\t): Promise<void> {\n\t\tconst context = await this.getContext();\n\t\tconst { excludePoliciesForFiles, perfStats, gitRoot } = context;\n\n\t\t// doing exclusion per handler\n\t\tconst exclusions = excludePoliciesForFiles.get(policy.name);\n\t\tif (\n\t\t\texclusions !== undefined &&\n\t\t\t!exclusions.every((regex) => !regex.test(relPath))\n\t\t) {\n\t\t\tthis.verbose(`Excluded from '${policy.name}' policy: ${relPath}`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst result = await runWithPerf(\n\t\t\tpolicy.name,\n\t\t\t\"handle\",\n\t\t\tperfStats,\n\t\t\tasync () =>\n\t\t\t\tpolicy.handler({\n\t\t\t\t\tfile: relPath,\n\t\t\t\t\troot: gitRoot,\n\t\t\t\t\tresolve: this.flags.fix,\n\t\t\t\t\tconfig: this.commandConfig?.perPolicyConfig?.[\n\t\t\t\t\t\tpolicy.name\n\t\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: FIXME\n\t\t\t\t\t] as any,\n\t\t\t\t}),\n\t\t);\n\n\t\tif (result === true) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst messages = new StringBuilder();\n\t\tif (isPolicyFixResult(result)) {\n\t\t\tif (result.resolved) {\n\t\t\t\tmessages.append(\n\t\t\t\t\t`Resolved ${policy.name} policy failure for file: ${result.file}`,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tmessages.append(\n\t\t\t\t\t`Error when trying to fix ${policy.name} policy failure in ${result.file}`,\n\t\t\t\t);\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t}\n\t\t} else {\n\t\t\t// result must be a PolicyFailureResult; check if there is a standalone resolver.\n\t\t\tconst { resolver } = policy;\n\n\t\t\tif (this.flags.fix && resolver !== undefined) {\n\t\t\t\t// Resolve the failure\n\t\t\t\tmessages.append(`${newline}attempting to resolve: ${relPath}`);\n\t\t\t\tconst resolveResult = await runWithPerf(\n\t\t\t\t\tpolicy.name,\n\t\t\t\t\t\"resolve\",\n\t\t\t\t\tperfStats,\n\t\t\t\t\tasync () => resolver({ file: relPath, root: gitRoot }),\n\t\t\t\t);\n\n\t\t\t\tif (\n\t\t\t\t\tresolveResult.errorMessage !== undefined &&\n\t\t\t\t\tresolveResult.errorMessage !== \"\"\n\t\t\t\t) {\n\t\t\t\t\tmessages.append(newline + resolveResult.errorMessage);\n\t\t\t\t}\n\n\t\t\t\tif (!resolveResult.resolved) {\n\t\t\t\t\tprocess.exitCode = 1;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// No resolver, or fix is false, so we're in the full failure case.\n\t\t\t\tconst autoFixable = result.autoFixable\n\t\t\t\t\t? chalk.green(\" (autofixable)\")\n\t\t\t\t\t: \"\";\n\t\t\t\tmessages.append(\n\t\t\t\t\t`'${chalk.bold(policy.name)}' policy failure${autoFixable}: ${result.file}`,\n\t\t\t\t);\n\t\t\t\tmessages.append(\n\t\t\t\t\tresult.errorMessage === undefined\n\t\t\t\t\t\t? \"\"\n\t\t\t\t\t\t: `${newline}\\t${result.errorMessage}`,\n\t\t\t\t);\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t}\n\t\t}\n\n\t\tif ((process.exitCode ?? 0) === 0) {\n\t\t\tthis.info(messages.toString());\n\t\t} else {\n\t\t\tthis.warning(messages.toString());\n\t\t}\n\t}\n\n\t/**\n\t * Given a string that represents a path to a file in the repo, determines if the file should be checked, and if so,\n\t * routes the file to the appropriate handlers.\n\t */\n\tprivate async checkOrExcludeFile(\n\t\tinputPath: string,\n\t\tcommandContext: RepopoCommandContext,\n\t): Promise<void> {\n\t\tconst { excludeFiles: exclusions, gitRoot, perfStats } = commandContext;\n\n\t\tconst filePath = path.join(gitRoot, inputPath).trim().replace(/\\\\/g, \"/\");\n\n\t\tperfStats.count++;\n\t\tif (!exclusions.every((value) => !value.test(inputPath))) {\n\t\t\tthis.verbose(`Excluded all handlers: ${inputPath}`);\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.routeToHandlers(filePath, commandContext);\n\t\t} catch (error: unknown) {\n\t\t\tthrow new Error(\n\t\t\t\t`Error routing ${filePath} to handler: ${error}\\nStack:\\n${(error as Error).stack}`,\n\t\t\t);\n\t\t}\n\n\t\tperfStats.processed++;\n\t}\n}\n\nasync function readStdin(): Promise<string> {\n\treturn new Promise((resolve) => {\n\t\tconst stdin = process.stdin;\n\t\tstdin.setEncoding(\"utf8\");\n\n\t\tlet data = \"\";\n\t\tstdin.on(\"data\", (chunk) => {\n\t\t\tdata += chunk;\n\t\t});\n\n\t\tstdin.on(\"end\", () => {\n\t\t\tresolve(data);\n\t\t});\n\n\t\tif (stdin.isTTY) {\n\t\t\tresolve(\"\");\n\t\t}\n\t});\n}\n"]}
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"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","sourcesContent":["import { EOL as newline } from \"node:os\";\nimport { Flags } from \"@oclif/core\";\nimport { StringBuilder } from \"@rushstack/node-core-library\";\nimport chalk from \"picocolors\";\n\nimport { BaseRepopoCommand } from \"../baseCommand.js\";\nimport type { RepopoCommandContext } from \"../context.js\";\nimport { type PolicyHandlerPerfStats, logStats, runWithPerf } from \"../perf.js\";\nimport {\n\ttype PolicyFailure,\n\ttype PolicyFixResult,\n\ttype PolicyHandlerResult,\n\ttype PolicyInstance,\n\ttype PolicyStandaloneResolver,\n\tisPolicyFixResult,\n} from \"../policy.js\";\n\n/**\n * This tool enforces policies across the code base via a series of handler functions. The handler functions are\n * associated with a regular expression, and all files matching that expression are passed to the handler function.\n *\n * By default, the list of files to check comes from `git ls-files. You can also pipe in file names from stdin. For\n * example:\n *\n * `git ls-files -co --exclude-standard --full-name | repopo check --stdin --verbose`\n */\nexport class CheckPolicy<\n\tT extends typeof BaseRepopoCommand & {\n\t\targs: typeof CheckPolicy.args;\n\t\tflags: typeof CheckPolicy.flags;\n\t},\n> extends BaseRepopoCommand<T> {\n\tstatic override readonly summary =\n\t\t\"Checks and applies policies to the files in the repository.\";\n\n\tstatic override readonly flags = {\n\t\tfix: Flags.boolean({\n\t\t\taliases: [\"resolve\"],\n\t\t\tdescription: \"Fix errors if possible.\",\n\t\t\trequired: false,\n\t\t\tchar: \"f\",\n\t\t}),\n\t\tstdin: Flags.boolean({\n\t\t\tdescription: \"Read list of files from stdin.\",\n\t\t\trequired: false,\n\t\t}),\n\t\t...BaseRepopoCommand.flags,\n\t} as const;\n\n\tpublic override async run(): Promise<void> {\n\t\tif (this.flags.fix) {\n\t\t\tthis.info(\"Resolving errors if possible.\");\n\t\t}\n\n\t\tconst config = this.commandConfig;\n\t\tconst policies = config?.policies ?? [];\n\t\tthis.verbose(`${policies.length} policies loaded.`);\n\t\tfor (const h of policies) {\n\t\t\tthis.verbose(h.name);\n\t\t}\n\n\t\tconst filePathsToCheck: string[] = [];\n\n\t\tif (this.flags.stdin) {\n\t\t\tconst stdInput = await readStdin();\n\n\t\t\tif (stdInput !== undefined) {\n\t\t\t\tfilePathsToCheck.push(\n\t\t\t\t\t...stdInput\n\t\t\t\t\t\t.replace(\n\t\t\t\t\t\t\t// normalize slashes in case they're windows paths\n\t\t\t\t\t\t\t/\\\\/g,\n\t\t\t\t\t\t\t\"/\",\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.split(\"\\n\"),\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tconst gitFiles =\n\t\t\t\t(await this.git.raw(\n\t\t\t\t\t\"ls-files\",\n\t\t\t\t\t// include staged files and untracked files\n\t\t\t\t\t\"-co\",\n\t\t\t\t\t// exclude gitignored files and other standard ignore rules\n\t\t\t\t\t\"--exclude-standard\",\n\t\t\t\t\t// Outputs paths relative to the root of the repository, regardless of the current working directory.\n\t\t\t\t\t\"--full-name\",\n\t\t\t\t)) ?? \"\";\n\n\t\t\tfilePathsToCheck.push(\n\t\t\t\t...gitFiles\n\t\t\t\t\t.replace(\n\t\t\t\t\t\t// normalize slashes in case they're windows paths\n\t\t\t\t\t\t/\\\\/g,\n\t\t\t\t\t\t\"/\",\n\t\t\t\t\t)\n\t\t\t\t\t.split(\"\\n\"),\n\t\t\t);\n\t\t}\n\n\t\tconst context: RepopoCommandContext = await this.getContext();\n\n\t\tawait this.checkAllFiles(filePathsToCheck, context);\n\t}\n\n\t/**\n\t * Executes all policies against the provided paths.\n\t *\n\t * @param pathsToCheck - All paths that should be checked. Paths should be relative to the repository root.\n\t * @param context - The context.\n\t */\n\tprivate async checkAllFiles(\n\t\tpathsToCheck: string[],\n\t\tcontext: RepopoCommandContext,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tfor (const pathToCheck of pathsToCheck) {\n\t\t\t\tawait this.checkOrExcludeFile(pathToCheck, context);\n\t\t\t}\n\t\t} finally {\n\t\t\tif (!this.flags.quiet) {\n\t\t\t\tlogStats(context.perfStats, this);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Given a string that represents a path to a file in the repo, determines if the file should be checked, and if so,\n\t * routes the file to the appropriate handlers.\n\t *\n\t * @param relPath - A git repo-relative path to a file.\n\t */\n\tprivate async checkOrExcludeFile(\n\t\trelPath: string,\n\t\tcontext: RepopoCommandContext,\n\t): Promise<void> {\n\t\tconst { perfStats } = context;\n\t\tperfStats.count++;\n\n\t\ttry {\n\t\t\tawait this.routeToPolicies(relPath, context);\n\t\t} catch (error: unknown) {\n\t\t\tthrow new Error(\n\t\t\t\t`Error routing ${relPath} to handler: ${error}\\nStack:\\n${(error as Error).stack}`,\n\t\t\t);\n\t\t}\n\n\t\tperfStats.processed++;\n\t}\n\n\tprivate async routeToPolicies(\n\t\trelPath: string,\n\t\tcontext: RepopoCommandContext,\n\t): Promise<void> {\n\t\tconst { policies, excludeFromAll } = context;\n\n\t\t// Check exclusions\n\t\tif (excludeFromAll.some((regex) => regex.test(relPath))) {\n\t\t\tthis.verbose(`Excluded all handlers: ${relPath}`);\n\t\t\treturn; // Early return for excluded files\n\t\t}\n\n\t\t// Run all matching policies\n\t\tconst matchingPolicies = policies.filter((policy) =>\n\t\t\tpolicy.match.test(relPath),\n\t\t);\n\n\t\t// for(const policy of matchingPolicies) {\n\t\t// \tbars.addFile(policy.name,\n\t\t// }\n\n\t\tawait Promise.all(\n\t\t\tmatchingPolicies.map(async (policy) => {\n\t\t\t\treturn await this.runPolicyOnFile(relPath, policy, context);\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate async runPolicyOnFile(\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tcontext: RepopoCommandContext,\n\t): Promise<void> {\n\t\tconst { excludePoliciesForFiles, perfStats, gitRoot } = context;\n\n\t\t// Check if the policy is excluded for the file\n\t\tif (this.isPolicyExcluded(relPath, policy, excludePoliciesForFiles)) {\n\t\t\tthis.verbose(`Excluded from '${policy.name}' policy: ${relPath}`);\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\t// Execute the policy handler\n\t\t\tconst result = await this.executePolicyHandler(\n\t\t\t\trelPath,\n\t\t\t\tpolicy,\n\t\t\t\tperfStats,\n\t\t\t\tgitRoot,\n\t\t\t);\n\n\t\t\t// Handle the result of the policy execution\n\t\t\tawait this.handlePolicyResult(\n\t\t\t\tresult,\n\t\t\t\trelPath,\n\t\t\t\tpolicy,\n\t\t\t\tperfStats,\n\t\t\t\tgitRoot,\n\t\t\t);\n\t\t} catch (error: unknown) {\n\t\t\t// Log and rethrow the error for higher-level handling\n\t\t\tthis.error(\n\t\t\t\t`Error executing policy '${policy.name}' for file '${relPath}': ${error}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate isPolicyExcluded(\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\texcludePoliciesForFiles: Map<string, RegExp[]>,\n\t): boolean {\n\t\treturn (\n\t\t\texcludePoliciesForFiles\n\t\t\t\t.get(policy.name)\n\t\t\t\t?.some((regex) => regex.test(relPath)) ?? false\n\t\t);\n\t}\n\n\tprivate async executePolicyHandler(\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tperfStats: PolicyHandlerPerfStats,\n\t\tgitRoot: string,\n\t): Promise<PolicyHandlerResult> {\n\t\ttry {\n\t\t\treturn await runWithPerf(policy.name, \"handle\", perfStats, () =>\n\t\t\t\tpolicy.handler({\n\t\t\t\t\tfile: relPath,\n\t\t\t\t\troot: gitRoot,\n\t\t\t\t\tresolve: this.flags.fix,\n\t\t\t\t\tconfig: policy.config,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error: unknown) {\n\t\t\tthis.error(\n\t\t\t\t`Error in policy handler '${policy.name}' for file '${relPath}': ${error}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async handlePolicyResult(\n\t\tresult: PolicyHandlerResult,\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tperfStats: PolicyHandlerPerfStats,\n\t\tgitRoot: string,\n\t): Promise<void> {\n\t\tif (result === true) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (isPolicyFixResult(result)) {\n\t\t\tthis.handleFixResult(result, policy);\n\t\t} else {\n\t\t\tawait this.handleFailureResult(\n\t\t\t\tresult,\n\t\t\t\trelPath,\n\t\t\t\tpolicy,\n\t\t\t\tperfStats,\n\t\t\t\tgitRoot,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate handleFixResult(\n\t\tresult: PolicyFixResult,\n\t\tpolicy: PolicyInstance,\n\t): void {\n\t\tconst messages = new StringBuilder();\n\n\t\tif (result.resolved) {\n\t\t\tmessages.append(\n\t\t\t\t`Resolved ${policy.name} policy failure for file: ${result.file}`,\n\t\t\t);\n\t\t} else {\n\t\t\tmessages.append(\n\t\t\t\t`Error fixing ${policy.name} policy failure in ${result.file}`,\n\t\t\t);\n\t\t\tprocess.exitCode = 1;\n\t\t}\n\n\t\tthis.logMessages(messages);\n\t}\n\n\tprivate async handleFailureResult(\n\t\tresult: PolicyFailure,\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tperfStats: PolicyHandlerPerfStats,\n\t\tgitRoot: string,\n\t): Promise<void> {\n\t\tconst messages = new StringBuilder();\n\n\t\tif (this.flags.fix && policy.resolver) {\n\t\t\tawait this.attemptResolution(\n\t\t\t\trelPath,\n\t\t\t\tpolicy,\n\t\t\t\tpolicy.resolver,\n\t\t\t\tperfStats,\n\t\t\t\tgitRoot,\n\t\t\t\tmessages,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.logPolicyFailure(result, policy, messages);\n\t\t}\n\n\t\tthis.logMessages(messages);\n\t}\n\n\tprivate async attemptResolution(\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tresolver: PolicyStandaloneResolver,\n\t\tperfStats: PolicyHandlerPerfStats,\n\t\tgitRoot: string,\n\t\tmessages: StringBuilder,\n\t): Promise<void> {\n\t\tmessages.append(`${newline}Attempting to resolve: ${relPath}`);\n\t\tconst resolveResult = await runWithPerf(\n\t\t\tpolicy.name,\n\t\t\t\"resolve\",\n\t\t\tperfStats,\n\t\t\t() => resolver({ file: relPath, root: gitRoot }),\n\t\t);\n\n\t\tif (!resolveResult.resolved) {\n\t\t\tprocess.exitCode = 1;\n\t\t}\n\n\t\tif (resolveResult.errorMessage) {\n\t\t\tmessages.append(newline + resolveResult.errorMessage);\n\t\t}\n\t}\n\n\tprivate logPolicyFailure(\n\t\tresult: PolicyFailure,\n\t\tpolicy: PolicyInstance,\n\t\tmessages: StringBuilder,\n\t): void {\n\t\tconst autoFixable = result.autoFixable ? chalk.green(\" (autofixable)\") : \"\";\n\t\tmessages.append(\n\t\t\t`'${chalk.bold(policy.name)}' policy failure${autoFixable}: ${result.file}`,\n\t\t);\n\t\tif (result.errorMessage) {\n\t\t\tmessages.append(`${newline}\\t${result.errorMessage}`);\n\t\t}\n\t\tprocess.exitCode = 1;\n\t}\n\tprivate logMessages(messages: StringBuilder): void {\n\t\tif ((process.exitCode ?? 0) === 0) {\n\t\t\tthis.info(messages.toString());\n\t\t} else {\n\t\t\tthis.warning(messages.toString());\n\t\t}\n\t}\n}\n\nasync function readStdin(): Promise<string> {\n\treturn new Promise((resolve) => {\n\t\tconst stdin = process.stdin;\n\t\tstdin.setEncoding(\"utf8\");\n\n\t\tlet data = \"\";\n\t\tstdin.on(\"data\", (chunk) => {\n\t\t\tdata += chunk;\n\t\t});\n\n\t\tstdin.on(\"end\", () => {\n\t\t\tresolve(data);\n\t\t});\n\n\t\tif (stdin.isTTY) {\n\t\t\tresolve(\"\");\n\t\t}\n\t});\n}\n"]}
package/esm/config.d.ts CHANGED
@@ -1,14 +1,9 @@
1
- import type { PackageJsonPropertiesSettings } from "./policies/PackageJsonProperties.js";
2
- import { type PolicyName, type RepoPolicy } from "./policy.js";
3
- /**
4
- * @alpha
5
- */
6
- export type PerPolicySettings = ({
7
- PackageJsonProperties: PackageJsonPropertiesSettings;
8
- } & Record<PolicyName, unknown>) | undefined;
1
+ import type { PolicyCreator } from "./generators.js";
2
+ import { type PolicyInstance } from "./policy.js";
9
3
  /**
10
4
  * @alpha
11
5
  */
6
+ export type PolicyList = PolicyCreator[];
12
7
  /**
13
8
  * @alpha
14
9
  */
@@ -18,18 +13,12 @@ export interface RepopoConfig {
18
13
  *
19
14
  * See `DefaultPolicies` for the policies that will be enabled by default if this is `undefined`.
20
15
  */
21
- policies?: RepoPolicy<any>[];
16
+ policies?: PolicyInstance<any>[];
22
17
  /**
23
18
  * An array of strings/regular expressions. File paths that match any of these expressions will be completely excluded
24
19
  * from policy.
25
20
  */
26
21
  excludeFiles?: (string | RegExp)[];
27
- /**
28
- * An object with a policy name as keys that map to an array of strings/regular expressions to
29
- * exclude that rule from being checked.
30
- */
31
- excludePoliciesForFiles?: Record<PolicyName, (string | RegExp)[]>;
32
- perPolicyConfig?: PerPolicySettings | undefined;
33
22
  }
34
23
  /**
35
24
  * The default config applied when no config is found.
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,qCAAqC,CAAC;AACzF,OAAO,EAAmB,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAEhF;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAC1B,CAAC;IACD,qBAAqB,EAAE,6BAA6B,CAAC;CACpD,GAAG,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,GAChC,SAAS,CAAC;AAEb;;GAEG;AACH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B;;;;OAIG;IAGH,QAAQ,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;IAE7B;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAEnC;;;OAGG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;IAGlE,eAAe,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;CAChD;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,YAIjC,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAEnE;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B;;;;OAIG;IAEH,QAAQ,CAAC,EAAE,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;IAEjC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;CACnC;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,YAIjC,CAAC"}
package/esm/config.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { makePolicy } from "./makePolicy.js";
1
2
  import { DefaultPolicies } from "./policy.js";
2
3
  /**
3
4
  * The default config applied when no config is found.
@@ -5,8 +6,8 @@ import { DefaultPolicies } from "./policy.js";
5
6
  * @alpha
6
7
  */
7
8
  export const DefaultPolicyConfig = {
8
- policies: DefaultPolicies,
9
+ policies: DefaultPolicies.map((p) => makePolicy(p)),
9
10
  excludeFiles: [],
10
- excludePoliciesForFiles: {},
11
+ // excludePoliciesForFiles: {},
11
12
  };
12
13
  //# sourceMappingURL=config.js.map
package/esm/config.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAoC,MAAM,aAAa,CAAC;AA2ChF;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAiB;IAChD,QAAQ,EAAE,eAAe;IACzB,YAAY,EAAE,EAAE;IAChB,uBAAuB,EAAE,EAAE;CAC3B,CAAC","sourcesContent":["import type { PackageJsonPropertiesSettings } from \"./policies/PackageJsonProperties.js\";\nimport { DefaultPolicies, type PolicyName, type RepoPolicy } from \"./policy.js\";\n\n/**\n * @alpha\n */\nexport type PerPolicySettings =\n\t| ({\n\t\t\tPackageJsonProperties: PackageJsonPropertiesSettings;\n\t } & Record<PolicyName, unknown>)\n\t| undefined;\n\n/**\n * @alpha\n */\n/**\n * @alpha\n */\nexport interface RepopoConfig {\n\t/**\n\t * An array of policies that are enabled.\n\t *\n\t * See `DefaultPolicies` for the policies that will be enabled by default if this is `undefined`.\n\t */\n\n\t// biome-ignore lint/suspicious/noExplicitAny: FIXME\n\tpolicies?: RepoPolicy<any>[];\n\n\t/**\n\t * An array of strings/regular expressions. File paths that match any of these expressions will be completely excluded\n\t * from policy.\n\t */\n\texcludeFiles?: (string | RegExp)[];\n\n\t/**\n\t * An object with a policy name as keys that map to an array of strings/regular expressions to\n\t * exclude that rule from being checked.\n\t */\n\texcludePoliciesForFiles?: Record<PolicyName, (string | RegExp)[]>;\n\n\t// TODO: The type of this argument would ideally be a union of all types Record<Name of RepoPolicy, C of RepoPolicy>\n\tperPolicyConfig?: PerPolicySettings | undefined;\n}\n\n/**\n * The default config applied when no config is found.\n *\n * @alpha\n */\nexport const DefaultPolicyConfig: RepopoConfig = {\n\tpolicies: DefaultPolicies,\n\texcludeFiles: [],\n\texcludePoliciesForFiles: {},\n};\n"]}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAuB,MAAM,aAAa,CAAC;AA0BnE;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAiB;IAChD,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACnD,YAAY,EAAE,EAAE;IAChB,+BAA+B;CAC/B,CAAC","sourcesContent":["import type { PolicyCreator } from \"./generators.js\";\nimport { makePolicy } from \"./makePolicy.js\";\nimport { DefaultPolicies, type PolicyInstance } from \"./policy.js\";\n\n/**\n * @alpha\n */\nexport type PolicyList = PolicyCreator[];\n\n/**\n * @alpha\n */\nexport interface RepopoConfig {\n\t/**\n\t * An array of policies that are enabled.\n\t *\n\t * See `DefaultPolicies` for the policies that will be enabled by default if this is `undefined`.\n\t */\n\t// biome-ignore lint/suspicious/noExplicitAny: FIXME\n\tpolicies?: PolicyInstance<any>[];\n\n\t/**\n\t * An array of strings/regular expressions. File paths that match any of these expressions will be completely excluded\n\t * from policy.\n\t */\n\texcludeFiles?: (string | RegExp)[];\n}\n\n/**\n * The default config applied when no config is found.\n *\n * @alpha\n */\nexport const DefaultPolicyConfig: RepopoConfig = {\n\tpolicies: DefaultPolicies.map((p) => makePolicy(p)),\n\texcludeFiles: [],\n\t// excludePoliciesForFiles: {},\n};\n"]}