repopo 0.7.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/CHANGELOG.md +217 -6
  2. package/THIRD-PARTY-LICENSES.txt +152 -5
  3. package/esm/adapters/fluidFramework.d.ts +103 -0
  4. package/esm/adapters/fluidFramework.d.ts.map +1 -0
  5. package/esm/adapters/fluidFramework.js +124 -0
  6. package/esm/adapters/fluidFramework.js.map +1 -0
  7. package/esm/baseCommand.d.ts +1 -0
  8. package/esm/baseCommand.d.ts.map +1 -1
  9. package/esm/baseCommand.js +2 -0
  10. package/esm/baseCommand.js.map +1 -1
  11. package/esm/commands/check.d.ts.map +1 -1
  12. package/esm/commands/check.js +76 -50
  13. package/esm/commands/check.js.map +1 -1
  14. package/esm/commands/list.d.ts.map +1 -1
  15. package/esm/commands/list.js +3 -1
  16. package/esm/commands/list.js.map +1 -1
  17. package/esm/generators.d.ts +30 -2
  18. package/esm/generators.d.ts.map +1 -1
  19. package/esm/generators.js +31 -1
  20. package/esm/generators.js.map +1 -1
  21. package/esm/index.d.ts +14 -3
  22. package/esm/index.d.ts.map +1 -1
  23. package/esm/index.js +13 -2
  24. package/esm/index.js.map +1 -1
  25. package/esm/makePolicy.d.ts +31 -2
  26. package/esm/makePolicy.d.ts.map +1 -1
  27. package/esm/makePolicy.js +27 -13
  28. package/esm/makePolicy.js.map +1 -1
  29. package/esm/perf.d.ts +6 -2
  30. package/esm/perf.d.ts.map +1 -1
  31. package/esm/perf.js +5 -4
  32. package/esm/perf.js.map +1 -1
  33. package/esm/policies/HtmlFileHeaders.d.ts.map +1 -1
  34. package/esm/policies/HtmlFileHeaders.js +11 -7
  35. package/esm/policies/HtmlFileHeaders.js.map +1 -1
  36. package/esm/policies/JsTsFileHeaders.d.ts.map +1 -1
  37. package/esm/policies/JsTsFileHeaders.js +11 -7
  38. package/esm/policies/JsTsFileHeaders.js.map +1 -1
  39. package/esm/policies/LicenseFileExists.d.ts.map +1 -1
  40. package/esm/policies/LicenseFileExists.js +22 -16
  41. package/esm/policies/LicenseFileExists.js.map +1 -1
  42. package/esm/policies/NoJsFileExtensions.d.ts.map +1 -1
  43. package/esm/policies/NoJsFileExtensions.js +16 -9
  44. package/esm/policies/NoJsFileExtensions.js.map +1 -1
  45. package/esm/policies/NoLargeBinaryFiles.d.ts.map +1 -1
  46. package/esm/policies/NoLargeBinaryFiles.js +35 -29
  47. package/esm/policies/NoLargeBinaryFiles.js.map +1 -1
  48. package/esm/policies/NoPrivateWorkspaceDependencies.d.ts +37 -0
  49. package/esm/policies/NoPrivateWorkspaceDependencies.d.ts.map +1 -0
  50. package/esm/policies/NoPrivateWorkspaceDependencies.js +145 -0
  51. package/esm/policies/NoPrivateWorkspaceDependencies.js.map +1 -0
  52. package/esm/policies/PackageAllowedScopes.d.ts +88 -0
  53. package/esm/policies/PackageAllowedScopes.d.ts.map +1 -0
  54. package/esm/policies/PackageAllowedScopes.js +118 -0
  55. package/esm/policies/PackageAllowedScopes.js.map +1 -0
  56. package/esm/policies/PackageEsmType.d.ts +100 -0
  57. package/esm/policies/PackageEsmType.d.ts.map +1 -0
  58. package/esm/policies/PackageEsmType.js +261 -0
  59. package/esm/policies/PackageEsmType.js.map +1 -0
  60. package/esm/policies/PackageFolderName.d.ts +97 -0
  61. package/esm/policies/PackageFolderName.d.ts.map +1 -0
  62. package/esm/policies/PackageFolderName.js +108 -0
  63. package/esm/policies/PackageFolderName.js.map +1 -0
  64. package/esm/policies/PackageJsonProperties.d.ts.map +1 -1
  65. package/esm/policies/PackageJsonProperties.js +36 -30
  66. package/esm/policies/PackageJsonProperties.js.map +1 -1
  67. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts.map +1 -1
  68. package/esm/policies/PackageJsonRepoDirectoryProperty.js +41 -37
  69. package/esm/policies/PackageJsonRepoDirectoryProperty.js.map +1 -1
  70. package/esm/policies/PackageJsonSorted.d.ts.map +1 -1
  71. package/esm/policies/PackageJsonSorted.js +40 -28
  72. package/esm/policies/PackageJsonSorted.js.map +1 -1
  73. package/esm/policies/PackageLicense.d.ts +61 -0
  74. package/esm/policies/PackageLicense.d.ts.map +1 -0
  75. package/esm/policies/PackageLicense.js +135 -0
  76. package/esm/policies/PackageLicense.js.map +1 -0
  77. package/esm/policies/PackagePrivateField.d.ts +124 -0
  78. package/esm/policies/PackagePrivateField.d.ts.map +1 -0
  79. package/esm/policies/PackagePrivateField.js +159 -0
  80. package/esm/policies/PackagePrivateField.js.map +1 -0
  81. package/esm/policies/PackageReadme.d.ts +77 -0
  82. package/esm/policies/PackageReadme.d.ts.map +1 -0
  83. package/esm/policies/PackageReadme.js +213 -0
  84. package/esm/policies/PackageReadme.js.map +1 -0
  85. package/esm/policies/PackageScripts.d.ts +180 -2
  86. package/esm/policies/PackageScripts.d.ts.map +1 -1
  87. package/esm/policies/PackageScripts.js +358 -34
  88. package/esm/policies/PackageScripts.js.map +1 -1
  89. package/esm/policies/PackageTestScripts.d.ts +100 -0
  90. package/esm/policies/PackageTestScripts.d.ts.map +1 -0
  91. package/esm/policies/PackageTestScripts.js +155 -0
  92. package/esm/policies/PackageTestScripts.js.map +1 -0
  93. package/esm/policies/RequiredGitignorePatterns.d.ts.map +1 -1
  94. package/esm/policies/RequiredGitignorePatterns.js +30 -19
  95. package/esm/policies/RequiredGitignorePatterns.js.map +1 -1
  96. package/esm/policies.d.ts +9 -1
  97. package/esm/policies.d.ts.map +1 -1
  98. package/esm/policies.js +10 -1
  99. package/esm/policies.js.map +1 -1
  100. package/esm/policy.d.ts +37 -8
  101. package/esm/policy.d.ts.map +1 -1
  102. package/esm/policy.js +18 -9
  103. package/esm/policy.js.map +1 -1
  104. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts +43 -1
  105. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts.map +1 -1
  106. package/esm/policyDefiners/defineFileHeaderPolicy.js +18 -5
  107. package/esm/policyDefiners/defineFileHeaderPolicy.js.map +1 -1
  108. package/esm/policyDefiners/definePackagePolicy.d.ts +43 -2
  109. package/esm/policyDefiners/definePackagePolicy.d.ts.map +1 -1
  110. package/esm/policyDefiners/definePackagePolicy.js +41 -5
  111. package/esm/policyDefiners/definePackagePolicy.js.map +1 -1
  112. package/esm/tsdoc-metadata.json +1 -1
  113. package/esm/utils/indentation.d.ts +73 -0
  114. package/esm/utils/indentation.d.ts.map +1 -0
  115. package/esm/utils/indentation.js +97 -0
  116. package/esm/utils/indentation.js.map +1 -0
  117. package/esm/utils/packageName.d.ts +71 -0
  118. package/esm/utils/packageName.d.ts.map +1 -0
  119. package/esm/utils/packageName.js +79 -0
  120. package/esm/utils/packageName.js.map +1 -0
  121. package/oclif.manifest.json +1 -1
  122. package/package.json +33 -16
package/esm/policy.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { Operation } from "effection";
2
+ import type { RequireExactlyOne } from "type-fest";
1
3
  /**
2
4
  * A type representing a policy name.
3
5
  *
@@ -30,17 +32,31 @@ export interface PolicyFunctionArguments<C> {
30
32
  config?: C | undefined;
31
33
  }
32
34
  /**
33
- * A policy handler is a function that is called to check policy against a file.
35
+ * A policy handler function that is called to check policy against a file.
36
+ *
37
+ * @remarks
38
+ * Policy handlers can be implemented in two ways:
39
+ * - As an async function returning a Promise
40
+ * - As an Effection generator function returning an Operation
41
+ *
42
+ * Both styles are supported to allow gradual migration and flexibility.
34
43
  *
35
44
  * @alpha
36
45
  */
37
- export type PolicyHandler<C = unknown | undefined> = (args: PolicyFunctionArguments<C>) => Promise<PolicyHandlerResult>;
46
+ export type PolicyHandler<C = unknown | undefined> = ((args: PolicyFunctionArguments<C>) => Promise<PolicyHandlerResult>) | ((args: PolicyFunctionArguments<C>) => Operation<PolicyHandlerResult>);
38
47
  /**
39
48
  * A standalone function that can be called to resolve a policy failure.
40
49
  *
50
+ * @remarks
51
+ * Resolvers can be implemented in two ways:
52
+ * - As an async function returning a Promise
53
+ * - As an Effection generator function returning an Operation
54
+ *
55
+ * Both styles are supported to allow gradual migration and flexibility.
56
+ *
41
57
  * @alpha
42
58
  */
43
- export type PolicyStandaloneResolver<C = undefined> = (args: Omit<PolicyFunctionArguments<C>, "resolve">) => Promise<PolicyFixResult>;
59
+ export type PolicyStandaloneResolver<C = undefined> = (args: Omit<PolicyFunctionArguments<C>, "resolve">) => Promise<PolicyFixResult> | Operation<PolicyFixResult>;
44
60
  /**
45
61
  * A RepoPolicyDefinition checks and applies policies to files in the repository.
46
62
  *
@@ -62,7 +78,7 @@ export interface PolicyDefinition<C = undefined> {
62
78
  /**
63
79
  * A more detailed description of the policy and its intended function.
64
80
  */
65
- description?: string | undefined;
81
+ description: string;
66
82
  /**
67
83
  * A regular expression that is used to match files in the repo.
68
84
  */
@@ -108,7 +124,7 @@ export interface PolicyInstanceSettings<C> {
108
124
  /**
109
125
  * @alpha
110
126
  */
111
- export type PolicyInstance<C = undefined> = PolicyDefinition<C> & PolicyInstanceSettings<C>;
127
+ export type PolicyInstance<C = undefined> = RequireExactlyOne<PolicyDefinition<C> & PolicyInstanceSettings<C>, "handler">;
112
128
  /**
113
129
  * A policy failure.
114
130
  *
@@ -130,7 +146,11 @@ export interface PolicyFailure {
130
146
  /**
131
147
  * An optional error message accompanying the failure.
132
148
  */
133
- errorMessage?: string | undefined;
149
+ errorMessages: string[];
150
+ /**
151
+ * An optional string that tells the user how to fix the failure(s).
152
+ */
153
+ manualFix?: string;
134
154
  }
135
155
  /**
136
156
  * The result of an automatic fix for a failing policy.
@@ -154,13 +174,22 @@ export declare function isPolicyFixResult(toCheck: any): toCheck is PolicyFixRes
154
174
  * @alpha
155
175
  */
156
176
  export declare const DefaultPolicies: PolicyDefinition<any>[];
177
+ /**
178
+ * Abstract base class for creating policies with object-based construction.
179
+ *
180
+ * @remarks
181
+ * This class accepts a {@link PolicyDefinition} object in its constructor,
182
+ * making it easier to add new optional properties in the future without breaking changes.
183
+ *
184
+ * @alpha
185
+ */
157
186
  export declare abstract class Policy<C> implements PolicyDefinition<C> {
158
187
  readonly name: string;
188
+ readonly description: string;
159
189
  readonly match: RegExp;
160
190
  readonly handler: PolicyHandler<C>;
161
- readonly description?: string | undefined;
162
191
  readonly defaultConfig?: C | undefined;
163
192
  readonly resolver?: PolicyStandaloneResolver<C> | undefined;
164
- constructor(name: string, match: RegExp, handler: PolicyHandler<C>, description?: string | undefined, defaultConfig?: C | undefined, resolver?: PolicyStandaloneResolver<C> | undefined);
193
+ constructor(definition: PolicyDefinition<C>);
165
194
  }
166
195
  //# sourceMappingURL=policy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
package/esm/policy.js CHANGED
@@ -4,7 +4,7 @@ import { PackageJsonSorted } from "./policies/PackageJsonSorted.js";
4
4
  import { PackageScripts } from "./policies/PackageScripts.js";
5
5
  // biome-ignore lint/suspicious/noExplicitAny: type guard
6
6
  export function isPolicyFixResult(toCheck) {
7
- if (typeof toCheck !== "object") {
7
+ if (typeof toCheck !== "object" || toCheck === null) {
8
8
  return false;
9
9
  }
10
10
  return "resolved" in toCheck;
@@ -21,20 +21,29 @@ export const DefaultPolicies = [
21
21
  PackageJsonSorted,
22
22
  PackageScripts,
23
23
  ];
24
+ /**
25
+ * Abstract base class for creating policies with object-based construction.
26
+ *
27
+ * @remarks
28
+ * This class accepts a {@link PolicyDefinition} object in its constructor,
29
+ * making it easier to add new optional properties in the future without breaking changes.
30
+ *
31
+ * @alpha
32
+ */
24
33
  export class Policy {
25
34
  name;
35
+ description;
26
36
  match;
27
37
  handler;
28
- description;
29
38
  defaultConfig;
30
39
  resolver;
31
- constructor(name, match, handler, description, defaultConfig, resolver) {
32
- this.name = name;
33
- this.match = match;
34
- this.handler = handler;
35
- this.description = description;
36
- this.defaultConfig = defaultConfig;
37
- this.resolver = resolver;
40
+ constructor(definition) {
41
+ this.name = definition.name;
42
+ this.description = definition.description;
43
+ this.match = definition.match;
44
+ this.handler = definition.handler;
45
+ this.defaultConfig = definition.defaultConfig;
46
+ this.resolver = definition.resolver;
38
47
  }
39
48
  }
40
49
  //# sourceMappingURL=policy.js.map
package/esm/policy.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,gCAAgC,EAAE,MAAM,gDAAgD,CAAC;AAClG,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AA4L9D,yDAAyD;AACzD,MAAM,UAAU,iBAAiB,CAAC,OAAY;IAC7C,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,UAAU,IAAI,OAAO,CAAC;AAC9B,CAAC;AAED;;;;GAIG;AAEH,oDAAoD;AACpD,MAAM,CAAC,MAAM,eAAe,GAA4B;IACvD,kBAAkB;IAClB,gCAAgC;IAChC,iBAAiB;IACjB,cAAc;CACL,CAAC;AAEX,MAAM,OAAgB,MAAM;IAEV;IACA;IACA;IACA;IACA;IACA;IANjB,YACiB,IAAY,EACZ,KAAa,EACb,OAAyB,EACzB,WAAoB,EACpB,aAAiB,EACjB,QAAsC;QALtC,SAAI,GAAJ,IAAI,CAAQ;QACZ,UAAK,GAAL,KAAK,CAAQ;QACb,YAAO,GAAP,OAAO,CAAkB;QACzB,gBAAW,GAAX,WAAW,CAAS;QACpB,kBAAa,GAAb,aAAa,CAAI;QACjB,aAAQ,GAAR,QAAQ,CAA8B;IACpD,CAAC;CACJ","sourcesContent":["import { NoJsFileExtensions } from \"./policies/NoJsFileExtensions.js\";\nimport { PackageJsonRepoDirectoryProperty } from \"./policies/PackageJsonRepoDirectoryProperty.js\";\nimport { PackageJsonSorted } from \"./policies/PackageJsonSorted.js\";\nimport { PackageScripts } from \"./policies/PackageScripts.js\";\n\n/**\n * A type representing a policy name.\n *\n * @alpha\n */\nexport type PolicyName = string;\n\n/**\n * Arguments passed to policy functions.\n *\n * @alpha\n */\n\nexport interface PolicyFunctionArguments<C> {\n\t/**\n\t * Path to the file, relative to the repo root.\n\t */\n\tfile: string;\n\n\t/**\n\t * Absolute path to the root of the repo.\n\t */\n\troot: string;\n\n\t/**\n\t * If true, the handler should resolve any violations automatically if possible.\n\t */\n\tresolve: boolean;\n\n\t/**\n\t * @remarks\n\t *\n\t * Note that the handler function receives the config as an argument.\n\t */\n\tconfig?: C | undefined;\n}\n\n/**\n * A policy handler is a function that is called to check policy against a file.\n *\n * @alpha\n */\n\nexport type PolicyHandler<C = unknown | undefined> = (\n\targs: PolicyFunctionArguments<C>,\n) => Promise<PolicyHandlerResult>;\n\n// export type PolicyCheckOnly = (\n// \tfile: string,\n// \troot: string,\n// ) => Promise<PolicyHandlerResult>;\n\n/**\n * A standalone function that can be called to resolve a policy failure.\n *\n * @alpha\n */\nexport type PolicyStandaloneResolver<C = undefined> = (\n\targs: Omit<PolicyFunctionArguments<C>, \"resolve\">,\n) => Promise<PolicyFixResult>;\n\n// function isPolicyHandler(input: PolicyHandler | PolicyCheckOnly): input is PolicyHandler\n\n/**\n * A RepoPolicyDefinition checks and applies policies to files in the repository.\n *\n * Each policy has a name and a match regex for matching which files it should apply to. Every file in th repo is\n * enumerated and if it matches the regex for a policy, that policy is applied.\n *\n * Each policy includes a handler function that checks a file against the policy and can optionally resolve any problems\n * (automated resolutions depend on the policy implementation).\n *\n * @typeParam C - type of configuration object used by the policy\n *\n * @alpha\n */\nexport interface PolicyDefinition<C = undefined> {\n\t/**\n\t * The name of the policy; displayed in UI and used in settings.\n\t */\n\tname: PolicyName;\n\n\t/**\n\t * A more detailed description of the policy and its intended function.\n\t */\n\tdescription?: string | undefined;\n\n\t/**\n\t * A regular expression that is used to match files in the repo.\n\t */\n\tmatch: RegExp;\n\n\t/**\n\t * A handler function that checks if a file is compliant with the policy.\n\t *\n\t * @param file - Repo-relative path to the file to check.\n\t * @param root - Absolute path to the root of the repo.\n\t * @param resolve - If true, automated policy fixes will be applied. Not all policies support automated fixes.\n\t * @returns True if the file passed the policy; otherwise a PolicyFailure object will be returned.\n\t */\n\n\thandler: PolicyHandler<C>;\n\n\t/**\n\t * A resolver function that can be used to automatically address the policy violation.\n\t *\n\t * @param file - Repo-relative path to the file to check.\n\t * @param root - Absolute path to the root of the repo.\n\t * @returns true if the file passed the policy; otherwise a PolicyFailure object will be returned.\n\t */\n\tresolver?: PolicyStandaloneResolver<C> | undefined;\n\n\t/**\n\t * A default config that will be used if none is provided.\n\t */\n\tdefaultConfig?: C | undefined;\n}\n\n/**\n * @alpha\n */\nexport interface PolicyInstanceSettings<C> {\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\t * Paths will be matched relative to the root of the repo.\n\t */\n\texcludeFiles?: (string | RegExp)[];\n\n\t/**\n\t * The config that is applied to the policy instance.\n\t */\n\tconfig?: C | undefined;\n}\n\n/**\n * @alpha\n */\nexport type PolicyInstance<C = undefined> = PolicyDefinition<C> &\n\tPolicyInstanceSettings<C>;\n\n/**\n * A policy failure.\n *\n * @alpha\n */\nexport interface PolicyFailure {\n\t/**\n\t * Name of the policy that failed.\n\t */\n\tname: PolicyName;\n\n\t/**\n\t * Path to the file that failed the policy.\n\t */\n\tfile: string;\n\n\t/**\n\t * Set to `true` if the policy can be fixed automatically.\n\t */\n\tautoFixable?: boolean | undefined;\n\n\t/**\n\t * An optional error message accompanying the failure.\n\t */\n\terrorMessage?: string | undefined;\n}\n\n/**\n * The result of an automatic fix for a failing policy.\n *\n * @alpha\n */\nexport interface PolicyFixResult extends PolicyFailure {\n\t/**\n\t * Set to true if the failure was resolved by the automated fixer.\n\t */\n\tresolved: boolean;\n}\n\n/**\n * @alpha\n */\nexport type PolicyHandlerResult = true | PolicyFailure | PolicyFixResult;\n\n// biome-ignore lint/suspicious/noExplicitAny: type guard\nexport function isPolicyFixResult(toCheck: any): toCheck is PolicyFixResult {\n\tif (typeof toCheck !== \"object\") {\n\t\treturn false;\n\t}\n\treturn \"resolved\" in toCheck;\n}\n\n/**\n * Default policies included with repopo.\n *\n * @alpha\n */\n\n// biome-ignore lint/suspicious/noExplicitAny: FIXME\nexport const DefaultPolicies: PolicyDefinition<any>[] = [\n\tNoJsFileExtensions,\n\tPackageJsonRepoDirectoryProperty,\n\tPackageJsonSorted,\n\tPackageScripts,\n] as const;\n\nexport abstract class Policy<C> implements PolicyDefinition<C> {\n\tpublic constructor(\n\t\tpublic readonly name: string,\n\t\tpublic readonly match: RegExp,\n\t\tpublic readonly handler: PolicyHandler<C>,\n\t\tpublic readonly description?: string,\n\t\tpublic readonly defaultConfig?: C,\n\t\tpublic readonly resolver?: PolicyStandaloneResolver<C>,\n\t) {}\n}\n"]}
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,gCAAgC,EAAE,MAAM,gDAAgD,CAAC;AAClG,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAyM9D,yDAAyD;AACzD,MAAM,UAAU,iBAAiB,CAAC,OAAY;IAC7C,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrD,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,UAAU,IAAI,OAAO,CAAC;AAC9B,CAAC;AAED;;;;GAIG;AAEH,oDAAoD;AACpD,MAAM,CAAC,MAAM,eAAe,GAA4B;IACvD,kBAAkB;IAClB,gCAAgC;IAChC,iBAAiB;IACjB,cAAc;CACL,CAAC;AAEX;;;;;;;;GAQG;AACH,MAAM,OAAgB,MAAM;IACX,IAAI,CAAS;IACb,WAAW,CAAS;IACpB,KAAK,CAAS;IACd,OAAO,CAAmB;IAC1B,aAAa,CAAiB;IAC9B,QAAQ,CAA2C;IAEnE,YAAmB,UAA+B;QACjD,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC;QAC5B,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC,WAAW,CAAC;QAC1C,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC;QAC9B,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC;QAClC,IAAI,CAAC,aAAa,GAAG,UAAU,CAAC,aAAa,CAAC;QAC9C,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC;IACrC,CAAC;CACD","sourcesContent":["import type { Operation } from \"effection\";\nimport type { RequireExactlyOne } from \"type-fest\";\nimport { NoJsFileExtensions } from \"./policies/NoJsFileExtensions.js\";\nimport { PackageJsonRepoDirectoryProperty } from \"./policies/PackageJsonRepoDirectoryProperty.js\";\nimport { PackageJsonSorted } from \"./policies/PackageJsonSorted.js\";\nimport { PackageScripts } from \"./policies/PackageScripts.js\";\n\n/**\n * A type representing a policy name.\n *\n * @alpha\n */\nexport type PolicyName = string;\n\n/**\n * Arguments passed to policy functions.\n *\n * @alpha\n */\n\nexport interface PolicyFunctionArguments<C> {\n\t/**\n\t * Path to the file, relative to the repo root.\n\t */\n\tfile: string;\n\n\t/**\n\t * Absolute path to the root of the repo.\n\t */\n\troot: string;\n\n\t/**\n\t * If true, the handler should resolve any violations automatically if possible.\n\t */\n\tresolve: boolean;\n\n\t/**\n\t * @remarks\n\t *\n\t * Note that the handler function receives the config as an argument.\n\t */\n\tconfig?: C | undefined;\n}\n\n/**\n * A policy handler function that is called to check policy against a file.\n *\n * @remarks\n * Policy 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 PolicyHandler<C = unknown | undefined> =\n\t| ((args: PolicyFunctionArguments<C>) => Promise<PolicyHandlerResult>)\n\t| ((args: PolicyFunctionArguments<C>) => Operation<PolicyHandlerResult>);\n\n/**\n * A standalone function that can be called to resolve a policy failure.\n *\n * @remarks\n * Resolvers 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 PolicyStandaloneResolver<C = undefined> = (\n\targs: Omit<PolicyFunctionArguments<C>, \"resolve\">,\n) => Promise<PolicyFixResult> | Operation<PolicyFixResult>;\n\n/**\n * A RepoPolicyDefinition checks and applies policies to files in the repository.\n *\n * Each policy has a name and a match regex for matching which files it should apply to. Every file in th repo is\n * enumerated and if it matches the regex for a policy, that policy is applied.\n *\n * Each policy includes a handler function that checks a file against the policy and can optionally resolve any problems\n * (automated resolutions depend on the policy implementation).\n *\n * @typeParam C - type of configuration object used by the policy\n *\n * @alpha\n */\nexport interface PolicyDefinition<C = undefined> {\n\t/**\n\t * The name of the policy; displayed in UI and used in settings.\n\t */\n\tname: PolicyName;\n\n\t/**\n\t * A more detailed description of the policy and its intended function.\n\t */\n\tdescription: string;\n\n\t/**\n\t * A regular expression that is used to match files in the repo.\n\t */\n\tmatch: RegExp;\n\n\t/**\n\t * A handler function that checks if a file is compliant with the policy.\n\t *\n\t * @param file - Repo-relative path to the file to check.\n\t * @param root - Absolute path to the root of the repo.\n\t * @param resolve - If true, automated policy fixes will be applied. Not all policies support automated fixes.\n\t * @returns True if the file passed the policy; otherwise a PolicyFailure object will be returned.\n\t */\n\n\thandler: PolicyHandler<C>;\n\n\t/**\n\t * A resolver function that can be used to automatically address the policy violation.\n\t *\n\t * @param file - Repo-relative path to the file to check.\n\t * @param root - Absolute path to the root of the repo.\n\t * @returns true if the file passed the policy; otherwise a PolicyFailure object will be returned.\n\t */\n\tresolver?: PolicyStandaloneResolver<C> | undefined;\n\n\t/**\n\t * A default config that will be used if none is provided.\n\t */\n\tdefaultConfig?: C | undefined;\n}\n\n/**\n * @alpha\n */\nexport interface PolicyInstanceSettings<C> {\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\t * Paths will be matched relative to the root of the repo.\n\t */\n\texcludeFiles?: (string | RegExp)[];\n\n\t/**\n\t * The config that is applied to the policy instance.\n\t */\n\tconfig?: C | undefined;\n}\n\n/**\n * @alpha\n */\nexport type PolicyInstance<C = undefined> = RequireExactlyOne<\n\tPolicyDefinition<C> & PolicyInstanceSettings<C>,\n\t\"handler\"\n>;\n\n/**\n * A policy failure.\n *\n * @alpha\n */\nexport interface PolicyFailure {\n\t/**\n\t * Name of the policy that failed.\n\t */\n\tname: PolicyName;\n\n\t/**\n\t * Path to the file that failed the policy.\n\t */\n\tfile: string;\n\n\t/**\n\t * Set to `true` if the policy can be fixed automatically.\n\t */\n\tautoFixable?: boolean | undefined;\n\n\t/**\n\t * An optional error message accompanying the failure.\n\t */\n\terrorMessages: string[];\n\n\t/**\n\t * An optional string that tells the user how to fix the failure(s).\n\t */\n\tmanualFix?: string;\n}\n\n/**\n * The result of an automatic fix for a failing policy.\n *\n * @alpha\n */\nexport interface PolicyFixResult extends PolicyFailure {\n\t/**\n\t * Set to true if the failure was resolved by the automated fixer.\n\t */\n\tresolved: boolean;\n}\n\n/**\n * @alpha\n */\nexport type PolicyHandlerResult = true | PolicyFailure | PolicyFixResult;\n\n// biome-ignore lint/suspicious/noExplicitAny: type guard\nexport function isPolicyFixResult(toCheck: any): toCheck is PolicyFixResult {\n\tif (typeof toCheck !== \"object\" || toCheck === null) {\n\t\treturn false;\n\t}\n\treturn \"resolved\" in toCheck;\n}\n\n/**\n * Default policies included with repopo.\n *\n * @alpha\n */\n\n// biome-ignore lint/suspicious/noExplicitAny: FIXME\nexport const DefaultPolicies: PolicyDefinition<any>[] = [\n\tNoJsFileExtensions,\n\tPackageJsonRepoDirectoryProperty,\n\tPackageJsonSorted,\n\tPackageScripts,\n] as const;\n\n/**\n * Abstract base class for creating policies with object-based construction.\n *\n * @remarks\n * This class accepts a {@link PolicyDefinition} object in its constructor,\n * making it easier to add new optional properties in the future without breaking changes.\n *\n * @alpha\n */\nexport abstract class Policy<C> implements PolicyDefinition<C> {\n\tpublic readonly name: string;\n\tpublic readonly description: string;\n\tpublic readonly match: RegExp;\n\tpublic readonly handler: PolicyHandler<C>;\n\tpublic readonly defaultConfig?: C | undefined;\n\tpublic readonly resolver?: PolicyStandaloneResolver<C> | undefined;\n\n\tpublic constructor(definition: PolicyDefinition<C>) {\n\t\tthis.name = definition.name;\n\t\tthis.description = definition.description;\n\t\tthis.match = definition.match;\n\t\tthis.handler = definition.handler;\n\t\tthis.defaultConfig = definition.defaultConfig;\n\t\tthis.resolver = definition.resolver;\n\t}\n}\n"]}
@@ -13,9 +13,16 @@ export interface FileHeaderPolicyConfig {
13
13
  autoGenText?: string;
14
14
  }
15
15
  /**
16
+ * Configuration for generating file headers with specific formatting rules.
17
+ *
18
+ * @remarks
19
+ * This interface extends FileHeaderPolicyConfig and adds formatting-specific
20
+ * properties to control how headers are inserted into different file types.
21
+ *
16
22
  * @alpha
17
23
  */
18
24
  export interface FileHeaderGeneratorConfig extends Partial<FileHeaderPolicyConfig> {
25
+ /** Regular expression that matches files this header generator applies to */
19
26
  match: RegExp;
20
27
  /**
21
28
  * Regex matching header prefix (e.g. `/*!\r?\n`)
@@ -33,13 +40,48 @@ export interface FileHeaderGeneratorConfig extends Partial<FileHeaderPolicyConfi
33
40
  * Regex matching the header postfix.
34
41
  */
35
42
  headerEnd?: RegExp;
43
+ /**
44
+ * Function that generates the properly formatted header content for insertion into files.
45
+ *
46
+ * @param content - The original file content
47
+ * @param config - The file header policy configuration
48
+ * @returns The formatted header string to insert
49
+ */
36
50
  replacer: (content: string, config: FileHeaderPolicyConfig) => string;
37
51
  }
52
+ /**
53
+ * Input arguments for defining a file header policy.
54
+ *
55
+ * @alpha
56
+ */
57
+ export interface DefineFileHeaderPolicyArgs {
58
+ /**
59
+ * The name of the policy.
60
+ */
61
+ name: string;
62
+ /**
63
+ * A description of the policy's purpose.
64
+ */
65
+ description: string;
66
+ /**
67
+ * Configuration for how headers are detected and inserted.
68
+ */
69
+ config: FileHeaderGeneratorConfig;
70
+ }
38
71
  /**
39
72
  * Given a {@link FileHeaderPolicyConfig}, produces a function that detects correct file headers
40
73
  * and returns an error string if the header is missing or incorrect.
41
74
  *
75
+ * @example
76
+ * ```typescript
77
+ * const MyHeaderPolicy = defineFileHeaderPolicy({
78
+ * name: "MyHeaderPolicy",
79
+ * description: "Ensures files have required headers",
80
+ * config: { match: /\.ts$/, lineStart: /\/\/ /, lineEnd: /\r?\n/, replacer: ... },
81
+ * });
82
+ * ```
83
+ *
42
84
  * @alpha
43
85
  */
44
- export declare function defineFileHeaderPolicy(name: string, config: FileHeaderGeneratorConfig): PolicyDefinition<FileHeaderPolicyConfig>;
86
+ export declare function defineFileHeaderPolicy(args: DefineFileHeaderPolicyArgs): PolicyDefinition<FileHeaderPolicyConfig>;
45
87
  //# sourceMappingURL=defineFileHeaderPolicy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"defineFileHeaderPolicy.d.ts","sourceRoot":"","sources":["../../src/policyDefiners/defineFileHeaderPolicy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACX,gBAAgB,EAGhB,MAAM,cAAc,CAAC;AAItB;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,yBAChB,SAAQ,OAAO,CAAC,sBAAsB,CAAC;IACvC,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB,KAAK,MAAM,CAAC;CACtE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACrC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,yBAAyB,GAC/B,gBAAgB,CAAC,sBAAsB,CAAC,CAiE1C"}
1
+ {"version":3,"file":"defineFileHeaderPolicy.d.ts","sourceRoot":"","sources":["../../src/policyDefiners/defineFileHeaderPolicy.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACX,gBAAgB,EAGhB,MAAM,cAAc,CAAC;AAItB;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,yBAChB,SAAQ,OAAO,CAAC,sBAAsB,CAAC;IACvC,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;OAMG;IACH,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB,KAAK,MAAM,CAAC;CACtE;AAED;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IAC1C;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,MAAM,EAAE,yBAAyB,CAAC;CAClC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACrC,IAAI,EAAE,0BAA0B,GAC9B,gBAAgB,CAAC,sBAAsB,CAAC,CAoE1C"}
@@ -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
  }
@@ -34,18 +46,19 @@ export function defineFileHeaderPolicy(name, config) {
34
46
  name,
35
47
  file,
36
48
  autoFixable: true,
49
+ errorMessages: [],
37
50
  };
38
51
  // TODO: Consider reading only the first 512B or so since headers are typically
39
52
  // at the beginning of the file.
40
- const content = await readFile(file, { encoding: "utf8" });
53
+ const content = yield* call(() => readFile(file, { encoding: "utf8" }));
41
54
  const failed = !regex.test(content);
42
55
  if (failed) {
43
- failResult.errorMessage = `${extname(file)} file missing header`;
56
+ failResult.errorMessages.push(`${extname(file)} file missing header`);
44
57
  }
45
58
  if (failed) {
46
59
  if (resolve) {
47
60
  const newContent = config.replacer(content, policyConfig);
48
- await writeFile(file, newContent);
61
+ yield* call(() => writeFile(file, newContent));
49
62
  const fixResult = {
50
63
  ...failResult,
51
64
  resolved: true,
@@ -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;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,YAAY,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC;YAClE,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};\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.errorMessage = `${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":"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","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 {\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 * 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): PolicyDefinition<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"]}
@@ -1,15 +1,56 @@
1
+ import { type Operation } from "effection";
1
2
  import type { PackageJson } from "type-fest";
2
3
  import type { PolicyDefinition, PolicyFunctionArguments, PolicyHandlerResult } 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
+ *
6
14
  * @alpha
7
15
  */
8
- export type PackageJsonHandler<J, C> = (json: J, args: PolicyFunctionArguments<C>) => Promise<PolicyHandlerResult>;
16
+ export type PackageJsonHandler<J, C> = (json: J, args: PolicyFunctionArguments<C>) => Operation<PolicyHandlerResult> | Promise<PolicyHandlerResult>;
17
+ /**
18
+ * Input arguments for defining a package.json policy.
19
+ *
20
+ * @alpha
21
+ */
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
+ }
9
36
  /**
10
37
  * Define a repo policy for package.json files.
11
38
  *
39
+ * @example
40
+ * ```typescript
41
+ * const MyPackagePolicy = definePackagePolicy({
42
+ * name: "MyPackagePolicy",
43
+ * description: "Ensures package.json has required fields",
44
+ * handler: function* (json, { file }) {
45
+ * if (!json.name) {
46
+ * return { name: "MyPackagePolicy", file, errorMessages: ["Missing name"] };
47
+ * }
48
+ * return true;
49
+ * },
50
+ * });
51
+ * ```
52
+ *
12
53
  * @alpha
13
54
  */
14
- export declare function definePackagePolicy<J = PackageJson, C = undefined>(name: string, packagePolicy: PackageJsonHandler<J, C>): PolicyDefinition<C>;
55
+ export declare function definePackagePolicy<J = PackageJson, C = undefined>(args: DefinePackagePolicyArgs<J, C>): PolicyDefinition<C>;
15
56
  //# sourceMappingURL=definePackagePolicy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"definePackagePolicy.d.ts","sourceRoot":"","sources":["../../src/policyDefiners/definePackagePolicy.ts"],"names":[],"mappings":"AACA,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,gBAAgB,EAChB,uBAAuB,EACvB,mBAAmB,EACnB,MAAM,cAAc,CAAC;AAItB;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI,CACtC,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,uBAAuB,CAAC,CAAC,CAAC,KAC5B,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;CAClC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,GAAG,WAAW,EAAE,CAAC,GAAG,SAAS,EACjE,IAAI,EAAE,uBAAuB,CAAC,CAAC,EAAE,CAAC,CAAC,GACjC,gBAAgB,CAAC,CAAC,CAAC,CAwBrB"}
@@ -1,19 +1,55 @@
1
+ import { call } from "effection";
1
2
  import jsonfile from "jsonfile";
3
+ import { resolve } from "pathe";
2
4
  import { PackageJsonRegexMatch } from "../policies/constants.js";
3
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
+ }
4
15
  /**
5
16
  * Define a repo policy for package.json files.
6
17
  *
18
+ * @example
19
+ * ```typescript
20
+ * const MyPackagePolicy = definePackagePolicy({
21
+ * name: "MyPackagePolicy",
22
+ * description: "Ensures package.json has required fields",
23
+ * handler: function* (json, { file }) {
24
+ * if (!json.name) {
25
+ * return { name: "MyPackagePolicy", file, errorMessages: ["Missing name"] };
26
+ * }
27
+ * return true;
28
+ * },
29
+ * });
30
+ * ```
31
+ *
7
32
  * @alpha
8
33
  */
9
- export function definePackagePolicy(name, packagePolicy) {
10
- // const func = () => handler(json, args);
34
+ export function definePackagePolicy(args) {
35
+ const { name, description, handler: packagePolicy } = args;
11
36
  return {
12
37
  name,
38
+ description,
13
39
  match: PackageJsonRegexMatch,
14
- handler: async (innerArgs) => {
15
- const json = await readJson(innerArgs.file);
16
- return packagePolicy(json, innerArgs);
40
+ handler: function* (innerArgs) {
41
+ const json = yield* call(() => readJson(resolve(innerArgs.root, innerArgs.file)));
42
+ const result = packagePolicy(json, innerArgs);
43
+ // Handle both Operation (generator) and Promise return types
44
+ if (result instanceof Promise) {
45
+ return yield* call(() => result);
46
+ }
47
+ // Check if it's an Effection Operation (generator)
48
+ if (isOperation(result)) {
49
+ return yield* result;
50
+ }
51
+ // This should never happen with proper handler typing
52
+ throw new Error(`Unexpected handler result type: ${typeof result}`);
17
53
  },
18
54
  };
19
55
  }
@@ -1 +1 @@
1
- {"version":3,"file":"definePackagePolicy.js","sourceRoot":"","sources":["../../src/policyDefiners/definePackagePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,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,SAAS,CAAC,IAAI,CAAC,CAAC;YAC/C,OAAO,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACvC,CAAC;KACD,CAAC;AACH,CAAC","sourcesContent":["import jsonfile from \"jsonfile\";\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(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;AAwBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,mBAAmB,CAClC,IAAmC;IAEnC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IAC3D,OAAO;QACN,IAAI;QACJ,WAAW;QACX,KAAK,EAAE,qBAAqB;QAC5B,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,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAE9C,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","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\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 * @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: PolicyFunctionArguments<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\n/**\n * Define a repo policy for package.json files.\n *\n * @example\n * ```typescript\n * const MyPackagePolicy = definePackagePolicy({\n * name: \"MyPackagePolicy\",\n * description: \"Ensures package.json has required fields\",\n * handler: function* (json, { file }) {\n * if (!json.name) {\n * return { name: \"MyPackagePolicy\", file, errorMessages: [\"Missing name\"] };\n * }\n * return true;\n * },\n * });\n * ```\n *\n * @alpha\n */\nexport function definePackagePolicy<J = PackageJson, C = undefined>(\n\targs: DefinePackagePolicyArgs<J, C>,\n): PolicyDefinition<C> {\n\tconst { name, description, handler: packagePolicy } = args;\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\tmatch: PackageJsonRegexMatch,\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 = packagePolicy(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"]}
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.54.0"
8
+ "packageVersion": "7.56.0"
9
9
  }
10
10
  ]
11
11
  }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Represents detected indentation style.
3
+ *
4
+ * - `"\t"` - Tab character
5
+ * - `number` - Number of spaces (e.g., 2, 4)
6
+ */
7
+ export type IndentationStyle = "\t" | number;
8
+ /**
9
+ * Default indentation style used when detection fails or no indentation is found.
10
+ *
11
+ * @alpha
12
+ */
13
+ export declare const DEFAULT_INDENTATION: IndentationStyle;
14
+ /**
15
+ * Detect the indentation style used in a file.
16
+ *
17
+ * Analyzes the file content to determine whether tabs or spaces are used
18
+ * for indentation. This is useful when writing files to preserve
19
+ * the existing formatting style.
20
+ *
21
+ * @param filePath - Path to the file
22
+ * @param defaultIndentation - Indentation to use if detection fails (default: tab)
23
+ * @returns The detected indentation (tab character or number of spaces)
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * const indent = await detectIndentation("/path/to/package.json");
28
+ * // Returns "\t" for tabs, or a number like 2 or 4 for spaces
29
+ *
30
+ * // With custom default
31
+ * const indent = await detectIndentation("/path/to/file.yaml", 2);
32
+ * ```
33
+ *
34
+ * @alpha
35
+ */
36
+ export declare function detectIndentation(filePath: string, defaultIndentation?: IndentationStyle): Promise<IndentationStyle>;
37
+ /**
38
+ * Detect the indentation style used in text content.
39
+ *
40
+ * Analyzes the content string to determine whether tabs or spaces are used
41
+ * for indentation. This is a pure function useful for testing and for
42
+ * cases where the content is already in memory.
43
+ *
44
+ * The detection algorithm:
45
+ * 1. Splits content into lines
46
+ * 2. Finds the first line that starts with whitespace
47
+ * 3. If it starts with a tab, returns tab
48
+ * 4. If it starts with spaces, returns the count of leading spaces
49
+ * 5. If no indented lines found, returns the default
50
+ *
51
+ * @param content - The file content as a string
52
+ * @param defaultIndentation - Indentation to use if no indented lines found (default: tab)
53
+ * @returns The detected indentation (tab character or number of spaces)
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * // JSON with 2-space indentation
58
+ * const json = '{\n "name": "test"\n}';
59
+ * detectIndentationFromContent(json); // Returns 2
60
+ *
61
+ * // YAML with tab indentation
62
+ * const yaml = 'root:\n\tchild: value';
63
+ * detectIndentationFromContent(yaml); // Returns "\t"
64
+ *
65
+ * // No indentation found - uses default
66
+ * detectIndentationFromContent('no indent'); // Returns "\t"
67
+ * detectIndentationFromContent('no indent', 4); // Returns 4
68
+ * ```
69
+ *
70
+ * @alpha
71
+ */
72
+ export declare function detectIndentationFromContent(content: string, defaultIndentation?: IndentationStyle): IndentationStyle;
73
+ //# sourceMappingURL=indentation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indentation.d.ts","sourceRoot":"","sources":["../../src/utils/indentation.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG,MAAM,CAAC;AAE7C;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,gBAAuB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,iBAAiB,CACtC,QAAQ,EAAE,MAAM,EAChB,kBAAkB,GAAE,gBAAsC,GACxD,OAAO,CAAC,gBAAgB,CAAC,CAQ3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,4BAA4B,CAC3C,OAAO,EAAE,MAAM,EACf,kBAAkB,GAAE,gBAAsC,GACxD,gBAAgB,CAmBlB"}