vouchington-tooling 0.20.0 → 0.22.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 (257) hide show
  1. package/README.md +73 -10
  2. package/dist/agent-blackboard/snapshot-partition-format.mjs +2 -72
  3. package/dist/agent-blackboard/snapshot-partition-guards.d.mts +3 -0
  4. package/dist/agent-blackboard/snapshot-partition-guards.mjs +9 -0
  5. package/dist/agent-blackboard/snapshot-partition-predicates.d.mts +3 -0
  6. package/dist/agent-blackboard/snapshot-partition-predicates.mjs +65 -0
  7. package/dist/api-contract-discovery/header-contract-parser.d.mts +3 -0
  8. package/dist/api-contract-discovery/header-contract-parser.mjs +93 -0
  9. package/dist/api-contract-discovery/header-contract-registry.d.mts +3 -0
  10. package/dist/api-contract-discovery/header-contract-registry.mjs +38 -0
  11. package/dist/api-contract-discovery/header-contract-types.d.mts +19 -0
  12. package/dist/api-contract-discovery/header-contract-types.mjs +1 -0
  13. package/dist/api-contract-discovery/index.d.mts +31 -0
  14. package/dist/api-contract-discovery/index.mjs +26 -0
  15. package/dist/api-contract-discovery/query-contract-extraction.d.mts +3 -0
  16. package/dist/api-contract-discovery/query-contract-extraction.mjs +65 -0
  17. package/dist/api-contract-discovery/query-contract-literals.d.mts +8 -0
  18. package/dist/api-contract-discovery/query-contract-literals.mjs +54 -0
  19. package/dist/api-contract-discovery/query-contract-registry.d.mts +3 -0
  20. package/dist/api-contract-discovery/query-contract-registry.mjs +68 -0
  21. package/dist/api-contract-discovery/query-contract-types.d.mts +8 -0
  22. package/dist/api-contract-discovery/query-contract-types.mjs +1 -0
  23. package/dist/api-contract-discovery/registered-route-catalog.d.mts +10 -0
  24. package/dist/api-contract-discovery/registered-route-catalog.mjs +81 -0
  25. package/dist/api-contract-discovery/registered-route-handler-analysis.d.mts +2 -0
  26. package/dist/api-contract-discovery/registered-route-handler-analysis.mjs +74 -0
  27. package/dist/api-contract-discovery/request-contract-implicit.d.mts +17 -0
  28. package/dist/api-contract-discovery/request-contract-implicit.mjs +73 -0
  29. package/dist/api-contract-discovery/request-contract-lenient.d.mts +28 -0
  30. package/dist/api-contract-discovery/request-contract-lenient.mjs +59 -0
  31. package/dist/api-contract-discovery/request-contract-registry.d.mts +14 -0
  32. package/dist/api-contract-discovery/request-contract-registry.mjs +61 -0
  33. package/dist/api-contract-discovery/request-contract-route-analysis.d.mts +25 -0
  34. package/dist/api-contract-discovery/request-contract-route-analysis.mjs +68 -0
  35. package/dist/api-contract-discovery/request-contract-types.d.mts +12 -0
  36. package/dist/api-contract-discovery/request-contract-types.mjs +1 -0
  37. package/dist/api-contract-discovery/response-contract-ctx-analysis.d.mts +7 -0
  38. package/dist/api-contract-discovery/response-contract-ctx-analysis.mjs +28 -0
  39. package/dist/api-contract-discovery/response-contract-error-branch.d.mts +15 -0
  40. package/dist/api-contract-discovery/response-contract-error-branch.mjs +47 -0
  41. package/dist/api-contract-discovery/response-contract-implicit-sources.test-helpers.d.mts +145 -0
  42. package/dist/api-contract-discovery/response-contract-implicit-sources.test-helpers.mjs +145 -0
  43. package/dist/api-contract-discovery/response-contract-implicit.d.mts +5 -0
  44. package/dist/api-contract-discovery/response-contract-implicit.mjs +110 -0
  45. package/dist/api-contract-discovery/response-contract-lenient.d.mts +23 -0
  46. package/dist/api-contract-discovery/response-contract-lenient.mjs +52 -0
  47. package/dist/api-contract-discovery/response-contract-media.d.mts +3 -0
  48. package/dist/api-contract-discovery/response-contract-media.mjs +46 -0
  49. package/dist/api-contract-discovery/response-contract-registration.d.mts +11 -0
  50. package/dist/api-contract-discovery/response-contract-registration.mjs +61 -0
  51. package/dist/api-contract-discovery/response-contract-registry.d.mts +7 -0
  52. package/dist/api-contract-discovery/response-contract-registry.mjs +76 -0
  53. package/dist/api-contract-discovery/response-contract-route-analysis.d.mts +13 -0
  54. package/dist/api-contract-discovery/response-contract-route-analysis.mjs +144 -0
  55. package/dist/api-contract-discovery/response-contract-status.d.mts +27 -0
  56. package/dist/api-contract-discovery/response-contract-status.mjs +80 -0
  57. package/dist/api-contract-discovery/response-contract-types.d.mts +16 -0
  58. package/dist/api-contract-discovery/response-contract-types.mjs +1 -0
  59. package/dist/api-contract-discovery/test-setup.test-helpers.d.mts +3 -0
  60. package/dist/api-contract-discovery/test-setup.test-helpers.mjs +2 -0
  61. package/dist/ast-grep-examples/companion-parity-compare.d.mts +3 -0
  62. package/dist/ast-grep-examples/companion-parity-compare.mjs +58 -0
  63. package/dist/ast-grep-examples/companion-parity.d.mts +2 -1
  64. package/dist/ast-grep-examples/companion-parity.mjs +2 -58
  65. package/dist/browser-session-runner/attempt.mjs +29 -48
  66. package/dist/browser-session-runner/termination.d.mts +11 -0
  67. package/dist/browser-session-runner/termination.mjs +34 -0
  68. package/dist/cli/parse-direct-options.d.mts +26 -0
  69. package/dist/cli/parse-direct-options.mjs +72 -0
  70. package/dist/cli/parse-forwarded-commands.d.mts +42 -0
  71. package/dist/cli/parse-forwarded-commands.mjs +29 -0
  72. package/dist/cli/parse-options.d.mts +1 -2
  73. package/dist/cli/parse-options.mjs +2 -72
  74. package/dist/cli/parse.mjs +4 -26
  75. package/dist/compiler-build/freshness.d.mts +27 -0
  76. package/dist/compiler-build/freshness.mjs +116 -0
  77. package/dist/compiler-build/index.d.mts +2 -0
  78. package/dist/compiler-build/index.mjs +2 -0
  79. package/dist/compiler-build/settlement.d.mts +10 -0
  80. package/dist/compiler-build/settlement.mjs +14 -0
  81. package/dist/config-inventory/call-arguments.d.mts +1 -0
  82. package/dist/config-inventory/call-arguments.mjs +30 -0
  83. package/dist/config-inventory/collect.d.mts +3 -0
  84. package/dist/config-inventory/collect.mjs +43 -0
  85. package/dist/config-inventory/dynamic-configs.d.mts +2 -0
  86. package/dist/config-inventory/dynamic-configs.mjs +9 -0
  87. package/dist/config-inventory/env-expression-readers.d.mts +3 -0
  88. package/dist/config-inventory/env-expression-readers.mjs +117 -0
  89. package/dist/config-inventory/env-prefix-readers.d.mts +2 -0
  90. package/dist/config-inventory/env-prefix-readers.mjs +14 -0
  91. package/dist/config-inventory/env-reference-matchers.d.mts +3 -0
  92. package/dist/config-inventory/env-reference-matchers.mjs +9 -0
  93. package/dist/config-inventory/env-var-accumulator.d.mts +6 -0
  94. package/dist/config-inventory/env-var-accumulator.mjs +82 -0
  95. package/dist/config-inventory/env-vars.d.mts +4 -0
  96. package/dist/config-inventory/env-vars.mjs +108 -0
  97. package/dist/config-inventory/format.d.mts +2 -0
  98. package/dist/config-inventory/format.mjs +69 -0
  99. package/dist/config-inventory/index.d.mts +3 -0
  100. package/dist/config-inventory/index.mjs +2 -0
  101. package/dist/config-inventory/package-gates.d.mts +2 -0
  102. package/dist/config-inventory/package-gates.mjs +54 -0
  103. package/dist/config-inventory/shared.d.mts +3 -0
  104. package/dist/config-inventory/shared.mjs +7 -0
  105. package/dist/config-inventory/types.d.mts +96 -0
  106. package/dist/config-inventory/types.mjs +1 -0
  107. package/dist/contract-schema/contract-schema-bounded-array.d.mts +15 -0
  108. package/dist/contract-schema/contract-schema-bounded-array.mjs +32 -0
  109. package/dist/contract-schema/contract-schema-type-extractor.d.mts +2 -8
  110. package/dist/contract-schema/contract-schema-type-extractor.mjs +2 -31
  111. package/dist/coverage-transport/control-v2-parse-object.d.mts +12 -0
  112. package/dist/coverage-transport/control-v2-parse-object.mjs +28 -0
  113. package/dist/coverage-transport/control-v2.mjs +2 -27
  114. package/dist/dependency-license-policy/audit-directory.d.mts +28 -0
  115. package/dist/dependency-license-policy/audit-directory.mjs +115 -0
  116. package/dist/dependency-license-policy/audit-signals.d.mts +12 -0
  117. package/dist/dependency-license-policy/audit-signals.mjs +44 -0
  118. package/dist/dependency-license-policy/audit-store.d.mts +12 -0
  119. package/dist/dependency-license-policy/audit-store.mjs +32 -0
  120. package/dist/dependency-license-policy/collect.d.mts +3 -1
  121. package/dist/dependency-license-policy/collect.mjs +16 -21
  122. package/dist/dependency-license-policy/execute-pnpm.d.mts +10 -0
  123. package/dist/dependency-license-policy/execute-pnpm.mjs +83 -0
  124. package/dist/dependency-license-policy/types.d.mts +11 -9
  125. package/dist/dependency-license-policy/workspace.d.mts +3 -1
  126. package/dist/dependency-license-policy/workspace.mjs +12 -5
  127. package/dist/gh-api-shell-quoting/argument-scan.d.mts +7 -0
  128. package/dist/gh-api-shell-quoting/argument-scan.mjs +35 -0
  129. package/dist/gh-api-shell-quoting/logical-line.d.mts +3 -0
  130. package/dist/gh-api-shell-quoting/logical-line.mjs +90 -0
  131. package/dist/gh-api-shell-quoting/scan.d.mts +2 -4
  132. package/dist/gh-api-shell-quoting/scan.mjs +1 -119
  133. package/dist/gh-cli/diff.d.mts +24 -4
  134. package/dist/gh-cli/diff.mjs +111 -4
  135. package/dist/gh-cli/index.d.mts +2 -1
  136. package/dist/gh-cli/index.mjs +1 -1
  137. package/dist/gha-workspace-policy/docker-options.d.mts +4 -0
  138. package/dist/gha-workspace-policy/docker-options.mjs +93 -0
  139. package/dist/gha-workspace-policy/docker-workspace-user.mjs +1 -168
  140. package/dist/gha-workspace-policy/shell-token-modes.d.mts +10 -0
  141. package/dist/gha-workspace-policy/shell-token-modes.mjs +31 -0
  142. package/dist/gha-workspace-policy/shell-tokens.d.mts +1 -0
  143. package/dist/gha-workspace-policy/shell-tokens.mjs +65 -0
  144. package/dist/index.d.mts +2 -1
  145. package/dist/index.mjs +1 -1
  146. package/dist/openapi-document/contract-schema-types.d.mts +1 -1
  147. package/dist/openapi-document/openapi-types.d.mts +1 -1
  148. package/dist/pnpm-install/native-family.d.mts +3 -0
  149. package/dist/pnpm-install/native-family.mjs +31 -0
  150. package/dist/pnpm-install/native-health.d.mts +1 -4
  151. package/dist/pnpm-install/native-health.mjs +2 -31
  152. package/dist/retrospective-facts/local-merge.d.mts +2 -0
  153. package/dist/retrospective-facts/local-merge.mjs +21 -0
  154. package/dist/retrospective-facts/local.mjs +1 -21
  155. package/dist/retrospective-transcript/claude-blocks.d.mts +3 -0
  156. package/dist/retrospective-transcript/claude-blocks.mjs +38 -0
  157. package/dist/retrospective-transcript/claude.mjs +4 -34
  158. package/dist/retrospective-transcript/codex-payload.d.mts +2 -0
  159. package/dist/retrospective-transcript/codex-payload.mjs +51 -0
  160. package/dist/retrospective-transcript/codex-records.d.mts +2 -0
  161. package/dist/retrospective-transcript/codex-records.mjs +95 -0
  162. package/dist/retrospective-transcript/codex.mjs +2 -144
  163. package/dist/retrospective-transcript/index.d.mts +3 -16
  164. package/dist/retrospective-transcript/index.mjs +4 -48
  165. package/dist/retrospective-transcript/resolve-transcript-file.d.mts +19 -0
  166. package/dist/retrospective-transcript/resolve-transcript-file.mjs +50 -0
  167. package/dist/session-friction/command-segments.d.mts +3 -0
  168. package/dist/session-friction/command-segments.mjs +94 -0
  169. package/dist/session-friction/log-file.d.mts +7 -0
  170. package/dist/session-friction/log-file.mjs +83 -0
  171. package/dist/session-friction/log.mjs +3 -83
  172. package/dist/session-friction/normalize.mjs +1 -94
  173. package/dist/sql-scanner/comments.d.mts +1 -0
  174. package/dist/sql-scanner/comments.mjs +101 -0
  175. package/dist/sql-scanner/index.d.mts +1 -1
  176. package/dist/sql-scanner/index.mjs +1 -100
  177. package/dist/sql-scanner/literals.mjs +1 -35
  178. package/dist/sql-scanner/quote-decode.d.mts +2 -0
  179. package/dist/sql-scanner/quote-decode.mjs +35 -0
  180. package/dist/vitest-diagnostics/index.d.mts +7 -0
  181. package/dist/vitest-diagnostics/index.mjs +4 -0
  182. package/dist/vitest-diagnostics/vitest-fork-exit-error-detail.d.mts +7 -0
  183. package/dist/vitest-diagnostics/vitest-fork-exit-error-detail.mjs +26 -0
  184. package/dist/vitest-diagnostics/vitest-fork-exit-records.d.mts +26 -0
  185. package/dist/vitest-diagnostics/vitest-fork-exit-records.mjs +161 -0
  186. package/dist/vitest-diagnostics/vitest-fork-exit-sentinel.d.mts +14 -0
  187. package/dist/vitest-diagnostics/vitest-fork-exit-sentinel.mjs +131 -0
  188. package/dist/vitest-diagnostics/vitest-fork-leak-detection.d.mts +26 -0
  189. package/dist/vitest-diagnostics/vitest-fork-leak-detection.mjs +96 -0
  190. package/dist/vitest-diagnostics/vitest-fork-leak-diagnostics.d.mts +3 -0
  191. package/dist/vitest-diagnostics/vitest-fork-leak-diagnostics.mjs +14 -0
  192. package/dist/vitest-diagnostics/vitest-fork-leak-episode.d.mts +37 -0
  193. package/dist/vitest-diagnostics/vitest-fork-leak-episode.mjs +118 -0
  194. package/dist/vitest-diagnostics/vitest-worker-exit-diagnostics-errors.d.mts +2 -0
  195. package/dist/vitest-diagnostics/vitest-worker-exit-diagnostics-errors.mjs +42 -0
  196. package/dist/vitest-diagnostics/vitest-worker-exit-diagnostics-reporter.d.mts +12 -0
  197. package/dist/vitest-diagnostics/vitest-worker-exit-diagnostics-reporter.mjs +142 -0
  198. package/dist/workflow-policy/concurrency-scope.d.mts +4 -0
  199. package/dist/workflow-policy/concurrency-scope.mjs +66 -0
  200. package/dist/workflow-policy/concurrency.d.mts +10 -0
  201. package/dist/workflow-policy/concurrency.mjs +77 -0
  202. package/dist/workflow-policy/condition-entailment.d.mts +20 -0
  203. package/dist/workflow-policy/condition-entailment.mjs +132 -0
  204. package/dist/workflow-policy/condition-split.d.mts +15 -0
  205. package/dist/workflow-policy/condition-split.mjs +71 -0
  206. package/dist/workflow-policy/graph.d.mts +2 -0
  207. package/dist/workflow-policy/graph.mjs +138 -0
  208. package/dist/workflow-policy/index.d.mts +7 -0
  209. package/dist/workflow-policy/index.mjs +6 -0
  210. package/dist/workflow-policy/permission-mismatches.d.mts +3 -0
  211. package/dist/workflow-policy/permission-mismatches.mjs +52 -0
  212. package/dist/workflow-policy/permissions.d.mts +16 -0
  213. package/dist/workflow-policy/permissions.mjs +83 -0
  214. package/dist/workflow-policy/secret-readiness.d.mts +18 -0
  215. package/dist/workflow-policy/secret-readiness.mjs +163 -0
  216. package/dist/workflow-policy/shell-comments.d.mts +7 -0
  217. package/dist/workflow-policy/shell-comments.mjs +28 -0
  218. package/dist/workflow-policy/types.d.mts +90 -0
  219. package/dist/workflow-policy/types.mjs +1 -0
  220. package/dist/workspace-gates/manifest-version-parser.mjs +1 -52
  221. package/dist/workspace-gates/manifest-version-skips.d.mts +1 -0
  222. package/dist/workspace-gates/manifest-version-skips.mjs +52 -0
  223. package/docs/workflow-and-compiler.md +74 -0
  224. package/package.json +26 -2
  225. package/skills/agent-workflow/SKILL.md +4 -4
  226. package/skills/agent-workflow/references/review-response.md +47 -44
  227. package/skills/backend-vitest-test-authoring/SKILL.md +9 -6
  228. package/skills/blackboard/SKILL.md +8 -8
  229. package/skills/dependabot/SKILL.md +68 -67
  230. package/skills/dotnet-test-authoring/SKILL.md +11 -12
  231. package/skills/git-commit-checklist/SKILL.md +3 -3
  232. package/skills/github-actions-authoring/SKILL.md +40 -38
  233. package/skills/github-actions-checklist/SKILL.md +93 -85
  234. package/skills/github-issue/SKILL.md +82 -78
  235. package/skills/nextjs-vitest-test-authoring/SKILL.md +8 -6
  236. package/skills/npm-publishing/SKILL.md +42 -38
  237. package/skills/organize-github-issues/SKILL.md +18 -22
  238. package/skills/package-json-checklist/SKILL.md +5 -5
  239. package/skills/planning/SKILL.md +3 -3
  240. package/skills/playwright-authoring/SKILL.md +10 -9
  241. package/skills/postgres-node-performance-tuning/SKILL.md +10 -6
  242. package/skills/postgres-partitioning-uuid-v7/SKILL.md +10 -7
  243. package/skills/pr-description/SKILL.md +4 -3
  244. package/skills/retrospective/SKILL.md +14 -15
  245. package/skills/retrospective-distill/SKILL.md +14 -14
  246. package/skills/review-ci-logs/SKILL.md +18 -19
  247. package/skills/review-github-issue-taxonomy/SKILL.md +21 -18
  248. package/skills/revisit-followups/SKILL.md +3 -3
  249. package/skills/stacked-prs/SKILL.md +30 -61
  250. package/skills/static-analysis-checklist/SKILL.md +6 -4
  251. package/skills/storybook-authoring/SKILL.md +9 -9
  252. package/skills/swift-test-authoring/SKILL.md +10 -9
  253. package/skills/test-authoring/SKILL.md +14 -14
  254. package/skills/test-authoring/references/core-practice.md +12 -11
  255. package/skills/test-authoring/references/dependency-boundaries.md +36 -35
  256. package/skills/test-authoring/references/tautological-tests.md +45 -44
  257. package/skills/vitest-test-authoring/SKILL.md +9 -6
@@ -0,0 +1,10 @@
1
+ export type SettlementConfirmation<Configuration> = {
2
+ configuration: Configuration;
3
+ settled: boolean;
4
+ };
5
+ export type SettlementCallbacks<Configuration, Value> = {
6
+ buildAttempt(configuration: Configuration): Value;
7
+ confirmAttempt(configuration: Configuration, value: Value): SettlementConfirmation<Configuration>;
8
+ };
9
+ /** Rebuilds against the configuration returned by each failed confirmation. */
10
+ export declare function settleBuild<Configuration, Value>(initialConfiguration: Configuration, maximumAttempts: number, callbacks: SettlementCallbacks<Configuration, Value>): Value;
@@ -0,0 +1,14 @@
1
+ /** Rebuilds against the configuration returned by each failed confirmation. */
2
+ export function settleBuild(initialConfiguration, maximumAttempts, callbacks) {
3
+ if (!Number.isSafeInteger(maximumAttempts) || maximumAttempts < 1)
4
+ throw new RangeError('maximumAttempts must be a positive safe integer');
5
+ let configuration = initialConfiguration;
6
+ for (let attempts = 1; attempts <= maximumAttempts; attempts += 1) {
7
+ const value = callbacks.buildAttempt(configuration);
8
+ const confirmation = callbacks.confirmAttempt(configuration, value);
9
+ if (confirmation.settled)
10
+ return value;
11
+ configuration = confirmation.configuration;
12
+ }
13
+ throw new Error(`Inputs changed during ${maximumAttempts} consecutive build attempts`);
14
+ }
@@ -0,0 +1 @@
1
+ export declare function splitCallArguments(args: string): string[];
@@ -0,0 +1,30 @@
1
+ export function splitCallArguments(args) {
2
+ const parts = [];
3
+ let start = 0;
4
+ let depth = 0;
5
+ let quote = '';
6
+ for (let index = 0; index < args.length; index += 1) {
7
+ const char = args[index];
8
+ if (quote) {
9
+ if (char === '\\')
10
+ index += 1;
11
+ else if (char === quote)
12
+ quote = '';
13
+ }
14
+ else if (char === '"' || char === "'" || char === '`') {
15
+ quote = char;
16
+ }
17
+ else if ('<[{('.includes(char)) {
18
+ depth += 1;
19
+ }
20
+ else if ('>]})'.includes(char)) {
21
+ depth = Math.max(0, depth - 1);
22
+ }
23
+ else if (char === ',' && depth === 0) {
24
+ parts.push(args.slice(start, index).trim());
25
+ start = index + 1;
26
+ }
27
+ }
28
+ parts.push(args.slice(start).trim());
29
+ return parts;
30
+ }
@@ -0,0 +1,3 @@
1
+ import type { ConfigInventory, ConfigInventoryContext, ConfigInventoryOptions } from './types.mts';
2
+ /** Collects syntax-level evidence without executing any consumer module. */
3
+ export declare function collectConfigInventory(context: ConfigInventoryContext, options: ConfigInventoryOptions): ConfigInventory;
@@ -0,0 +1,43 @@
1
+ import { addDynamicConfigReferences } from './dynamic-configs.mjs';
2
+ import { collectEnvVarPrefixReadersFromFile } from './env-prefix-readers.mjs';
3
+ import { compileEnvVarReferenceMatchers } from './env-reference-matchers.mjs';
4
+ import { collectEnvVarReferencesFromFile, collectEnvVarsFromFile, seedTypedEnvContractEntries, toEnvVarRow, } from './env-vars.mjs';
5
+ import { collectPackageGatesFromFile } from './package-gates.mjs';
6
+ /** Collects syntax-level evidence without executing any consumer module. */
7
+ export function collectConfigInventory(context, options) {
8
+ const envVars = new Map();
9
+ const dynamicConfigs = new Map();
10
+ const packageGates = new Map();
11
+ const sources = [];
12
+ const constants = options.envConstants ?? new Map();
13
+ seedTypedEnvContractEntries(envVars, options.envContract ?? [], options.sensitivityOrder);
14
+ for (const file of [...new Set(context.trackedFiles)].sort()) {
15
+ const rules = options.describeFile(file);
16
+ if (!rules)
17
+ continue;
18
+ const source = context.readTrackedFile(file);
19
+ if (source === null)
20
+ continue;
21
+ sources.push({ file, source, rules });
22
+ collectEnvVarsFromFile(file, source, envVars, constants, rules, options.envHelperNames ?? []);
23
+ if (rules.packageManagerConfig)
24
+ collectPackageGatesFromFile(file, source, packageGates);
25
+ addDynamicConfigReferences(dynamicConfigs, file, options.collectDynamicConfigs?.(file, source) ?? []);
26
+ }
27
+ const matchers = compileEnvVarReferenceMatchers(envVars);
28
+ for (const { file, source, rules } of sources) {
29
+ if (!rules.markdown)
30
+ collectEnvVarPrefixReadersFromFile(file, source, envVars, constants);
31
+ collectEnvVarReferencesFromFile(file, source, envVars, matchers, rules.referenceBuckets ?? []);
32
+ }
33
+ return {
34
+ envVars: [...envVars.values()]
35
+ .map((accumulator) => {
36
+ const row = toEnvVarRow(accumulator);
37
+ return { ...row, ...options.annotateEnv?.(row) };
38
+ })
39
+ .toSorted((a, b) => a.name.localeCompare(b.name)),
40
+ dynamicConfigs: [...dynamicConfigs.values()].toSorted((a, b) => a.namespace.localeCompare(b.namespace)),
41
+ packageGates: [...packageGates.values()].toSorted((a, b) => a.name.localeCompare(b.name)),
42
+ };
43
+ }
@@ -0,0 +1,2 @@
1
+ import type { DynamicConfigInventoryRow, DynamicConfigReference } from './types.mts';
2
+ export declare function addDynamicConfigReferences(rows: Map<string, DynamicConfigInventoryRow>, file: string, references: readonly DynamicConfigReference[]): void;
@@ -0,0 +1,9 @@
1
+ import { sorted } from './shared.mjs';
2
+ export function addDynamicConfigReferences(rows, file, references) {
3
+ for (const { namespace, kind } of references) {
4
+ const row = rows.get(namespace) ?? { namespace, definitionFiles: [], registryFiles: [] };
5
+ const key = kind === 'definition' ? 'definitionFiles' : 'registryFiles';
6
+ row[key] = sorted(new Set([...row[key], file]));
7
+ rows.set(namespace, row);
8
+ }
9
+ }
@@ -0,0 +1,3 @@
1
+ export declare function matchLocalEnvWrapperCallNames(source: string, envConstants: ReadonlyMap<string, string>): string[];
2
+ export declare function matchLocalEnvWrapperCallPrefixes(source: string, envConstants: ReadonlyMap<string, string>): string[];
3
+ export declare function matchWorkflowEnvMapNames(source: string): string[];
@@ -0,0 +1,117 @@
1
+ import { splitCallArguments } from './call-arguments.mjs';
2
+ const FUNCTION_DECLARATION_PATTERN = /\bfunction\s+([a-zA-Z_$][\w$]*)\s*\(([^)]*)\)\s*(?::[^{]+)?\{([\s\S]*?)\n\s*\}/g;
3
+ const CALL_EXPRESSION_PATTERN = /\b([a-zA-Z_$][\w$]*)\s*\(([^)]*)\)/g;
4
+ const ENV_MAP_DECLARATION_PATTERN = /^(\s*)(?:-\s*)?env\s*:\s*(?:#.*)?$/;
5
+ const BLANK_OR_COMMENT_PATTERN = /^\s*(?:#.*)?$/;
6
+ const UPPERCASE_YAML_KEY_PATTERN = /^\s*([A-Z][A-Z0-9_]*)\s*:/;
7
+ const PROCESS_ENV_PARAM_PATTERN = /\bprocess\.env\[([a-zA-Z_$][\w$]*)\]/g;
8
+ const IDENTIFIER_INDEXED_ACCESS_PATTERN = /\b([a-zA-Z_$][\w$]*)\[([a-zA-Z_$][\w$]*)\]/g;
9
+ export function matchLocalEnvWrapperCallNames(source, envConstants) {
10
+ const envNameArgumentIndexes = findLocalEnvWrapperArgumentIndexes(source);
11
+ if (envNameArgumentIndexes.size === 0)
12
+ return [];
13
+ const names = new Set();
14
+ for (const match of source.matchAll(CALL_EXPRESSION_PATTERN)) {
15
+ const functionName = match[1];
16
+ const envNameArgumentIndex = envNameArgumentIndexes.get(functionName);
17
+ if (envNameArgumentIndex === undefined)
18
+ continue;
19
+ const args = splitCallArguments(match[2]);
20
+ const name = envNameFromArgument(args[envNameArgumentIndex], envConstants);
21
+ if (name)
22
+ names.add(name);
23
+ }
24
+ return [...names];
25
+ }
26
+ export function matchLocalEnvWrapperCallPrefixes(source, envConstants) {
27
+ const envNameArgumentIndexes = findLocalEnvWrapperArgumentIndexes(source);
28
+ if (envNameArgumentIndexes.size === 0)
29
+ return [];
30
+ const prefixes = new Set();
31
+ for (const match of source.matchAll(CALL_EXPRESSION_PATTERN)) {
32
+ const functionName = match[1];
33
+ const envNameArgumentIndex = envNameArgumentIndexes.get(functionName);
34
+ if (envNameArgumentIndex === undefined)
35
+ continue;
36
+ const args = splitCallArguments(match[2]);
37
+ const prefix = envNamePrefixFromArgument(args[envNameArgumentIndex], envConstants);
38
+ if (prefix)
39
+ prefixes.add(prefix);
40
+ }
41
+ return [...prefixes];
42
+ }
43
+ export function matchWorkflowEnvMapNames(source) {
44
+ const names = new Set();
45
+ const lines = source.split('\n');
46
+ for (let index = 0; index < lines.length; index += 1) {
47
+ const envIndent = lines[index].match(ENV_MAP_DECLARATION_PATTERN)?.[1]?.length;
48
+ if (envIndent === undefined)
49
+ continue;
50
+ collectEnvMapChildNames(lines, index, envIndent, names);
51
+ }
52
+ return [...names];
53
+ }
54
+ function findLocalEnvWrapperArgumentIndexes(source) {
55
+ const indexes = new Map();
56
+ for (const match of source.matchAll(FUNCTION_DECLARATION_PATTERN)) {
57
+ const functionName = match[1];
58
+ const params = parseParameterNames(match[2]);
59
+ const body = match[3];
60
+ const processEnvParams = new Set([...body.matchAll(PROCESS_ENV_PARAM_PATTERN)].map((item) => item[1]));
61
+ const indexedAccesses = new Set([...body.matchAll(IDENTIFIER_INDEXED_ACCESS_PATTERN)].map((item) => `${item[1]}:${item[2]}`));
62
+ addProcessEnvWrapperIndexes(indexes, functionName, params, processEnvParams);
63
+ addEnvObjectWrapperIndexes(indexes, functionName, params, indexedAccesses);
64
+ }
65
+ return indexes;
66
+ }
67
+ function addProcessEnvWrapperIndexes(indexes, functionName, params, processEnvParams) {
68
+ for (const [index, param] of params.entries()) {
69
+ if (processEnvParams.has(param))
70
+ indexes.set(functionName, index);
71
+ }
72
+ }
73
+ function addEnvObjectWrapperIndexes(indexes, functionName, params, indexedAccesses) {
74
+ for (const [envIndex, envParam] of params.entries()) {
75
+ for (const [nameIndex, nameParam] of params.entries()) {
76
+ if (envIndex === nameIndex)
77
+ continue;
78
+ if (indexedAccesses.has(`${envParam}:${nameParam}`))
79
+ indexes.set(functionName, nameIndex);
80
+ }
81
+ }
82
+ }
83
+ function parseParameterNames(parameters) {
84
+ return splitCallArguments(parameters).map((parameter) => {
85
+ const name = parameter.trim().match(/^([a-zA-Z_$][\w$]*)\b/)?.[1];
86
+ return name ?? '';
87
+ });
88
+ }
89
+ function envNameFromArgument(arg, envConstants) {
90
+ if (!arg)
91
+ return null;
92
+ const literal = arg.match(/^['"]([A-Z][A-Z0-9_]*)['"]$/)?.[1];
93
+ if (literal)
94
+ return literal;
95
+ return envConstants.get(arg) ?? null;
96
+ }
97
+ function envNamePrefixFromArgument(arg, envConstants) {
98
+ const prefixConstant = arg?.match(/^`\$\{([A-Z0-9_]+)\}/)?.[1];
99
+ return prefixConstant ? (envConstants.get(prefixConstant) ?? null) : null;
100
+ }
101
+ function collectEnvMapChildNames(lines, envLineIndex, envIndent, names) {
102
+ let keyIndent = null;
103
+ for (let childIndex = envLineIndex + 1; childIndex < lines.length; childIndex += 1) {
104
+ const line = lines[childIndex];
105
+ if (BLANK_OR_COMMENT_PATTERN.test(line))
106
+ continue;
107
+ const indent = line.match(/^\s*/)[0].length;
108
+ if (indent <= envIndent)
109
+ break;
110
+ keyIndent ??= indent;
111
+ if (indent !== keyIndent)
112
+ continue;
113
+ const name = line.match(UPPERCASE_YAML_KEY_PATTERN)?.[1];
114
+ if (name)
115
+ names.add(name);
116
+ }
117
+ }
@@ -0,0 +1,2 @@
1
+ import type { EnvVarAccumulator } from './types.mts';
2
+ export declare function collectEnvVarPrefixReadersFromFile(file: string, source: string, envVars: Map<string, EnvVarAccumulator>, envConstants: ReadonlyMap<string, string>): void;
@@ -0,0 +1,14 @@
1
+ import { matchLocalEnvWrapperCallPrefixes } from './env-expression-readers.mjs';
2
+ import { ENV_NAME_PATTERN, sorted } from './shared.mjs';
3
+ export function collectEnvVarPrefixReadersFromFile(file, source, envVars, envConstants) {
4
+ const prefixes = matchLocalEnvWrapperCallPrefixes(source, envConstants);
5
+ if (prefixes.length === 0)
6
+ return;
7
+ for (const prefix of prefixes) {
8
+ for (const name of sorted(envVars.keys())) {
9
+ if (name.startsWith(prefix) && ENV_NAME_PATTERN.test(name)) {
10
+ envVars.get(name)?.readers.add(file);
11
+ }
12
+ }
13
+ }
14
+ }
@@ -0,0 +1,3 @@
1
+ import type { EnvVarAccumulator, EnvVarReferenceMatcher } from './types.mts';
2
+ export declare function compileEnvVarReferenceMatchers(envVars: Map<string, EnvVarAccumulator>): EnvVarReferenceMatcher[];
3
+ export declare function namesAlreadySeen(source: string, referenceMatchers: EnvVarReferenceMatcher[]): string[];
@@ -0,0 +1,9 @@
1
+ export function compileEnvVarReferenceMatchers(envVars) {
2
+ return [...envVars.keys()].map((name) => ({
3
+ name,
4
+ pattern: new RegExp(`(?<![A-Za-z0-9_/-])${name}(?![A-Za-z0-9_/-])`),
5
+ }));
6
+ }
7
+ export function namesAlreadySeen(source, referenceMatchers) {
8
+ return referenceMatchers.flatMap(({ name, pattern }) => (pattern.test(source) ? [name] : []));
9
+ }
@@ -0,0 +1,6 @@
1
+ import type { EnvVarAccumulator, EnvVarInventoryRow, SourceBucket, TypedEnvContractEntry } from './types.mts';
2
+ type EnvVarMetadata = Pick<TypedEnvContractEntry, 'contractKey' | 'sourceOfTruth' | 'runtimeSurfaces' | 'sensitivity'>;
3
+ export declare function seedTypedEnvContractEntries(envVars: Map<string, EnvVarAccumulator>, entries: readonly TypedEnvContractEntry[], sensitivityOrder?: readonly string[]): void;
4
+ export declare function toEnvVarRow(acc: EnvVarAccumulator): EnvVarInventoryRow;
5
+ export declare function addEnvVar(envVars: Map<string, EnvVarAccumulator>, name: string, file: string, bucket: SourceBucket, metadata?: EnvVarMetadata): void;
6
+ export {};
@@ -0,0 +1,82 @@
1
+ import { ENV_NAME_PATTERN, sorted } from './shared.mjs';
2
+ const DEFAULT_SENSITIVITY_ORDER = ['internal', 'public', 'secret'];
3
+ export function seedTypedEnvContractEntries(envVars, entries, sensitivityOrder = DEFAULT_SENSITIVITY_ORDER) {
4
+ const sensitivityRank = new Map(sensitivityOrder.map((value, index) => [value, index + 1]));
5
+ for (const entry of entries)
6
+ addTypedEnvContractEntry(envVars, entry, sensitivityRank);
7
+ }
8
+ export function toEnvVarRow(acc) {
9
+ const sourceSets = {
10
+ runtimeSurfaces: sorted(acc.runtimeSurfaces),
11
+ contractKeys: sorted(acc.contractKeys),
12
+ readers: sorted(acc.readers),
13
+ localSetup: sorted(acc.localSetup),
14
+ docs: sorted(acc.docs),
15
+ deployment: sorted(acc.deployment),
16
+ dockerBuildArgs: sorted(acc.dockerBuildArgs),
17
+ workflows: sorted(acc.workflows),
18
+ packageGates: sorted(acc.packageGates),
19
+ };
20
+ return {
21
+ name: acc.name,
22
+ classifications: [],
23
+ reviewReason: null,
24
+ contractKey: acc.contractKey,
25
+ sourceOfTruth: acc.sourceOfTruth,
26
+ sensitivity: acc.sensitivity,
27
+ ...sourceSets,
28
+ };
29
+ }
30
+ export function addEnvVar(envVars, name, file, bucket, metadata = {}) {
31
+ if (!ENV_NAME_PATTERN.test(name))
32
+ return;
33
+ const acc = envVars.get(name) ?? createEnvVarAccumulator(name);
34
+ acc[bucket].add(file);
35
+ mergeEnvVarMetadata(acc, metadata);
36
+ envVars.set(name, acc);
37
+ }
38
+ function addTypedEnvContractEntry(envVars, entry, sensitivityRank) {
39
+ if (!ENV_NAME_PATTERN.test(entry.name))
40
+ return;
41
+ const acc = envVars.get(entry.name) ?? createEnvVarAccumulator(entry.name);
42
+ mergeEnvVarMetadata(acc, entry, sensitivityRank);
43
+ envVars.set(entry.name, acc);
44
+ }
45
+ function createEnvVarAccumulator(name) {
46
+ return {
47
+ name,
48
+ contractKey: null,
49
+ contractKeys: new Set(),
50
+ sourceOfTruth: null,
51
+ sensitivity: null,
52
+ runtimeSurfaces: new Set(),
53
+ readers: new Set(),
54
+ localSetup: new Set(),
55
+ docs: new Set(),
56
+ deployment: new Set(),
57
+ dockerBuildArgs: new Set(),
58
+ workflows: new Set(),
59
+ packageGates: new Set(),
60
+ };
61
+ }
62
+ function mergeEnvVarMetadata(acc, metadata, sensitivityRank = new Map()) {
63
+ if (metadata.contractKey) {
64
+ acc.contractKeys.add(metadata.contractKey);
65
+ if (acc.contractKey === null)
66
+ acc.contractKey = metadata.contractKey;
67
+ }
68
+ if (acc.sourceOfTruth === null && metadata.sourceOfTruth)
69
+ acc.sourceOfTruth = metadata.sourceOfTruth;
70
+ acc.sensitivity = highestSensitivity(acc.sensitivity, metadata.sensitivity, sensitivityRank);
71
+ for (const surface of metadata.runtimeSurfaces ?? [])
72
+ acc.runtimeSurfaces.add(surface);
73
+ }
74
+ function highestSensitivity(current, incoming, sensitivityRank) {
75
+ if (!incoming)
76
+ return current;
77
+ if (current === null)
78
+ return incoming;
79
+ return (sensitivityRank.get(incoming) ?? 0) > (sensitivityRank.get(current) ?? 0)
80
+ ? incoming
81
+ : current;
82
+ }
@@ -0,0 +1,4 @@
1
+ import type { EnvVarAccumulator, EnvVarReferenceMatcher, ConfigSourceRules } from './types.mts';
2
+ export { seedTypedEnvContractEntries, toEnvVarRow } from './env-var-accumulator.mts';
3
+ export declare function collectEnvVarsFromFile(file: string, source: string, envVars: Map<string, EnvVarAccumulator>, envConstants: ReadonlyMap<string, string>, rules: ConfigSourceRules, helperNames: readonly string[]): void;
4
+ export declare function collectEnvVarReferencesFromFile(file: string, source: string, envVars: Map<string, EnvVarAccumulator>, referenceMatchers: EnvVarReferenceMatcher[], buckets: readonly import('./types.mts').SourceBucket[]): void;
@@ -0,0 +1,108 @@
1
+ import { matchLocalEnvWrapperCallNames, matchWorkflowEnvMapNames, } from './env-expression-readers.mjs';
2
+ import { namesAlreadySeen } from './env-reference-matchers.mjs';
3
+ import { addEnvVar } from './env-var-accumulator.mjs';
4
+ import { matchNames } from './shared.mjs';
5
+ export { seedTypedEnvContractEntries, toEnvVarRow } from './env-var-accumulator.mjs';
6
+ const PROCESS_ENV_PATTERNS = [
7
+ /\bprocess\.env\.([A-Z][A-Z0-9_]*)\b/g,
8
+ /\bprocess\.env\[['"]([A-Z][A-Z0-9_]*)['"]\]/g,
9
+ /\b(?:const|let|var)\s*\{\s*([^}]+?)\s*\}\s*=\s*process\.env\b/g,
10
+ ];
11
+ const WORKER_ENV_BINDING_PATTERN = /\benv\.([A-Z][A-Z0-9_]*)\b/g;
12
+ const PROCESS_ENV_IDENTIFIER_PATTERN = /\bprocess\.env\[([A-Z0-9_]+)\]/g;
13
+ const ENV_ASSIGNMENT_PATTERN = /(?:^|[\s"'(])([A-Z][A-Z0-9_]*)=/g;
14
+ const EXPORT_ENV_PATTERN = /(?:^|\n)\s*(?:export\s+)?([A-Z][A-Z0-9_]*)=/g;
15
+ const DEV_INITIALIZE_EXPORT_PATTERN = /(?:^|\n)\s*(?:export\s+|printf\s+'export\s+)([A-Z][A-Z0-9_]*)=/g;
16
+ const DOCKER_ARG_NAME_PATTERN = /(?:^|\n)\s*ARG\s+([A-Z][A-Z0-9_]*)(?:[=\s]|$)/g;
17
+ const DOCKER_ENV_NAME_PATTERN = /(?:^|\n)\s*ENV\s+([A-Z][A-Z0-9_]*)(?:[=\s]|$)/g;
18
+ const WRANGLER_JSONC_ENV_NAME_PATTERN = /"([A-Z][A-Z0-9_]*)"\s*:/g;
19
+ const MARKDOWN_CODE_ENV_PATTERN = /`([A-Z][A-Z0-9_]{2,})`/g;
20
+ export function collectEnvVarsFromFile(file, source, envVars, envConstants, rules, helperNames) {
21
+ const isMarkdown = rules.markdown === true;
22
+ if (!isMarkdown) {
23
+ for (const pattern of PROCESS_ENV_PATTERNS) {
24
+ for (const name of matchEnvNames(source, pattern))
25
+ addEnvVar(envVars, name, file, 'readers');
26
+ }
27
+ for (const name of matchConstantIndexedEnvNames(source, envConstants))
28
+ addEnvVar(envVars, name, file, 'readers');
29
+ for (const name of matchHelperNames(source, helperNames))
30
+ addEnvVar(envVars, name, file, 'readers');
31
+ for (const name of matchLocalEnvWrapperCallNames(source, envConstants))
32
+ addEnvVar(envVars, name, file, 'readers');
33
+ if (rules.workerBindings) {
34
+ for (const name of matchEnvNames(source, WORKER_ENV_BINDING_PATTERN))
35
+ addEnvVar(envVars, name, file, 'readers');
36
+ }
37
+ }
38
+ if (rules.localAssignments) {
39
+ for (const name of matchEnvNames(source, EXPORT_ENV_PATTERN)) {
40
+ addEnvVar(envVars, name, file, 'localSetup');
41
+ }
42
+ }
43
+ if (rules.shellExports) {
44
+ for (const name of matchEnvNames(source, DEV_INITIALIZE_EXPORT_PATTERN)) {
45
+ addEnvVar(envVars, name, file, 'localSetup');
46
+ }
47
+ }
48
+ if (rules.jsonBindings) {
49
+ for (const name of matchEnvNames(source, WRANGLER_JSONC_ENV_NAME_PATTERN)) {
50
+ addEnvVar(envVars, name, file, 'localSetup');
51
+ }
52
+ }
53
+ if (rules.docker) {
54
+ for (const name of matchEnvNames(source, DOCKER_ARG_NAME_PATTERN)) {
55
+ addEnvVar(envVars, name, file, 'deployment');
56
+ addEnvVar(envVars, name, file, 'dockerBuildArgs');
57
+ }
58
+ for (const name of matchEnvNames(source, DOCKER_ENV_NAME_PATTERN)) {
59
+ addEnvVar(envVars, name, file, 'deployment');
60
+ }
61
+ }
62
+ if (rules.workflow) {
63
+ for (const name of matchWorkflowEnvMapNames(source)) {
64
+ addEnvVar(envVars, name, file, 'workflows');
65
+ }
66
+ }
67
+ if (rules.markdown) {
68
+ for (const name of matchEnvNames(source, MARKDOWN_CODE_ENV_PATTERN))
69
+ addEnvVar(envVars, name, file, 'docs');
70
+ }
71
+ if (rules.packageManifest) {
72
+ for (const name of matchEnvNames(source, ENV_ASSIGNMENT_PATTERN))
73
+ addEnvVar(envVars, name, file, 'packageGates');
74
+ }
75
+ }
76
+ export function collectEnvVarReferencesFromFile(file, source, envVars, referenceMatchers, buckets) {
77
+ if (buckets.length === 0)
78
+ return;
79
+ const names = namesAlreadySeen(source, referenceMatchers);
80
+ for (const bucket of buckets) {
81
+ for (const name of names)
82
+ addEnvVar(envVars, name, file, bucket);
83
+ }
84
+ }
85
+ function matchEnvNames(source, pattern) {
86
+ if (pattern === PROCESS_ENV_PATTERNS[2]) {
87
+ return [...source.matchAll(pattern)].flatMap((match) => parseDestructuredEnvNames(match[1]));
88
+ }
89
+ return matchNames(source, pattern);
90
+ }
91
+ function parseDestructuredEnvNames(bindingList) {
92
+ return bindingList.split(',').flatMap((binding) => {
93
+ const name = binding.trim().match(/^([A-Z][A-Z0-9_]*)\b/)?.[1];
94
+ return name ? [name] : [];
95
+ });
96
+ }
97
+ function matchConstantIndexedEnvNames(source, envConstants) {
98
+ return [...source.matchAll(PROCESS_ENV_IDENTIFIER_PATTERN)].flatMap((match) => {
99
+ const name = envConstants.get(match[1]);
100
+ return name ? [name] : [];
101
+ });
102
+ }
103
+ function matchHelperNames(source, names) {
104
+ if (names.length === 0)
105
+ return [];
106
+ const pattern = new RegExp(String.raw `(?<![\w$])(?:${names.map((name) => name.replace(/[.*+?^${}()|[\]\\]/g, (character) => `\\${character}`)).join('|')})\(\s*['"]([A-Z][A-Z0-9_]*)['"]`, 'g');
107
+ return matchNames(source, pattern);
108
+ }
@@ -0,0 +1,2 @@
1
+ import type { ConfigInventory } from './types.mts';
2
+ export declare function formatConfigInventoryMarkdown(inventory: ConfigInventory): string;
@@ -0,0 +1,69 @@
1
+ export function formatConfigInventoryMarkdown(inventory) {
2
+ return [
3
+ '# Configuration Inventory',
4
+ '',
5
+ 'Generated from caller-selected repository files.',
6
+ '',
7
+ '## Environment Variables',
8
+ '',
9
+ '| Name | Classifications | Contract | Source of truth | Sensitivity | Surfaces | Readers | Local setup | Deployment | Docker build args | Workflows | Docs | Package gates | Review |',
10
+ '| ---- | --------------- | -------- | --------------- | ----------- | -------- | ------- | ----------- | ---------- | ----------------- | --------- | ---- | ------------- | ------ |',
11
+ ...inventory.envVars.map((row) => tableRow([
12
+ code(row.name),
13
+ row.classifications.map(code).join(', '),
14
+ row.contractKeys.map(code).join('<br>'),
15
+ row.sourceOfTruth ? code(row.sourceOfTruth) : '',
16
+ row.sensitivity ? code(row.sensitivity) : '',
17
+ row.runtimeSurfaces.map(code).join('<br>'),
18
+ formatFiles(row.readers),
19
+ formatFiles(row.localSetup),
20
+ formatFiles(row.deployment),
21
+ formatFiles(row.dockerBuildArgs),
22
+ formatFiles(row.workflows),
23
+ formatFiles(row.docs),
24
+ formatFiles(row.packageGates),
25
+ escapeTextCell(row.reviewReason ?? ''),
26
+ ])),
27
+ '',
28
+ '## Dynamic Configuration Namespaces',
29
+ '',
30
+ '| Namespace | Definitions | Registry |',
31
+ '| --------- | ----------- | -------------- |',
32
+ ...inventory.dynamicConfigs.map((row) => tableRow([
33
+ code(row.namespace),
34
+ formatFiles(row.definitionFiles),
35
+ formatFiles(row.registryFiles),
36
+ ])),
37
+ '',
38
+ '## Package-Manager Gates',
39
+ '',
40
+ '| Gate | Values | Files |',
41
+ '| ---- | ------ | ----- |',
42
+ ...inventory.packageGates.map((row) => tableRow([code(row.name), row.values.map(code).join(', '), formatFiles(row.files)])),
43
+ '',
44
+ ].join('\n');
45
+ }
46
+ function formatFiles(files) {
47
+ return files.length === 0 ? '' : files.map((file) => code(file)).join('<br>');
48
+ }
49
+ function tableRow(cells) {
50
+ return `| ${cells.join(' | ')} |`;
51
+ }
52
+ function code(value) {
53
+ const delimiter = '`'.repeat(Math.max(0, ...[...value.matchAll(/`+/g)].map((match) => match[0].length)) + 1);
54
+ const content = escapeCodeCell(value);
55
+ const padding = content.includes('`') || content.startsWith(' ') || content.endsWith(' ') ? ' ' : '';
56
+ return `${delimiter}${padding}${content}${padding}${delimiter}`;
57
+ }
58
+ function escapeCodeCell(value) {
59
+ return value.replaceAll('|', String.raw `\|`).replaceAll(/\r\n|\r|\n/g, ' ');
60
+ }
61
+ function escapeTextCell(value) {
62
+ return value
63
+ .replaceAll('&', '&amp;')
64
+ .replaceAll('|', '&#124;')
65
+ .replaceAll('<', '&lt;')
66
+ .replaceAll('>', '&gt;')
67
+ .replaceAll('`', '&#96;')
68
+ .replaceAll(/\r\n|\r|\n/g, ' ');
69
+ }
@@ -0,0 +1,3 @@
1
+ export { collectConfigInventory } from './collect.mts';
2
+ export { formatConfigInventoryMarkdown } from './format.mts';
3
+ export type { ConfigInventory, ConfigInventoryContext, ConfigInventoryOptions, ConfigSourceRules, DynamicConfigInventoryRow, DynamicConfigReference, EnvClassification, EnvVarInventoryRow, PackageGateInventoryRow, SourceBucket, TypedEnvContractEntry, } from './types.mts';
@@ -0,0 +1,2 @@
1
+ export { collectConfigInventory } from './collect.mjs';
2
+ export { formatConfigInventoryMarkdown } from './format.mjs';
@@ -0,0 +1,2 @@
1
+ import type { PackageGateInventoryRow } from './types.mts';
2
+ export declare function collectPackageGatesFromFile(file: string, source: string, packageGates: Map<string, PackageGateInventoryRow>): void;
@@ -0,0 +1,54 @@
1
+ import { parse as load } from 'yaml';
2
+ const PACKAGE_GATE_KEYS = [
3
+ 'allowBuilds',
4
+ 'dangerouslyAllowAllBuilds',
5
+ 'ignoredOptionalDependencies',
6
+ 'minimumReleaseAge',
7
+ 'minimumReleaseAgeExclude',
8
+ 'overrides',
9
+ 'packageExtensions',
10
+ 'strictDepBuilds',
11
+ ];
12
+ export function collectPackageGatesFromFile(file, source, packageGates) {
13
+ let parsed;
14
+ try {
15
+ parsed = load(source);
16
+ }
17
+ catch {
18
+ return;
19
+ }
20
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
21
+ return;
22
+ for (const key of PACKAGE_GATE_KEYS) {
23
+ const values = extractPackageGateValues(parsed[key]);
24
+ if (values.length === 0)
25
+ continue;
26
+ const existing = packageGates.get(key);
27
+ packageGates.set(key, {
28
+ name: key,
29
+ values: [...new Set([...(existing?.values ?? []), ...values])].sort(),
30
+ files: [...new Set([...(existing?.files ?? []), file])].sort(),
31
+ });
32
+ }
33
+ }
34
+ function extractPackageGateValues(value) {
35
+ if (Array.isArray(value)) {
36
+ return value.flatMap((entry) => (isScalarValue(entry) ? [String(entry)] : []));
37
+ }
38
+ if (isPlainObject(value)) {
39
+ return Object.keys(value);
40
+ }
41
+ return isScalarValue(value) ? [String(value)] : [];
42
+ }
43
+ function isPlainObject(value) {
44
+ if (!value || typeof value !== 'object' || Array.isArray(value))
45
+ return false;
46
+ const prototype = Object.getPrototypeOf(value);
47
+ return prototype === Object.prototype;
48
+ }
49
+ function isScalarValue(value) {
50
+ return (typeof value === 'string' ||
51
+ typeof value === 'number' ||
52
+ typeof value === 'boolean' ||
53
+ value instanceof Date);
54
+ }
@@ -0,0 +1,3 @@
1
+ export declare const ENV_NAME_PATTERN: RegExp;
2
+ export declare function matchNames(source: string, pattern: RegExp): string[];
3
+ export declare function sorted(values: Iterable<string>): string[];
@@ -0,0 +1,7 @@
1
+ export const ENV_NAME_PATTERN = /^[A-Z][A-Z0-9_]*$/;
2
+ export function matchNames(source, pattern) {
3
+ return [...source.matchAll(pattern)].flatMap((match) => (match[1] ? [match[1]] : []));
4
+ }
5
+ export function sorted(values) {
6
+ return [...values].toSorted((a, b) => a.localeCompare(b));
7
+ }