repopo 0.8.0 → 0.10.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 (141) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/THIRD-PARTY-LICENSES.txt +4 -3
  3. package/esm/adapters/fluidFramework.js +8 -3
  4. package/esm/adapters/fluidFramework.js.map +1 -1
  5. package/esm/baseCommand.d.ts.map +1 -1
  6. package/esm/baseCommand.js +2 -1
  7. package/esm/baseCommand.js.map +1 -1
  8. package/esm/commands/check.d.ts +1 -0
  9. package/esm/commands/check.d.ts.map +1 -1
  10. package/esm/commands/check.js +114 -52
  11. package/esm/commands/check.js.map +1 -1
  12. package/esm/commands/list.d.ts.map +1 -1
  13. package/esm/commands/list.js +3 -1
  14. package/esm/commands/list.js.map +1 -1
  15. package/esm/config.d.ts +19 -4
  16. package/esm/config.d.ts.map +1 -1
  17. package/esm/config.js +2 -3
  18. package/esm/config.js.map +1 -1
  19. package/esm/generators.d.ts +30 -2
  20. package/esm/generators.d.ts.map +1 -1
  21. package/esm/generators.js +31 -1
  22. package/esm/generators.js.map +1 -1
  23. package/esm/index.d.ts +14 -4
  24. package/esm/index.d.ts.map +1 -1
  25. package/esm/index.js +17 -2
  26. package/esm/index.js.map +1 -1
  27. package/esm/makePolicy.d.ts +74 -3
  28. package/esm/makePolicy.d.ts.map +1 -1
  29. package/esm/makePolicy.js +87 -13
  30. package/esm/makePolicy.js.map +1 -1
  31. package/esm/perf.d.ts +3 -2
  32. package/esm/perf.d.ts.map +1 -1
  33. package/esm/perf.js +2 -2
  34. package/esm/perf.js.map +1 -1
  35. package/esm/policies/ConditionalScripts.d.ts +94 -0
  36. package/esm/policies/ConditionalScripts.d.ts.map +1 -0
  37. package/esm/policies/ConditionalScripts.js +144 -0
  38. package/esm/policies/ConditionalScripts.js.map +1 -0
  39. package/esm/policies/ExactScripts.d.ts +51 -0
  40. package/esm/policies/ExactScripts.d.ts.map +1 -0
  41. package/esm/policies/ExactScripts.js +107 -0
  42. package/esm/policies/ExactScripts.js.map +1 -0
  43. package/esm/policies/HtmlFileHeaders.d.ts +1 -1
  44. package/esm/policies/HtmlFileHeaders.d.ts.map +1 -1
  45. package/esm/policies/HtmlFileHeaders.js +11 -7
  46. package/esm/policies/HtmlFileHeaders.js.map +1 -1
  47. package/esm/policies/JsTsFileHeaders.d.ts +1 -1
  48. package/esm/policies/JsTsFileHeaders.d.ts.map +1 -1
  49. package/esm/policies/JsTsFileHeaders.js +11 -7
  50. package/esm/policies/JsTsFileHeaders.js.map +1 -1
  51. package/esm/policies/LicenseFileExists.d.ts.map +1 -1
  52. package/esm/policies/LicenseFileExists.js +22 -18
  53. package/esm/policies/LicenseFileExists.js.map +1 -1
  54. package/esm/policies/MutuallyExclusiveScripts.d.ts +46 -0
  55. package/esm/policies/MutuallyExclusiveScripts.d.ts.map +1 -0
  56. package/esm/policies/MutuallyExclusiveScripts.js +52 -0
  57. package/esm/policies/MutuallyExclusiveScripts.js.map +1 -0
  58. package/esm/policies/NoJsFileExtensions.d.ts.map +1 -1
  59. package/esm/policies/NoJsFileExtensions.js +16 -12
  60. package/esm/policies/NoJsFileExtensions.js.map +1 -1
  61. package/esm/policies/NoLargeBinaryFiles.d.ts.map +1 -1
  62. package/esm/policies/NoLargeBinaryFiles.js +35 -31
  63. package/esm/policies/NoLargeBinaryFiles.js.map +1 -1
  64. package/esm/policies/NoPrivateWorkspaceDependencies.d.ts +1 -1
  65. package/esm/policies/NoPrivateWorkspaceDependencies.d.ts.map +1 -1
  66. package/esm/policies/NoPrivateWorkspaceDependencies.js +53 -45
  67. package/esm/policies/NoPrivateWorkspaceDependencies.js.map +1 -1
  68. package/esm/policies/PackageAllowedScopes.d.ts +1 -1
  69. package/esm/policies/PackageAllowedScopes.d.ts.map +1 -1
  70. package/esm/policies/PackageAllowedScopes.js +45 -40
  71. package/esm/policies/PackageAllowedScopes.js.map +1 -1
  72. package/esm/policies/PackageEsmType.d.ts +1 -1
  73. package/esm/policies/PackageEsmType.d.ts.map +1 -1
  74. package/esm/policies/PackageEsmType.js +48 -44
  75. package/esm/policies/PackageEsmType.js.map +1 -1
  76. package/esm/policies/PackageFolderName.d.ts +1 -1
  77. package/esm/policies/PackageFolderName.d.ts.map +1 -1
  78. package/esm/policies/PackageFolderName.js +38 -34
  79. package/esm/policies/PackageFolderName.js.map +1 -1
  80. package/esm/policies/PackageJsonProperties.d.ts +1 -1
  81. package/esm/policies/PackageJsonProperties.d.ts.map +1 -1
  82. package/esm/policies/PackageJsonProperties.js +36 -31
  83. package/esm/policies/PackageJsonProperties.js.map +1 -1
  84. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts +1 -1
  85. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts.map +1 -1
  86. package/esm/policies/PackageJsonRepoDirectoryProperty.js +41 -38
  87. package/esm/policies/PackageJsonRepoDirectoryProperty.js.map +1 -1
  88. package/esm/policies/PackageJsonSorted.d.ts +1 -1
  89. package/esm/policies/PackageJsonSorted.d.ts.map +1 -1
  90. package/esm/policies/PackageJsonSorted.js +40 -36
  91. package/esm/policies/PackageJsonSorted.js.map +1 -1
  92. package/esm/policies/PackageLicense.d.ts +1 -1
  93. package/esm/policies/PackageLicense.d.ts.map +1 -1
  94. package/esm/policies/PackageLicense.js +58 -54
  95. package/esm/policies/PackageLicense.js.map +1 -1
  96. package/esm/policies/PackagePrivateField.d.ts +1 -1
  97. package/esm/policies/PackagePrivateField.d.ts.map +1 -1
  98. package/esm/policies/PackagePrivateField.js +58 -54
  99. package/esm/policies/PackagePrivateField.js.map +1 -1
  100. package/esm/policies/PackageReadme.d.ts +1 -1
  101. package/esm/policies/PackageReadme.d.ts.map +1 -1
  102. package/esm/policies/PackageReadme.js +30 -26
  103. package/esm/policies/PackageReadme.js.map +1 -1
  104. package/esm/policies/PackageScripts.d.ts +1 -1
  105. package/esm/policies/PackageScripts.d.ts.map +1 -1
  106. package/esm/policies/PackageScripts.js +39 -35
  107. package/esm/policies/PackageScripts.js.map +1 -1
  108. package/esm/policies/PackageTestScripts.d.ts +1 -1
  109. package/esm/policies/PackageTestScripts.d.ts.map +1 -1
  110. package/esm/policies/PackageTestScripts.js +46 -40
  111. package/esm/policies/PackageTestScripts.js.map +1 -1
  112. package/esm/policies/RequiredGitignorePatterns.d.ts.map +1 -1
  113. package/esm/policies/RequiredGitignorePatterns.js +20 -15
  114. package/esm/policies/RequiredGitignorePatterns.js.map +1 -1
  115. package/esm/policies/RequiredScripts.d.ts +71 -0
  116. package/esm/policies/RequiredScripts.d.ts.map +1 -0
  117. package/esm/policies/RequiredScripts.js +120 -0
  118. package/esm/policies/RequiredScripts.js.map +1 -0
  119. package/esm/policies/ScriptContains.d.ts +64 -0
  120. package/esm/policies/ScriptContains.d.ts.map +1 -0
  121. package/esm/policies/ScriptContains.js +62 -0
  122. package/esm/policies/ScriptContains.js.map +1 -0
  123. package/esm/policies.d.ts +6 -1
  124. package/esm/policies.d.ts.map +1 -1
  125. package/esm/policies.js +18 -0
  126. package/esm/policies.js.map +1 -1
  127. package/esm/policy.d.ts +193 -74
  128. package/esm/policy.d.ts.map +1 -1
  129. package/esm/policy.js +110 -19
  130. package/esm/policy.js.map +1 -1
  131. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts +49 -2
  132. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts.map +1 -1
  133. package/esm/policyDefiners/defineFileHeaderPolicy.js +21 -4
  134. package/esm/policyDefiners/defineFileHeaderPolicy.js.map +1 -1
  135. package/esm/policyDefiners/definePackagePolicy.d.ts +57 -3
  136. package/esm/policyDefiners/definePackagePolicy.d.ts.map +1 -1
  137. package/esm/policyDefiners/definePackagePolicy.js +50 -5
  138. package/esm/policyDefiners/definePackagePolicy.js.map +1 -1
  139. package/esm/tsdoc-metadata.json +1 -1
  140. package/oclif.manifest.json +1 -1
  141. package/package.json +6 -4
@@ -1,14 +1,25 @@
1
1
  import { readFile, writeFile } from "node:fs/promises";
2
2
  import { EOL as newline } from "node:os";
3
+ import { call } from "effection";
3
4
  import { extname } from "pathe";
4
5
  const trailingSpaces = /\s*\\r\?\\n/;
5
6
  /**
6
7
  * Given a {@link FileHeaderPolicyConfig}, produces a function that detects correct file headers
7
8
  * and returns an error string if the header is missing or incorrect.
8
9
  *
10
+ * @example
11
+ * ```typescript
12
+ * const MyHeaderPolicy = defineFileHeaderPolicy({
13
+ * name: "MyHeaderPolicy",
14
+ * description: "Ensures files have required headers",
15
+ * config: { match: /\.ts$/, lineStart: /\/\/ /, lineEnd: /\r?\n/, replacer: ... },
16
+ * });
17
+ * ```
18
+ *
9
19
  * @alpha
10
20
  */
11
- export function defineFileHeaderPolicy(name, config) {
21
+ export function defineFileHeaderPolicy(args) {
22
+ const { name, description, config } = args;
12
23
  const pre = config.headerStart?.source ?? "";
13
24
  const start = config.lineStart.source;
14
25
  const end = config.lineEnd.source;
@@ -25,8 +36,9 @@ export function defineFileHeaderPolicy(name, config) {
25
36
  const regex = new RegExp(`^${pre}${toRegex(config.headerText ?? "")}(${toRegex(config.autoGenText ?? "")})?${post}`);
26
37
  return {
27
38
  name,
39
+ description,
28
40
  match: config.match,
29
- handler: async ({ file, resolve, config: policyConfig }) => {
41
+ handler: function* ({ file, resolve, config: policyConfig }) {
30
42
  if (policyConfig === undefined) {
31
43
  return true;
32
44
  }
@@ -38,7 +50,7 @@ export function defineFileHeaderPolicy(name, config) {
38
50
  };
39
51
  // TODO: Consider reading only the first 512B or so since headers are typically
40
52
  // at the beginning of the file.
41
- const content = await readFile(file, { encoding: "utf8" });
53
+ const content = yield* call(() => readFile(file, { encoding: "utf8" }));
42
54
  const failed = !regex.test(content);
43
55
  if (failed) {
44
56
  failResult.errorMessages.push(`${extname(file)} file missing header`);
@@ -46,7 +58,7 @@ export function defineFileHeaderPolicy(name, config) {
46
58
  if (failed) {
47
59
  if (resolve) {
48
60
  const newContent = config.replacer(content, policyConfig);
49
- await writeFile(file, newContent);
61
+ yield* call(() => writeFile(file, newContent));
50
62
  const fixResult = {
51
63
  ...failResult,
52
64
  resolved: true,
@@ -59,4 +71,9 @@ export function defineFileHeaderPolicy(name, config) {
59
71
  },
60
72
  };
61
73
  }
74
+ /**
75
+ * Alias for defineFileHeaderPolicy.
76
+ * @alpha
77
+ */
78
+ export const fileHeaderPolicy = defineFileHeaderPolicy;
62
79
  //# sourceMappingURL=defineFileHeaderPolicy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"defineFileHeaderPolicy.js","sourceRoot":"","sources":["../../src/policyDefiners/defineFileHeaderPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,GAAG,IAAI,OAAO,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAOhC,MAAM,cAAc,GAAG,aAAa,CAAC;AA+CrC;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACrC,IAAY,EACZ,MAAiC;IAEjC,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,EAAE,MAAM,IAAI,EAAE,CAAC;IAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;IACtC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;IAClC,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,EAAE,MAAM,IAAI,EAAE,CAAC;IAE5C,2EAA2E;IAC3E,mGAAmG;IACnG,MAAM,OAAO,GAAG,CAAC,IAAY,EAAU,EAAE,CACxC,IAAI;SACF,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CACH,CAAC,IAAI,EAAE,EAAE,CACR,GAAG,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAAG,GAAG,EAAE,CAC/D;SACA,IAAI,CAAC,EAAE,CAAC;SACR,OAAO,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC,CAAC,uCAAuC;IAE9E,wFAAwF;IACxF,0FAA0F;IAC1F,MAAM,KAAK,GAAG,IAAI,MAAM,CACvB,IAAI,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,KAAK,IAAI,EAAE,CAC1F,CAAC;IAEF,OAAO;QACN,IAAI;QACJ,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE;YAC1D,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;gBAChC,OAAO,IAAI,CAAC;YACb,CAAC;YAED,MAAM,UAAU,GAAkB;gBACjC,IAAI;gBACJ,IAAI;gBACJ,WAAW,EAAE,IAAI;gBACjB,aAAa,EAAE,EAAE;aACjB,CAAC;YAEF,+EAA+E;YAC/E,gCAAgC;YAChC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;YAC3D,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEpC,IAAI,MAAM,EAAE,CAAC;gBACZ,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;YACvE,CAAC;YAED,IAAI,MAAM,EAAE,CAAC;gBACZ,IAAI,OAAO,EAAE,CAAC;oBACb,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;oBAC1D,MAAM,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;oBAElC,MAAM,SAAS,GAAoB;wBAClC,GAAG,UAAU;wBACb,QAAQ,EAAE,IAAI;qBACd,CAAC;oBAEF,OAAO,SAAS,CAAC;gBAClB,CAAC;gBACD,OAAO,UAAU,CAAC;YACnB,CAAC;YAED,OAAO,IAAI,CAAC;QACb,CAAC;KACD,CAAC;AACH,CAAC","sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\nimport { EOL as newline } from \"node:os\";\nimport { extname } from \"pathe\";\nimport type {\n\tPolicyDefinition,\n\tPolicyFailure,\n\tPolicyFixResult,\n} from \"../policy.js\";\n\nconst trailingSpaces = /\\s*\\\\r\\?\\\\n/;\n\n/**\n * @alpha\n */\nexport interface FileHeaderPolicyConfig {\n\t/**\n\t * The text to use as the header.\n\t */\n\theaderText: string;\n\n\t/**\n\t * An optional string that will be appended to the headerText.\n\t */\n\tautoGenText?: string;\n}\n\n/**\n * @alpha\n */\nexport interface FileHeaderGeneratorConfig\n\textends Partial<FileHeaderPolicyConfig> {\n\tmatch: RegExp;\n\n\t/**\n\t * Regex matching header prefix (e.g. `/*!\\r?\\n`)\n\t */\n\theaderStart?: RegExp;\n\n\t/**\n\t * Regex matching beginning of each line (e.g. ' * ')\n\t */\n\tlineStart: RegExp;\n\n\t/**\n\t * Regex matching the end of each line (e.g., `\\r?\\n`)\n\t */\n\tlineEnd: RegExp;\n\n\t/**\n\t * Regex matching the header postfix.\n\t */\n\theaderEnd?: RegExp;\n\n\treplacer: (content: string, config: FileHeaderPolicyConfig) => string;\n}\n\n/**\n * Given a {@link FileHeaderPolicyConfig}, produces a function that detects correct file headers\n * and returns an error string if the header is missing or incorrect.\n *\n * @alpha\n */\nexport function defineFileHeaderPolicy(\n\tname: string,\n\tconfig: FileHeaderGeneratorConfig,\n): PolicyDefinition<FileHeaderPolicyConfig> {\n\tconst pre = config.headerStart?.source ?? \"\";\n\tconst start = config.lineStart.source;\n\tconst end = config.lineEnd.source;\n\tconst post = config.headerEnd?.source ?? \"\";\n\n\t// Helper which constructs a matching RegExp from a given multiline string.\n\t// (See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping)\n\tconst toRegex = (text: string): string =>\n\t\ttext\n\t\t\t.split(newline)\n\t\t\t.map(\n\t\t\t\t(line) =>\n\t\t\t\t\t`${start}${line.replace(/[$()*+.?[\\\\\\]^{|}]/g, \"\\\\$&\")}${end}`,\n\t\t\t)\n\t\t\t.join(\"\")\n\t\t\t.replace(trailingSpaces, \"\\\\r?\\\\n\"); // Trim trailing spaces at end-of-line.\n\n\t// Detection regex matches the header start (if any), followed by lines in 'headerText',\n\t// optionally followed by lines in the 'autoGenText', and finally the header end (if any).\n\tconst regex = new RegExp(\n\t\t`^${pre}${toRegex(config.headerText ?? \"\")}(${toRegex(config.autoGenText ?? \"\")})?${post}`,\n\t);\n\n\treturn {\n\t\tname,\n\t\tmatch: config.match,\n\t\thandler: async ({ file, resolve, config: policyConfig }) => {\n\t\t\tif (policyConfig === undefined) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst failResult: PolicyFailure = {\n\t\t\t\tname,\n\t\t\t\tfile,\n\t\t\t\tautoFixable: true,\n\t\t\t\terrorMessages: [],\n\t\t\t};\n\n\t\t\t// TODO: Consider reading only the first 512B or so since headers are typically\n\t\t\t// at the beginning of the file.\n\t\t\tconst content = await readFile(file, { encoding: \"utf8\" });\n\t\t\tconst failed = !regex.test(content);\n\n\t\t\tif (failed) {\n\t\t\t\tfailResult.errorMessages.push(`${extname(file)} file missing header`);\n\t\t\t}\n\n\t\t\tif (failed) {\n\t\t\t\tif (resolve) {\n\t\t\t\t\tconst newContent = config.replacer(content, policyConfig);\n\t\t\t\t\tawait writeFile(file, newContent);\n\n\t\t\t\t\tconst fixResult: PolicyFixResult = {\n\t\t\t\t\t\t...failResult,\n\t\t\t\t\t\tresolved: true,\n\t\t\t\t\t};\n\n\t\t\t\t\treturn fixResult;\n\t\t\t\t}\n\t\t\t\treturn failResult;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"defineFileHeaderPolicy.js","sourceRoot":"","sources":["../../src/policyDefiners/defineFileHeaderPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,GAAG,IAAI,OAAO,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAGhC,MAAM,cAAc,GAAG,aAAa,CAAC;AAmFrC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,sBAAsB,CACrC,IAAgC;IAEhC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC3C,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,EAAE,MAAM,IAAI,EAAE,CAAC;IAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;IACtC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;IAClC,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,EAAE,MAAM,IAAI,EAAE,CAAC;IAE5C,2EAA2E;IAC3E,mGAAmG;IACnG,MAAM,OAAO,GAAG,CAAC,IAAY,EAAU,EAAE,CACxC,IAAI;SACF,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CACH,CAAC,IAAI,EAAE,EAAE,CACR,GAAG,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAAG,GAAG,EAAE,CAC/D;SACA,IAAI,CAAC,EAAE,CAAC;SACR,OAAO,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC,CAAC,uCAAuC;IAE9E,wFAAwF;IACxF,0FAA0F;IAC1F,MAAM,KAAK,GAAG,IAAI,MAAM,CACvB,IAAI,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,KAAK,IAAI,EAAE,CAC1F,CAAC;IAEF,OAAO;QACN,IAAI;QACJ,WAAW;QACX,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE;YAC1D,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;gBAChC,OAAO,IAAI,CAAC;YACb,CAAC;YAED,MAAM,UAAU,GAAkB;gBACjC,IAAI;gBACJ,IAAI;gBACJ,WAAW,EAAE,IAAI;gBACjB,aAAa,EAAE,EAAE;aACjB,CAAC;YAEF,+EAA+E;YAC/E,gCAAgC;YAChC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;YACxE,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEpC,IAAI,MAAM,EAAE,CAAC;gBACZ,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;YACvE,CAAC;YAED,IAAI,MAAM,EAAE,CAAC;gBACZ,IAAI,OAAO,EAAE,CAAC;oBACb,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;oBAC1D,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;oBAE/C,MAAM,SAAS,GAAoB;wBAClC,GAAG,UAAU;wBACb,QAAQ,EAAE,IAAI;qBACd,CAAC;oBAEF,OAAO,SAAS,CAAC;gBAClB,CAAC;gBACD,OAAO,UAAU,CAAC;YACnB,CAAC;YAED,OAAO,IAAI,CAAC;QACb,CAAC;KACD,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,sBAAsB,CAAC","sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\nimport { EOL as newline } from \"node:os\";\nimport { call } from \"effection\";\nimport { extname } from \"pathe\";\nimport type { PolicyFailure, PolicyFixResult, PolicyShape } from \"../policy.js\";\n\nconst trailingSpaces = /\\s*\\\\r\\?\\\\n/;\n\n/**\n * @alpha\n */\nexport interface FileHeaderPolicyConfig {\n\t/**\n\t * The text to use as the header.\n\t */\n\theaderText: string;\n\n\t/**\n\t * An optional string that will be appended to the headerText.\n\t */\n\tautoGenText?: string;\n}\n\n/**\n * Configuration for generating file headers with specific formatting rules.\n *\n * @remarks\n * This interface extends FileHeaderPolicyConfig and adds formatting-specific\n * properties to control how headers are inserted into different file types.\n *\n * @alpha\n */\nexport interface FileHeaderGeneratorConfig\n\textends Partial<FileHeaderPolicyConfig> {\n\t/** Regular expression that matches files this header generator applies to */\n\tmatch: RegExp;\n\n\t/**\n\t * Regex matching header prefix (e.g. `/*!\\r?\\n`)\n\t */\n\theaderStart?: RegExp;\n\n\t/**\n\t * Regex matching beginning of each line (e.g. ' * ')\n\t */\n\tlineStart: RegExp;\n\n\t/**\n\t * Regex matching the end of each line (e.g., `\\r?\\n`)\n\t */\n\tlineEnd: RegExp;\n\n\t/**\n\t * Regex matching the header postfix.\n\t */\n\theaderEnd?: RegExp;\n\n\t/**\n\t * Function that generates the properly formatted header content for insertion into files.\n\t *\n\t * @param content - The original file content\n\t * @param config - The file header policy configuration\n\t * @returns The formatted header string to insert\n\t */\n\treplacer: (content: string, config: FileHeaderPolicyConfig) => string;\n}\n\n/**\n * Input arguments for defining a file header policy.\n *\n * @alpha\n */\nexport interface DefineFileHeaderPolicyArgs {\n\t/**\n\t * The name of the policy.\n\t */\n\tname: string;\n\n\t/**\n\t * A description of the policy's purpose.\n\t */\n\tdescription: string;\n\n\t/**\n\t * Configuration for how headers are detected and inserted.\n\t */\n\tconfig: FileHeaderGeneratorConfig;\n}\n\n/**\n * Given a {@link FileHeaderPolicyConfig}, produces a function that detects correct file headers\n * and returns an error string if the header is missing or incorrect.\n *\n * @example\n * ```typescript\n * const MyHeaderPolicy = defineFileHeaderPolicy({\n * name: \"MyHeaderPolicy\",\n * description: \"Ensures files have required headers\",\n * config: { match: /\\.ts$/, lineStart: /\\/\\/ /, lineEnd: /\\r?\\n/, replacer: ... },\n * });\n * ```\n *\n * @alpha\n */\nexport function defineFileHeaderPolicy(\n\targs: DefineFileHeaderPolicyArgs,\n): PolicyShape<FileHeaderPolicyConfig> {\n\tconst { name, description, config } = args;\n\tconst pre = config.headerStart?.source ?? \"\";\n\tconst start = config.lineStart.source;\n\tconst end = config.lineEnd.source;\n\tconst post = config.headerEnd?.source ?? \"\";\n\n\t// Helper which constructs a matching RegExp from a given multiline string.\n\t// (See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping)\n\tconst toRegex = (text: string): string =>\n\t\ttext\n\t\t\t.split(newline)\n\t\t\t.map(\n\t\t\t\t(line) =>\n\t\t\t\t\t`${start}${line.replace(/[$()*+.?[\\\\\\]^{|}]/g, \"\\\\$&\")}${end}`,\n\t\t\t)\n\t\t\t.join(\"\")\n\t\t\t.replace(trailingSpaces, \"\\\\r?\\\\n\"); // Trim trailing spaces at end-of-line.\n\n\t// Detection regex matches the header start (if any), followed by lines in 'headerText',\n\t// optionally followed by lines in the 'autoGenText', and finally the header end (if any).\n\tconst regex = new RegExp(\n\t\t`^${pre}${toRegex(config.headerText ?? \"\")}(${toRegex(config.autoGenText ?? \"\")})?${post}`,\n\t);\n\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\tmatch: config.match,\n\t\thandler: function* ({ file, resolve, config: policyConfig }) {\n\t\t\tif (policyConfig === undefined) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst failResult: PolicyFailure = {\n\t\t\t\tname,\n\t\t\t\tfile,\n\t\t\t\tautoFixable: true,\n\t\t\t\terrorMessages: [],\n\t\t\t};\n\n\t\t\t// TODO: Consider reading only the first 512B or so since headers are typically\n\t\t\t// at the beginning of the file.\n\t\t\tconst content = yield* call(() => readFile(file, { encoding: \"utf8\" }));\n\t\t\tconst failed = !regex.test(content);\n\n\t\t\tif (failed) {\n\t\t\t\tfailResult.errorMessages.push(`${extname(file)} file missing header`);\n\t\t\t}\n\n\t\t\tif (failed) {\n\t\t\t\tif (resolve) {\n\t\t\t\t\tconst newContent = config.replacer(content, policyConfig);\n\t\t\t\t\tyield* call(() => writeFile(file, newContent));\n\n\t\t\t\t\tconst fixResult: PolicyFixResult = {\n\t\t\t\t\t\t...failResult,\n\t\t\t\t\t\tresolved: true,\n\t\t\t\t\t};\n\n\t\t\t\t\treturn fixResult;\n\t\t\t\t}\n\t\t\t\treturn failResult;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t},\n\t};\n}\n\n/**\n * Alias for defineFileHeaderPolicy.\n * @alpha\n */\nexport const fileHeaderPolicy = defineFileHeaderPolicy;\n"]}
@@ -1,15 +1,69 @@
1
+ import { type Operation } from "effection";
1
2
  import type { PackageJson } from "type-fest";
2
- import type { PolicyDefinition, PolicyFunctionArguments, PolicyHandlerResult } from "../policy.js";
3
+ import type { PolicyArgs, PolicyHandlerResult, PolicyShape } from "../policy.js";
3
4
  /**
4
5
  * A policy handler especially for policies that target package.json.
5
6
  *
7
+ * @remarks
8
+ * Package JSON handlers can be implemented in two ways:
9
+ * - As an async function returning a Promise
10
+ * - As an Effection generator function returning an Operation
11
+ *
12
+ * Both styles are supported to allow gradual migration and flexibility.
13
+ *
14
+ * @alpha
15
+ */
16
+ export type PackageJsonHandler<J, C> = (json: J, args: PolicyArgs<C>) => Operation<PolicyHandlerResult> | Promise<PolicyHandlerResult>;
17
+ /**
18
+ * Input arguments for defining a package.json policy.
19
+ *
6
20
  * @alpha
7
21
  */
8
- export type PackageJsonHandler<J, C> = (json: J, args: PolicyFunctionArguments<C>) => Promise<PolicyHandlerResult>;
22
+ export interface DefinePackagePolicyArgs<J, C> {
23
+ /**
24
+ * The name of the policy.
25
+ */
26
+ name: string;
27
+ /**
28
+ * A description of the policy's purpose.
29
+ */
30
+ description: string;
31
+ /**
32
+ * The handler function that receives the parsed package.json and policy arguments.
33
+ */
34
+ handler: PackageJsonHandler<J, C>;
35
+ /**
36
+ * Optional default configuration for the policy.
37
+ */
38
+ defaultConfig?: C;
39
+ }
9
40
  /**
10
41
  * Define a repo policy for package.json files.
11
42
  *
43
+ * @remarks
44
+ * This is a helper function that creates a policy pre-configured to match
45
+ * package.json files. The handler receives the parsed JSON content.
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * const MyPackagePolicy = definePackagePolicy({
50
+ * name: "MyPackagePolicy",
51
+ * description: "Ensures package.json has required fields",
52
+ * handler: async (json, { file }) => {
53
+ * if (!json.name) {
54
+ * return { error: "Missing name", fixable: false };
55
+ * }
56
+ * return true;
57
+ * },
58
+ * });
59
+ * ```
60
+ *
61
+ * @alpha
62
+ */
63
+ export declare function definePackagePolicy<J = PackageJson, C = undefined>(args: DefinePackagePolicyArgs<J, C>): PolicyShape<C>;
64
+ /**
65
+ * Alias for definePackagePolicy.
12
66
  * @alpha
13
67
  */
14
- export declare function definePackagePolicy<J = PackageJson, C = undefined>(name: string, packagePolicy: PackageJsonHandler<J, C>): PolicyDefinition<C>;
68
+ export declare const packagePolicy: typeof definePackagePolicy;
15
69
  //# sourceMappingURL=definePackagePolicy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"definePackagePolicy.d.ts","sourceRoot":"","sources":["../../src/policyDefiners/definePackagePolicy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,KAAK,EACX,gBAAgB,EAChB,uBAAuB,EACvB,mBAAmB,EACnB,MAAM,cAAc,CAAC;AAItB;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI,CACtC,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,uBAAuB,CAAC,CAAC,CAAC,KAC5B,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAElC;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,GAAG,WAAW,EAAE,CAAC,GAAG,SAAS,EACjE,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,GAErC,gBAAgB,CAAC,CAAC,CAAC,CAUrB"}
1
+ {"version":3,"file":"definePackagePolicy.d.ts","sourceRoot":"","sources":["../../src/policyDefiners/definePackagePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAGjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,KAAK,EACX,UAAU,EACV,mBAAmB,EACnB,WAAW,EACX,MAAM,cAAc,CAAC;AAItB;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI,CACtC,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KACf,SAAS,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAcnE;;;;GAIG;AACH,MAAM,WAAW,uBAAuB,CAAC,CAAC,EAAE,CAAC;IAC5C;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,OAAO,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAElC;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,GAAG,WAAW,EAAE,CAAC,GAAG,SAAS,EACjE,IAAI,EAAE,uBAAuB,CAAC,CAAC,EAAE,CAAC,CAAC,GACjC,WAAW,CAAC,CAAC,CAAC,CAyBhB;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,4BAAsB,CAAC"}
@@ -1,21 +1,66 @@
1
+ import { call } from "effection";
1
2
  import jsonfile from "jsonfile";
2
3
  import { resolve } from "pathe";
3
4
  import { PackageJsonRegexMatch } from "../policies/constants.js";
4
5
  const { readFile: readJson } = jsonfile;
6
+ /**
7
+ * Type guard to check if a value is an Effection Operation (generator).
8
+ */
9
+ function isOperation(value) {
10
+ return (typeof value === "object" &&
11
+ value !== null &&
12
+ "next" in value &&
13
+ typeof value.next === "function");
14
+ }
5
15
  /**
6
16
  * Define a repo policy for package.json files.
7
17
  *
18
+ * @remarks
19
+ * This is a helper function that creates a policy pre-configured to match
20
+ * package.json files. The handler receives the parsed JSON content.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const MyPackagePolicy = definePackagePolicy({
25
+ * name: "MyPackagePolicy",
26
+ * description: "Ensures package.json has required fields",
27
+ * handler: async (json, { file }) => {
28
+ * if (!json.name) {
29
+ * return { error: "Missing name", fixable: false };
30
+ * }
31
+ * return true;
32
+ * },
33
+ * });
34
+ * ```
35
+ *
8
36
  * @alpha
9
37
  */
10
- export function definePackagePolicy(name, packagePolicy) {
11
- // const func = () => handler(json, args);
38
+ export function definePackagePolicy(args) {
39
+ const { name, description, handler: packageHandler, defaultConfig } = args;
12
40
  return {
13
41
  name,
42
+ description,
14
43
  match: PackageJsonRegexMatch,
15
- handler: async (innerArgs) => {
16
- const json = await readJson(resolve(innerArgs.root, innerArgs.file));
17
- return packagePolicy(json, innerArgs);
44
+ defaultConfig,
45
+ handler: function* (innerArgs) {
46
+ const json = yield* call(() => readJson(resolve(innerArgs.root, innerArgs.file)));
47
+ const result = packageHandler(json, innerArgs);
48
+ // Handle both Operation (generator) and Promise return types
49
+ if (result instanceof Promise) {
50
+ return yield* call(() => result);
51
+ }
52
+ // Check if it's an Effection Operation (generator)
53
+ if (isOperation(result)) {
54
+ return yield* result;
55
+ }
56
+ // This should never happen with proper handler typing
57
+ throw new Error(`Unexpected handler result type: ${typeof result}`);
18
58
  },
19
59
  };
20
60
  }
61
+ /**
62
+ * Alias for definePackagePolicy.
63
+ * @alpha
64
+ */
65
+ export const packagePolicy = definePackagePolicy;
21
66
  //# sourceMappingURL=definePackagePolicy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"definePackagePolicy.js","sourceRoot":"","sources":["../../src/policyDefiners/definePackagePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAOjE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC;AAYxC;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAClC,IAAY,EACZ,aAAuC;IAGvC,0CAA0C;IAC1C,OAAO;QACN,IAAI;QACJ,KAAK,EAAE,qBAAqB;QAC5B,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;YAC5B,MAAM,IAAI,GAAM,MAAM,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YACxE,OAAO,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACvC,CAAC;KACD,CAAC;AACH,CAAC","sourcesContent":["import jsonfile from \"jsonfile\";\nimport { resolve } from \"pathe\";\nimport type { PackageJson } from \"type-fest\";\nimport { PackageJsonRegexMatch } from \"../policies/constants.js\";\nimport type {\n\tPolicyDefinition,\n\tPolicyFunctionArguments,\n\tPolicyHandlerResult,\n} from \"../policy.js\";\n\nconst { readFile: readJson } = jsonfile;\n\n/**\n * A policy handler especially for policies that target package.json.\n *\n * @alpha\n */\nexport type PackageJsonHandler<J, C> = (\n\tjson: J,\n\targs: PolicyFunctionArguments<C>,\n) => Promise<PolicyHandlerResult>;\n\n/**\n * Define a repo policy for package.json files.\n *\n * @alpha\n */\nexport function definePackagePolicy<J = PackageJson, C = undefined>(\n\tname: string,\n\tpackagePolicy: PackageJsonHandler<J, C>,\n\t// args: PolicyFunctionArguments<C>,\n): PolicyDefinition<C> {\n\t// const func = () => handler(json, args);\n\treturn {\n\t\tname,\n\t\tmatch: PackageJsonRegexMatch,\n\t\thandler: async (innerArgs) => {\n\t\t\tconst json: J = await readJson(resolve(innerArgs.root, innerArgs.file));\n\t\t\treturn packagePolicy(json, innerArgs);\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"definePackagePolicy.js","sourceRoot":"","sources":["../../src/policyDefiners/definePackagePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAkB,MAAM,WAAW,CAAC;AACjD,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAOjE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC;AAmBxC;;GAEG;AACH,SAAS,WAAW,CAAI,KAAc;IACrC,OAAO,CACN,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,MAAM,IAAI,KAAK;QACf,OAAQ,KAA2B,CAAC,IAAI,KAAK,UAAU,CACvD,CAAC;AACH,CAAC;AA6BD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,mBAAmB,CAClC,IAAmC;IAEnC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IAC3E,OAAO;QACN,IAAI;QACJ,WAAW;QACX,KAAK,EAAE,qBAAqB;QAC5B,aAAa;QACb,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS;YAC5B,MAAM,IAAI,GAAM,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAChC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CACjD,CAAC;YACF,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAE/C,6DAA6D;YAC7D,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;gBAC/B,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;YAClC,CAAC;YACD,mDAAmD;YACnD,IAAI,WAAW,CAAsB,MAAM,CAAC,EAAE,CAAC;gBAC9C,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC;YACtB,CAAC;YACD,sDAAsD;YACtD,MAAM,IAAI,KAAK,CAAC,mCAAmC,OAAO,MAAM,EAAE,CAAC,CAAC;QACrE,CAAC;KACD,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,mBAAmB,CAAC","sourcesContent":["import { call, type Operation } from \"effection\";\nimport jsonfile from \"jsonfile\";\nimport { resolve } from \"pathe\";\nimport type { PackageJson } from \"type-fest\";\nimport { PackageJsonRegexMatch } from \"../policies/constants.js\";\nimport type {\n\tPolicyArgs,\n\tPolicyHandlerResult,\n\tPolicyShape,\n} from \"../policy.js\";\n\nconst { readFile: readJson } = jsonfile;\n\n/**\n * A policy handler especially for policies that target package.json.\n *\n * @remarks\n * Package JSON handlers can be implemented in two ways:\n * - As an async function returning a Promise\n * - As an Effection generator function returning an Operation\n *\n * Both styles are supported to allow gradual migration and flexibility.\n *\n * @alpha\n */\nexport type PackageJsonHandler<J, C> = (\n\tjson: J,\n\targs: PolicyArgs<C>,\n) => Operation<PolicyHandlerResult> | Promise<PolicyHandlerResult>;\n\n/**\n * Type guard to check if a value is an Effection Operation (generator).\n */\nfunction isOperation<T>(value: unknown): value is Operation<T> {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"next\" in value &&\n\t\ttypeof (value as { next: unknown }).next === \"function\"\n\t);\n}\n\n/**\n * Input arguments for defining a package.json policy.\n *\n * @alpha\n */\nexport interface DefinePackagePolicyArgs<J, C> {\n\t/**\n\t * The name of the policy.\n\t */\n\tname: string;\n\n\t/**\n\t * A description of the policy's purpose.\n\t */\n\tdescription: string;\n\n\t/**\n\t * The handler function that receives the parsed package.json and policy arguments.\n\t */\n\thandler: PackageJsonHandler<J, C>;\n\n\t/**\n\t * Optional default configuration for the policy.\n\t */\n\tdefaultConfig?: C;\n}\n\n/**\n * Define a repo policy for package.json files.\n *\n * @remarks\n * This is a helper function that creates a policy pre-configured to match\n * package.json files. The handler receives the parsed JSON content.\n *\n * @example\n * ```typescript\n * const MyPackagePolicy = definePackagePolicy({\n * name: \"MyPackagePolicy\",\n * description: \"Ensures package.json has required fields\",\n * handler: async (json, { file }) => {\n * if (!json.name) {\n * return { error: \"Missing name\", fixable: false };\n * }\n * return true;\n * },\n * });\n * ```\n *\n * @alpha\n */\nexport function definePackagePolicy<J = PackageJson, C = undefined>(\n\targs: DefinePackagePolicyArgs<J, C>,\n): PolicyShape<C> {\n\tconst { name, description, handler: packageHandler, defaultConfig } = args;\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\tmatch: PackageJsonRegexMatch,\n\t\tdefaultConfig,\n\t\thandler: function* (innerArgs) {\n\t\t\tconst json: J = yield* call(() =>\n\t\t\t\treadJson(resolve(innerArgs.root, innerArgs.file)),\n\t\t\t);\n\t\t\tconst result = packageHandler(json, innerArgs);\n\n\t\t\t// Handle both Operation (generator) and Promise return types\n\t\t\tif (result instanceof Promise) {\n\t\t\t\treturn yield* call(() => result);\n\t\t\t}\n\t\t\t// Check if it's an Effection Operation (generator)\n\t\t\tif (isOperation<PolicyHandlerResult>(result)) {\n\t\t\t\treturn yield* result;\n\t\t\t}\n\t\t\t// This should never happen with proper handler typing\n\t\t\tthrow new Error(`Unexpected handler result type: ${typeof result}`);\n\t\t},\n\t};\n}\n\n/**\n * Alias for definePackagePolicy.\n * @alpha\n */\nexport const packagePolicy = definePackagePolicy;\n"]}
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.55.1"
8
+ "packageVersion": "7.56.0"
9
9
  }
10
10
  ]
11
11
  }
@@ -125,5 +125,5 @@
125
125
  ]
126
126
  }
127
127
  },
128
- "version": "0.8.0"
128
+ "version": "0.10.0"
129
129
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repopo",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Enforce policies on all or some of the files in a git repository.",
5
5
  "keywords": [
6
6
  "policy",
@@ -67,6 +67,7 @@
67
67
  "@rushstack/node-core-library": "^5.19.0",
68
68
  "consola": "^3.4.0",
69
69
  "defu": "^6.1.4",
70
+ "effection": "^4.0.0",
70
71
  "jsonfile": "^6.2.0",
71
72
  "microdiff": "^1.5.0",
72
73
  "pathe": "^2.0.3",
@@ -75,12 +76,12 @@
75
76
  "resolve-workspace-root": "^2.0.0",
76
77
  "simple-git": "^3.30.0",
77
78
  "tinyglobby": "^0.2.15",
78
- "@tylerbu/cli-api": "^0.10.0",
79
+ "@tylerbu/cli-api": "^0.10.1",
79
80
  "@tylerbu/fundamentals": "^0.3.0"
80
81
  },
81
82
  "devDependencies": {
82
83
  "@biomejs/biome": "2.3.8",
83
- "@microsoft/api-extractor": "^7.55.1",
84
+ "@microsoft/api-extractor": "^7.56.0",
84
85
  "@oclif/plugin-command-snapshot": "^5.3.8",
85
86
  "@oclif/test": "^4.1.15",
86
87
  "@types/jsonfile": "^6.1.4",
@@ -135,6 +136,7 @@
135
136
  "release:license": "generate-license-file -c ../../.generatelicensefile.cjs",
136
137
  "test": "vitest run",
137
138
  "test:coverage": "vitest run --coverage",
138
- "test:snapshots": "./bin/dev.js snapshot:compare --filepath test/commands/__snapshots__/commands.json"
139
+ "test:snapshots": "./bin/dev.js snapshot:compare --filepath test/commands/__snapshots__/commands.json",
140
+ "test:watch": "vitest"
139
141
  }
140
142
  }