@contractspec/module.workspace 0.0.0-canary-20260113162409

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 (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -0
  3. package/dist/ai/prompts/code-generation.d.ts +24 -0
  4. package/dist/ai/prompts/code-generation.d.ts.map +1 -0
  5. package/dist/ai/prompts/code-generation.js +134 -0
  6. package/dist/ai/prompts/code-generation.js.map +1 -0
  7. package/dist/ai/prompts/spec-creation.d.ts +28 -0
  8. package/dist/ai/prompts/spec-creation.d.ts.map +1 -0
  9. package/dist/ai/prompts/spec-creation.js +102 -0
  10. package/dist/ai/prompts/spec-creation.js.map +1 -0
  11. package/dist/analysis/deps/graph.d.ts +34 -0
  12. package/dist/analysis/deps/graph.d.ts.map +1 -0
  13. package/dist/analysis/deps/graph.js +85 -0
  14. package/dist/analysis/deps/graph.js.map +1 -0
  15. package/dist/analysis/deps/parse-imports.d.ts +17 -0
  16. package/dist/analysis/deps/parse-imports.d.ts.map +1 -0
  17. package/dist/analysis/deps/parse-imports.js +31 -0
  18. package/dist/analysis/deps/parse-imports.js.map +1 -0
  19. package/dist/analysis/diff/deep-diff.d.ts +33 -0
  20. package/dist/analysis/diff/deep-diff.d.ts.map +1 -0
  21. package/dist/analysis/diff/deep-diff.js +114 -0
  22. package/dist/analysis/diff/deep-diff.js.map +1 -0
  23. package/dist/analysis/diff/semantic.d.ts +11 -0
  24. package/dist/analysis/diff/semantic.d.ts.map +1 -0
  25. package/dist/analysis/diff/semantic.js +97 -0
  26. package/dist/analysis/diff/semantic.js.map +1 -0
  27. package/dist/analysis/example-scan.d.ts +15 -0
  28. package/dist/analysis/example-scan.d.ts.map +1 -0
  29. package/dist/analysis/example-scan.js +116 -0
  30. package/dist/analysis/example-scan.js.map +1 -0
  31. package/dist/analysis/feature-extractor.js +203 -0
  32. package/dist/analysis/feature-extractor.js.map +1 -0
  33. package/dist/analysis/feature-scan.d.ts +15 -0
  34. package/dist/analysis/feature-scan.d.ts.map +1 -0
  35. package/dist/analysis/feature-scan.js +56 -0
  36. package/dist/analysis/feature-scan.js.map +1 -0
  37. package/dist/analysis/grouping.d.ts +79 -0
  38. package/dist/analysis/grouping.d.ts.map +1 -0
  39. package/dist/analysis/grouping.js +115 -0
  40. package/dist/analysis/grouping.js.map +1 -0
  41. package/dist/analysis/impact/classifier.d.ts +19 -0
  42. package/dist/analysis/impact/classifier.d.ts.map +1 -0
  43. package/dist/analysis/impact/classifier.js +135 -0
  44. package/dist/analysis/impact/classifier.js.map +1 -0
  45. package/dist/analysis/impact/index.js +2 -0
  46. package/dist/analysis/impact/rules.d.ts +35 -0
  47. package/dist/analysis/impact/rules.d.ts.map +1 -0
  48. package/dist/analysis/impact/rules.js +154 -0
  49. package/dist/analysis/impact/rules.js.map +1 -0
  50. package/dist/analysis/impact/types.d.ts +95 -0
  51. package/dist/analysis/impact/types.d.ts.map +1 -0
  52. package/dist/analysis/index.js +18 -0
  53. package/dist/analysis/snapshot/index.js +2 -0
  54. package/dist/analysis/snapshot/normalizer.d.ts +36 -0
  55. package/dist/analysis/snapshot/normalizer.d.ts.map +1 -0
  56. package/dist/analysis/snapshot/normalizer.js +67 -0
  57. package/dist/analysis/snapshot/normalizer.js.map +1 -0
  58. package/dist/analysis/snapshot/snapshot.d.ts +18 -0
  59. package/dist/analysis/snapshot/snapshot.d.ts.map +1 -0
  60. package/dist/analysis/snapshot/snapshot.js +163 -0
  61. package/dist/analysis/snapshot/snapshot.js.map +1 -0
  62. package/dist/analysis/snapshot/types.d.ts +74 -0
  63. package/dist/analysis/snapshot/types.d.ts.map +1 -0
  64. package/dist/analysis/spec-parser.d.ts +11 -0
  65. package/dist/analysis/spec-parser.d.ts.map +1 -0
  66. package/dist/analysis/spec-parser.js +89 -0
  67. package/dist/analysis/spec-parser.js.map +1 -0
  68. package/dist/analysis/spec-parsing-utils.d.ts +26 -0
  69. package/dist/analysis/spec-parsing-utils.d.ts.map +1 -0
  70. package/dist/analysis/spec-parsing-utils.js +98 -0
  71. package/dist/analysis/spec-parsing-utils.js.map +1 -0
  72. package/dist/analysis/spec-scan.d.ts +20 -0
  73. package/dist/analysis/spec-scan.d.ts.map +1 -0
  74. package/dist/analysis/spec-scan.js +141 -0
  75. package/dist/analysis/spec-scan.js.map +1 -0
  76. package/dist/analysis/utils/matchers.js +77 -0
  77. package/dist/analysis/utils/matchers.js.map +1 -0
  78. package/dist/analysis/utils/variables.js +45 -0
  79. package/dist/analysis/utils/variables.js.map +1 -0
  80. package/dist/analysis/validate/index.js +1 -0
  81. package/dist/analysis/validate/spec-structure.d.ts +29 -0
  82. package/dist/analysis/validate/spec-structure.d.ts.map +1 -0
  83. package/dist/analysis/validate/spec-structure.js +455 -0
  84. package/dist/analysis/validate/spec-structure.js.map +1 -0
  85. package/dist/formatter.d.ts +42 -0
  86. package/dist/formatter.d.ts.map +1 -0
  87. package/dist/formatter.js +163 -0
  88. package/dist/formatter.js.map +1 -0
  89. package/dist/formatters/index.js +2 -0
  90. package/dist/formatters/spec-markdown.d.ts +31 -0
  91. package/dist/formatters/spec-markdown.d.ts.map +1 -0
  92. package/dist/formatters/spec-markdown.js +263 -0
  93. package/dist/formatters/spec-markdown.js.map +1 -0
  94. package/dist/formatters/spec-to-docblock.d.ts +14 -0
  95. package/dist/formatters/spec-to-docblock.d.ts.map +1 -0
  96. package/dist/formatters/spec-to-docblock.js +48 -0
  97. package/dist/formatters/spec-to-docblock.js.map +1 -0
  98. package/dist/index.d.ts +42 -0
  99. package/dist/index.js +39 -0
  100. package/dist/templates/app-config.d.ts +7 -0
  101. package/dist/templates/app-config.d.ts.map +1 -0
  102. package/dist/templates/app-config.js +107 -0
  103. package/dist/templates/app-config.js.map +1 -0
  104. package/dist/templates/data-view.d.ts +7 -0
  105. package/dist/templates/data-view.d.ts.map +1 -0
  106. package/dist/templates/data-view.js +69 -0
  107. package/dist/templates/data-view.js.map +1 -0
  108. package/dist/templates/event.d.ts +11 -0
  109. package/dist/templates/event.d.ts.map +1 -0
  110. package/dist/templates/event.js +41 -0
  111. package/dist/templates/event.js.map +1 -0
  112. package/dist/templates/experiment.d.ts +7 -0
  113. package/dist/templates/experiment.d.ts.map +1 -0
  114. package/dist/templates/experiment.js +88 -0
  115. package/dist/templates/experiment.js.map +1 -0
  116. package/dist/templates/handler.d.ts +20 -0
  117. package/dist/templates/handler.d.ts.map +1 -0
  118. package/dist/templates/handler.js +96 -0
  119. package/dist/templates/handler.js.map +1 -0
  120. package/dist/templates/integration-utils.js +105 -0
  121. package/dist/templates/integration-utils.js.map +1 -0
  122. package/dist/templates/integration.d.ts +7 -0
  123. package/dist/templates/integration.d.ts.map +1 -0
  124. package/dist/templates/integration.js +62 -0
  125. package/dist/templates/integration.js.map +1 -0
  126. package/dist/templates/knowledge.d.ts +7 -0
  127. package/dist/templates/knowledge.d.ts.map +1 -0
  128. package/dist/templates/knowledge.js +69 -0
  129. package/dist/templates/knowledge.js.map +1 -0
  130. package/dist/templates/migration.d.ts +7 -0
  131. package/dist/templates/migration.d.ts.map +1 -0
  132. package/dist/templates/migration.js +61 -0
  133. package/dist/templates/migration.js.map +1 -0
  134. package/dist/templates/operation.d.ts +11 -0
  135. package/dist/templates/operation.d.ts.map +1 -0
  136. package/dist/templates/operation.js +101 -0
  137. package/dist/templates/operation.js.map +1 -0
  138. package/dist/templates/presentation.d.ts +11 -0
  139. package/dist/templates/presentation.d.ts.map +1 -0
  140. package/dist/templates/presentation.js +79 -0
  141. package/dist/templates/presentation.js.map +1 -0
  142. package/dist/templates/telemetry.d.ts +7 -0
  143. package/dist/templates/telemetry.d.ts.map +1 -0
  144. package/dist/templates/telemetry.js +90 -0
  145. package/dist/templates/telemetry.js.map +1 -0
  146. package/dist/templates/utils.d.ts +27 -0
  147. package/dist/templates/utils.d.ts.map +1 -0
  148. package/dist/templates/utils.js +39 -0
  149. package/dist/templates/utils.js.map +1 -0
  150. package/dist/templates/workflow-runner.d.ts +16 -0
  151. package/dist/templates/workflow-runner.d.ts.map +1 -0
  152. package/dist/templates/workflow-runner.js +49 -0
  153. package/dist/templates/workflow-runner.js.map +1 -0
  154. package/dist/templates/workflow.d.ts +11 -0
  155. package/dist/templates/workflow.d.ts.map +1 -0
  156. package/dist/templates/workflow.js +68 -0
  157. package/dist/templates/workflow.js.map +1 -0
  158. package/dist/types/analysis-types.d.ts +199 -0
  159. package/dist/types/analysis-types.d.ts.map +1 -0
  160. package/dist/types/generation-types.d.ts +87 -0
  161. package/dist/types/generation-types.d.ts.map +1 -0
  162. package/dist/types/generation-types.js +21 -0
  163. package/dist/types/generation-types.js.map +1 -0
  164. package/dist/types/llm-types.d.ts +138 -0
  165. package/dist/types/llm-types.d.ts.map +1 -0
  166. package/dist/types/rulesync-types.d.ts +24 -0
  167. package/dist/types/rulesync-types.d.ts.map +1 -0
  168. package/dist/types/spec-types.d.ts +343 -0
  169. package/dist/types/spec-types.d.ts.map +1 -0
  170. package/package.json +63 -0
@@ -0,0 +1,42 @@
1
+ import { FormatterConfig, FormatterType } from "@contractspec/lib.contracts";
2
+
3
+ //#region src/formatter.d.ts
4
+
5
+ interface FormatterOptions {
6
+ /** Override formatter type from config */
7
+ type?: FormatterType;
8
+ /** Skip formatting entirely */
9
+ skip?: boolean;
10
+ /** Working directory for formatter */
11
+ cwd?: string;
12
+ /** Silent mode - don't log output */
13
+ silent?: boolean;
14
+ }
15
+ interface FormatResult {
16
+ success: boolean;
17
+ formatted: boolean;
18
+ error?: string;
19
+ duration?: number;
20
+ formatterUsed?: FormatterType;
21
+ }
22
+ /**
23
+ * Auto-detect available formatters in the workspace.
24
+ * Returns the first detected formatter in priority order.
25
+ */
26
+ declare function detectFormatter(cwd?: string): Promise<FormatterType | null>;
27
+ interface FormatLogger {
28
+ log: (message: string) => void;
29
+ warn: (message: string) => void;
30
+ success: (message: string) => void;
31
+ }
32
+ /**
33
+ * Format a single file or array of files.
34
+ */
35
+ declare function formatFiles(files: string | string[], config?: FormatterConfig, options?: FormatterOptions, logger?: FormatLogger): Promise<FormatResult>;
36
+ /**
37
+ * Format files in batch, grouping by directory for efficiency.
38
+ */
39
+ declare function formatFilesBatch(files: string[], config?: FormatterConfig, options?: FormatterOptions, logger?: FormatLogger): Promise<FormatResult>;
40
+ //#endregion
41
+ export { FormatLogger, FormatResult, FormatterOptions, detectFormatter, formatFiles, formatFilesBatch };
42
+ //# sourceMappingURL=formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.d.ts","names":[],"sources":["../src/formatter.ts"],"sourcesContent":[],"mappings":";;;;AAoLiB,UAlKA,gBAAA,CAkKY;EASP;EAEX,IAAA,CAAA,EA3KF,aA2KE;EACC;EACD,IAAA,CAAA,EAAA,OAAA;EACA;EAAR,GAAA,CAAA,EAAA,MAAA;EAAO;EA8EY,MAAA,CAAA,EAAA,OAAA;;AAGV,UAtPK,YAAA,CAsPL;EACD,OAAA,EAAA,OAAA;EACA,SAAA,EAAA,OAAA;EAAR,KAAA,CAAA,EAAA,MAAA;EAAO,QAAA,CAAA,EAAA,MAAA;kBAnPQ;;;;;;iBAkDI,eAAA,gBAEnB,QAAQ;UA8FM,YAAA;;;;;;;;iBASK,WAAA,oCAEX,2BACC,2BACD,eACR,QAAQ;;;;iBA8EW,gBAAA,2BAEX,2BACC,2BACD,eACR,QAAQ"}
@@ -0,0 +1,163 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { exec } from "node:child_process";
3
+ import { promisify } from "node:util";
4
+ import { existsSync } from "node:fs";
5
+ import { dirname, resolve } from "node:path";
6
+
7
+ //#region src/formatter.ts
8
+ /**
9
+ * Formatter utility for ContractSpec CLI.
10
+ *
11
+ * Detects and runs code formatters on generated files.
12
+ */
13
+ const execAsync = promisify(exec);
14
+ /**
15
+ * Config files that indicate a formatter is available.
16
+ */
17
+ const FORMATTER_CONFIG_FILES = {
18
+ prettier: [
19
+ ".prettierrc",
20
+ ".prettierrc.json",
21
+ ".prettierrc.yaml",
22
+ ".prettierrc.yml",
23
+ ".prettierrc.js",
24
+ ".prettierrc.cjs",
25
+ ".prettierrc.mjs",
26
+ "prettier.config.js",
27
+ "prettier.config.cjs",
28
+ "prettier.config.mjs"
29
+ ],
30
+ eslint: [
31
+ ".eslintrc",
32
+ ".eslintrc.json",
33
+ ".eslintrc.yaml",
34
+ ".eslintrc.yml",
35
+ ".eslintrc.js",
36
+ ".eslintrc.cjs",
37
+ "eslint.config.js",
38
+ "eslint.config.mjs",
39
+ "eslint.config.cjs"
40
+ ],
41
+ biome: ["biome.json", "biome.jsonc"],
42
+ dprint: ["dprint.json", ".dprint.json"],
43
+ custom: []
44
+ };
45
+ /**
46
+ * Package.json dependencies that indicate a formatter is available.
47
+ */
48
+ const FORMATTER_PACKAGES = {
49
+ prettier: ["prettier"],
50
+ eslint: ["eslint"],
51
+ biome: ["@biomejs/biome"],
52
+ dprint: ["dprint"],
53
+ custom: []
54
+ };
55
+ /**
56
+ * Auto-detect available formatters in the workspace.
57
+ * Returns the first detected formatter in priority order.
58
+ */
59
+ async function detectFormatter(cwd = process.cwd()) {
60
+ for (const formatter of [
61
+ "prettier",
62
+ "biome",
63
+ "eslint",
64
+ "dprint"
65
+ ]) if (await isFormatterAvailable(formatter, cwd)) return formatter;
66
+ return null;
67
+ }
68
+ /**
69
+ * Check if a specific formatter is available in the workspace.
70
+ */
71
+ async function isFormatterAvailable(formatter, cwd) {
72
+ const configFiles = FORMATTER_CONFIG_FILES[formatter] || [];
73
+ for (const configFile of configFiles) if (existsSync(resolve(cwd, configFile))) return true;
74
+ const packageJsonPath = resolve(cwd, "package.json");
75
+ if (existsSync(packageJsonPath)) try {
76
+ const packageJson = JSON.parse(await readFile(packageJsonPath, "utf-8"));
77
+ const allDeps = {
78
+ ...packageJson.dependencies,
79
+ ...packageJson.devDependencies
80
+ };
81
+ const packages = FORMATTER_PACKAGES[formatter] || [];
82
+ for (const pkg of packages) if (pkg in allDeps) return true;
83
+ } catch {}
84
+ const parentDir = dirname(cwd);
85
+ if (parentDir !== cwd && parentDir !== "/") return isFormatterAvailable(formatter, parentDir);
86
+ return false;
87
+ }
88
+ /**
89
+ * Get the command for a specific formatter type.
90
+ */
91
+ function getFormatterCommand(type, files, config) {
92
+ const fileArgs = files.map((f) => `"${f}"`).join(" ");
93
+ const extraArgs = config?.args?.join(" ") || "";
94
+ switch (type) {
95
+ case "prettier": return `bunx prettier --write ${extraArgs} ${fileArgs}`;
96
+ case "eslint": return `bunx eslint --fix ${extraArgs} ${fileArgs}`;
97
+ case "biome": return `bunx @biomejs/biome format --write ${extraArgs} ${fileArgs}`;
98
+ case "dprint": return `bunx dprint fmt ${extraArgs} ${fileArgs}`;
99
+ case "custom":
100
+ if (!config?.command) throw new Error("Custom formatter requires a command to be specified in config");
101
+ return `${config.command} ${extraArgs} ${fileArgs}`;
102
+ default: throw new Error(`Unknown formatter type: ${type}`);
103
+ }
104
+ }
105
+ /**
106
+ * Format a single file or array of files.
107
+ */
108
+ async function formatFiles(files, config, options, logger) {
109
+ const startTime = Date.now();
110
+ const fileList = Array.isArray(files) ? files : [files];
111
+ const cwd = options?.cwd || process.cwd();
112
+ if (options?.skip || config?.enabled === false) return {
113
+ success: true,
114
+ formatted: false,
115
+ duration: Date.now() - startTime
116
+ };
117
+ let formatterType = options?.type || config?.type;
118
+ if (!formatterType) {
119
+ const detected = await detectFormatter(cwd);
120
+ if (!detected) return {
121
+ success: true,
122
+ formatted: false,
123
+ duration: Date.now() - startTime
124
+ };
125
+ formatterType = detected;
126
+ }
127
+ const command = getFormatterCommand(formatterType, fileList, config);
128
+ const timeout = config?.timeout || 3e4;
129
+ if (!options?.silent && logger) logger.log(`🎨 Formatting ${fileList.length} file(s) with ${formatterType}...`);
130
+ try {
131
+ await execAsync(command, {
132
+ cwd,
133
+ timeout
134
+ });
135
+ if (!options?.silent && logger) logger.success(`✅ Formatted ${fileList.length} file(s)`);
136
+ return {
137
+ success: true,
138
+ formatted: true,
139
+ duration: Date.now() - startTime,
140
+ formatterUsed: formatterType
141
+ };
142
+ } catch (error) {
143
+ const errorMessage = error instanceof Error ? error.message : String(error);
144
+ if (!options?.silent && logger) logger.warn(`⚠️ Formatting failed (continuing anyway): ${errorMessage}`);
145
+ return {
146
+ success: false,
147
+ formatted: false,
148
+ error: errorMessage,
149
+ duration: Date.now() - startTime,
150
+ formatterUsed: formatterType
151
+ };
152
+ }
153
+ }
154
+ /**
155
+ * Format files in batch, grouping by directory for efficiency.
156
+ */
157
+ async function formatFilesBatch(files, config, options, logger) {
158
+ return formatFiles(files, config, options, logger);
159
+ }
160
+
161
+ //#endregion
162
+ export { detectFormatter, formatFiles, formatFilesBatch };
163
+ //# sourceMappingURL=formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.js","names":[],"sources":["../src/formatter.ts"],"sourcesContent":["/**\n * Formatter utility for ContractSpec CLI.\n *\n * Detects and runs code formatters on generated files.\n */\n\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { readFile } from 'node:fs/promises';\nimport type {\n FormatterConfig,\n FormatterType,\n} from '@contractspec/lib.contracts';\n\nconst execAsync = promisify(exec);\n\nexport interface FormatterOptions {\n /** Override formatter type from config */\n type?: FormatterType;\n /** Skip formatting entirely */\n skip?: boolean;\n /** Working directory for formatter */\n cwd?: string;\n /** Silent mode - don't log output */\n silent?: boolean;\n}\n\nexport interface FormatResult {\n success: boolean;\n formatted: boolean;\n error?: string;\n duration?: number;\n formatterUsed?: FormatterType;\n}\n\n/**\n * Config files that indicate a formatter is available.\n */\nconst FORMATTER_CONFIG_FILES: Record<FormatterType, string[]> = {\n prettier: [\n '.prettierrc',\n '.prettierrc.json',\n '.prettierrc.yaml',\n '.prettierrc.yml',\n '.prettierrc.js',\n '.prettierrc.cjs',\n '.prettierrc.mjs',\n 'prettier.config.js',\n 'prettier.config.cjs',\n 'prettier.config.mjs',\n ],\n eslint: [\n '.eslintrc',\n '.eslintrc.json',\n '.eslintrc.yaml',\n '.eslintrc.yml',\n '.eslintrc.js',\n '.eslintrc.cjs',\n 'eslint.config.js',\n 'eslint.config.mjs',\n 'eslint.config.cjs',\n ],\n biome: ['biome.json', 'biome.jsonc'],\n dprint: ['dprint.json', '.dprint.json'],\n custom: [],\n};\n\n/**\n * Package.json dependencies that indicate a formatter is available.\n */\nconst FORMATTER_PACKAGES: Record<FormatterType, string[]> = {\n prettier: ['prettier'],\n eslint: ['eslint'],\n biome: ['@biomejs/biome'],\n dprint: ['dprint'],\n custom: [],\n};\n\n/**\n * Auto-detect available formatters in the workspace.\n * Returns the first detected formatter in priority order.\n */\nexport async function detectFormatter(\n cwd: string = process.cwd()\n): Promise<FormatterType | null> {\n // Priority order for formatters\n const priority: FormatterType[] = ['prettier', 'biome', 'eslint', 'dprint'];\n\n for (const formatter of priority) {\n if (await isFormatterAvailable(formatter, cwd)) {\n return formatter;\n }\n }\n\n return null;\n}\n\n/**\n * Check if a specific formatter is available in the workspace.\n */\nasync function isFormatterAvailable(\n formatter: FormatterType,\n cwd: string\n): Promise<boolean> {\n // Check for config files\n const configFiles = FORMATTER_CONFIG_FILES[formatter] || [];\n for (const configFile of configFiles) {\n if (existsSync(resolve(cwd, configFile))) {\n return true;\n }\n }\n\n // Check package.json dependencies\n const packageJsonPath = resolve(cwd, 'package.json');\n if (existsSync(packageJsonPath)) {\n try {\n const packageJson = JSON.parse(\n await readFile(packageJsonPath, 'utf-8')\n ) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n const packages = FORMATTER_PACKAGES[formatter] || [];\n for (const pkg of packages) {\n if (pkg in allDeps) {\n return true;\n }\n }\n } catch {\n // Ignore parse errors\n }\n }\n\n // Walk up to find monorepo root\n const parentDir = dirname(cwd);\n if (parentDir !== cwd && parentDir !== '/') {\n return isFormatterAvailable(formatter, parentDir);\n }\n\n return false;\n}\n\n/**\n * Get the command for a specific formatter type.\n */\nfunction getFormatterCommand(\n type: FormatterType,\n files: string[],\n config?: FormatterConfig\n): string {\n const fileArgs = files.map((f) => `\"${f}\"`).join(' ');\n const extraArgs = config?.args?.join(' ') || '';\n\n switch (type) {\n case 'prettier':\n return `bunx prettier --write ${extraArgs} ${fileArgs}`;\n case 'eslint':\n return `bunx eslint --fix ${extraArgs} ${fileArgs}`;\n case 'biome':\n return `bunx @biomejs/biome format --write ${extraArgs} ${fileArgs}`;\n case 'dprint':\n return `bunx dprint fmt ${extraArgs} ${fileArgs}`;\n case 'custom':\n if (!config?.command) {\n throw new Error(\n 'Custom formatter requires a command to be specified in config'\n );\n }\n return `${config.command} ${extraArgs} ${fileArgs}`;\n default:\n throw new Error(`Unknown formatter type: ${type}`);\n }\n}\n\nexport interface FormatLogger {\n log: (message: string) => void;\n warn: (message: string) => void;\n success: (message: string) => void;\n}\n\n/**\n * Format a single file or array of files.\n */\nexport async function formatFiles(\n files: string | string[],\n config?: FormatterConfig,\n options?: FormatterOptions,\n logger?: FormatLogger\n): Promise<FormatResult> {\n const startTime = Date.now();\n const fileList = Array.isArray(files) ? files : [files];\n const cwd = options?.cwd || process.cwd();\n\n // Skip if explicitly disabled\n if (options?.skip || config?.enabled === false) {\n return {\n success: true,\n formatted: false,\n duration: Date.now() - startTime,\n };\n }\n\n // Determine formatter to use\n let formatterType = options?.type || config?.type;\n\n // Auto-detect if not specified\n if (!formatterType) {\n const detected = await detectFormatter(cwd);\n if (!detected) {\n // No formatter available - silently skip\n return {\n success: true,\n formatted: false,\n duration: Date.now() - startTime,\n };\n }\n formatterType = detected;\n }\n\n // Build command\n const command = getFormatterCommand(formatterType, fileList, config);\n const timeout = config?.timeout || 30000;\n\n if (!options?.silent && logger) {\n logger.log(\n `🎨 Formatting ${fileList.length} file(s) with ${formatterType}...`\n );\n }\n\n try {\n await execAsync(command, {\n cwd,\n timeout,\n });\n\n if (!options?.silent && logger) {\n logger.success(`✅ Formatted ${fileList.length} file(s)`);\n }\n\n return {\n success: true,\n formatted: true,\n duration: Date.now() - startTime,\n formatterUsed: formatterType,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // Log warning but don't fail the operation\n if (!options?.silent && logger) {\n logger.warn(`⚠️ Formatting failed (continuing anyway): ${errorMessage}`);\n }\n\n return {\n success: false,\n formatted: false,\n error: errorMessage,\n duration: Date.now() - startTime,\n formatterUsed: formatterType,\n };\n }\n}\n\n/**\n * Format files in batch, grouping by directory for efficiency.\n */\nexport async function formatFilesBatch(\n files: string[],\n config?: FormatterConfig,\n options?: FormatterOptions,\n logger?: FormatLogger\n): Promise<FormatResult> {\n // For now, just format all files together\n // Future optimization: group by directory and run formatter per directory\n return formatFiles(files, config, options, logger);\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { combineSpecMarkdowns, generateSpecsSummaryHeader, specToMarkdown, specToMarkdownWithOptions } from "./spec-markdown.js";
2
+ import { convertSpecToDocBlock } from "./spec-to-docblock.js";
@@ -0,0 +1,31 @@
1
+ import { LLMExportFormat, ParsedSpec, SpecToMarkdownOptions } from "../types/llm-types.js";
2
+
3
+ //#region src/formatters/spec-markdown.d.ts
4
+
5
+ /**
6
+ * Generate markdown from a parsed spec.
7
+ *
8
+ * Formats:
9
+ * - **full**: Complete information including source code and all details (for deep LLM context)
10
+ * - **prompt**: Concise with implementation instructions (actionable for LLM)
11
+ * - **context**: Brief summary with counts and key fields (lightweight overview)
12
+ */
13
+ declare function specToMarkdown(spec: ParsedSpec, format: LLMExportFormat, optionsOrDepth?: number | {
14
+ depth?: number;
15
+ rootPath?: string;
16
+ }): string;
17
+ /**
18
+ * Convert spec to markdown with custom options.
19
+ */
20
+ declare function specToMarkdownWithOptions(spec: ParsedSpec, options: SpecToMarkdownOptions): string;
21
+ /**
22
+ * Generate a summary header for multiple specs.
23
+ */
24
+ declare function generateSpecsSummaryHeader(specs: ParsedSpec[], format: LLMExportFormat): string;
25
+ /**
26
+ * Combine multiple spec markdowns into a single document.
27
+ */
28
+ declare function combineSpecMarkdowns(specs: ParsedSpec[], format: LLMExportFormat): string;
29
+ //#endregion
30
+ export { combineSpecMarkdowns, generateSpecsSummaryHeader, specToMarkdown, specToMarkdownWithOptions };
31
+ //# sourceMappingURL=spec-markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-markdown.d.ts","names":[],"sources":["../../src/formatters/spec-markdown.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;iBAuBgB,cAAA,OACR,oBACE;;;;;;;iBA4WM,yBAAA,OACR,qBACG;;;;iBAQK,0BAAA,QACP,sBACC;;;;iBAiCM,oBAAA,QACP,sBACC"}
@@ -0,0 +1,263 @@
1
+ import * as path from "node:path";
2
+
3
+ //#region src/formatters/spec-markdown.ts
4
+ /**
5
+ * Generate markdown from a parsed spec.
6
+ *
7
+ * Formats:
8
+ * - **full**: Complete information including source code and all details (for deep LLM context)
9
+ * - **prompt**: Concise with implementation instructions (actionable for LLM)
10
+ * - **context**: Brief summary with counts and key fields (lightweight overview)
11
+ */
12
+ function specToMarkdown(spec, format, optionsOrDepth = 0) {
13
+ const options = typeof optionsOrDepth === "number" ? { depth: optionsOrDepth } : optionsOrDepth;
14
+ const depth = options.depth ?? 0;
15
+ const rootPath = options.rootPath;
16
+ const lines = [];
17
+ const indent = depth > 0 ? " ".repeat(depth) : "";
18
+ const headerLevel = Math.min(depth + 1, 6);
19
+ const headerPrefix = "#".repeat(headerLevel);
20
+ lines.push(`${indent}${headerPrefix} ${spec.meta.key}`);
21
+ lines.push("");
22
+ if (spec.meta.description) {
23
+ lines.push(`${indent}${spec.meta.description}`);
24
+ lines.push("");
25
+ }
26
+ if (format === "context") return formatContextMode(spec, lines, indent);
27
+ if (format === "prompt") return formatPromptMode(spec, lines, indent);
28
+ return formatFullMode(spec, lines, indent, rootPath);
29
+ }
30
+ /**
31
+ * Format spec in context mode (brief summary).
32
+ */
33
+ function formatContextMode(spec, lines, indent) {
34
+ const metaParts = [];
35
+ metaParts.push(`**${spec.specType}**`);
36
+ if (spec.kind && spec.kind !== "unknown") metaParts.push(`(${spec.kind})`);
37
+ metaParts.push(`v${spec.meta.version}`);
38
+ if (spec.meta.stability) metaParts.push(`[${spec.meta.stability}]`);
39
+ lines.push(`${indent}${metaParts.join(" ")}`);
40
+ lines.push("");
41
+ if (spec.specType === "feature") {
42
+ const counts = [];
43
+ if (spec.operations?.length) counts.push(`${spec.operations.length} operation(s)`);
44
+ if (spec.events?.length) counts.push(`${spec.events.length} event(s)`);
45
+ if (spec.presentations?.length) counts.push(`${spec.presentations.length} presentation(s)`);
46
+ if (counts.length > 0) {
47
+ lines.push(`${indent}Contains: ${counts.join(", ")}`);
48
+ lines.push("");
49
+ }
50
+ }
51
+ if (spec.specType === "operation") {
52
+ const indicators = [];
53
+ if (spec.hasIo) indicators.push("I/O");
54
+ if (spec.hasPolicy) indicators.push("Policy");
55
+ if (spec.emittedEvents?.length) indicators.push(`${spec.emittedEvents.length} event(s)`);
56
+ if (indicators.length > 0) {
57
+ lines.push(`${indent}Includes: ${indicators.join(", ")}`);
58
+ lines.push("");
59
+ }
60
+ }
61
+ return lines.join("\n");
62
+ }
63
+ /**
64
+ * Format spec in prompt mode (implementation-focused).
65
+ */
66
+ function formatPromptMode(spec, lines, indent) {
67
+ lines.push(`${indent}**Type**: ${spec.specType}${spec.kind && spec.kind !== "unknown" ? ` (${spec.kind})` : ""}`);
68
+ lines.push(`${indent}**Version**: ${spec.meta.version}`);
69
+ if (spec.meta.stability) lines.push(`${indent}**Stability**: ${spec.meta.stability}`);
70
+ if (spec.meta.owners?.length) lines.push(`${indent}**Owners**: ${spec.meta.owners.join(", ")}`);
71
+ if (spec.meta.tags?.length) lines.push(`${indent}**Tags**: ${spec.meta.tags.join(", ")}`);
72
+ lines.push("");
73
+ if (spec.meta.goal) {
74
+ lines.push(`${indent}**Goal**: ${spec.meta.goal}`);
75
+ lines.push("");
76
+ }
77
+ if (spec.meta.context) {
78
+ lines.push(`${indent}**Context**: ${spec.meta.context}`);
79
+ lines.push("");
80
+ }
81
+ if (spec.specType === "operation") {
82
+ const structure = [];
83
+ if (spec.hasIo) structure.push("Input/Output Schema");
84
+ if (spec.hasPolicy) structure.push("Policy Enforcement");
85
+ if (spec.hasPayload) structure.push("Payload");
86
+ if (spec.hasContent) structure.push("Content");
87
+ if (structure.length > 0) {
88
+ lines.push(`${indent}**Structure**: ${structure.join(", ")}`);
89
+ lines.push("");
90
+ }
91
+ }
92
+ if (spec.specType === "feature") appendFeatureRefs(spec, lines, indent);
93
+ if (spec.emittedEvents?.length) {
94
+ lines.push(`${indent}**Emits**: ${formatRefs(spec.emittedEvents)}`);
95
+ lines.push("");
96
+ }
97
+ lines.push(`${indent}---`);
98
+ lines.push("");
99
+ lines.push(`${indent}**Implementation Instructions**:`);
100
+ lines.push("");
101
+ appendImplementationInstructions(spec, lines, indent);
102
+ return lines.join("\n");
103
+ }
104
+ /**
105
+ * Format spec in full mode (complete with source code).
106
+ */
107
+ function formatFullMode(spec, lines, indent, rootPath) {
108
+ lines.push(`${indent}## Metadata`);
109
+ lines.push("");
110
+ lines.push(`${indent}- **Type**: ${spec.specType}${spec.kind && spec.kind !== "unknown" ? ` (${spec.kind})` : ""}`);
111
+ lines.push(`${indent}- **Version**: ${spec.meta.version}`);
112
+ if (spec.meta.stability) lines.push(`${indent}- **Stability**: ${spec.meta.stability}`);
113
+ if (spec.meta.owners?.length) lines.push(`${indent}- **Owners**: ${spec.meta.owners.join(", ")}`);
114
+ if (spec.meta.tags?.length) lines.push(`${indent}- **Tags**: ${spec.meta.tags.join(", ")}`);
115
+ if (spec.filePath) {
116
+ const displayPath = rootPath ? path.relative(rootPath, spec.filePath) : spec.filePath;
117
+ lines.push(`${indent}- **File**: \`${displayPath}\``);
118
+ }
119
+ lines.push("");
120
+ if (spec.meta.goal) {
121
+ lines.push(`${indent}## Goal`);
122
+ lines.push("");
123
+ lines.push(`${indent}${spec.meta.goal}`);
124
+ lines.push("");
125
+ }
126
+ if (spec.meta.context) {
127
+ lines.push(`${indent}## Context`);
128
+ lines.push("");
129
+ lines.push(`${indent}${spec.meta.context}`);
130
+ lines.push("");
131
+ }
132
+ if (spec.specType === "feature") appendFeatureSections(spec, lines, indent);
133
+ if (spec.emittedEvents?.length) {
134
+ lines.push(`${indent}## Emitted Events`);
135
+ lines.push("");
136
+ for (const ev of spec.emittedEvents) lines.push(`${indent}- \`${ev.name}\` (v${ev.version})`);
137
+ lines.push("");
138
+ }
139
+ if (spec.policyRefs?.length) {
140
+ lines.push(`${indent}## Policy References`);
141
+ lines.push("");
142
+ for (const policy of spec.policyRefs) lines.push(`${indent}- \`${policy.name}\` (v${policy.version})`);
143
+ lines.push("");
144
+ }
145
+ if (spec.testRefs?.length) {
146
+ lines.push(`${indent}## Test Specifications`);
147
+ lines.push("");
148
+ for (const test of spec.testRefs) lines.push(`${indent}- \`${test.name}\` (v${test.version})`);
149
+ lines.push("");
150
+ }
151
+ if (spec.sourceBlock) {
152
+ lines.push(`${indent}## Source Definition`);
153
+ lines.push("");
154
+ lines.push(`${indent}\`\`\`typescript`);
155
+ const sourceLines = spec.sourceBlock.split("\n");
156
+ for (const sourceLine of sourceLines) lines.push(`${indent}${sourceLine}`);
157
+ lines.push(`${indent}\`\`\``);
158
+ lines.push("");
159
+ }
160
+ return lines.join("\n");
161
+ }
162
+ /**
163
+ * Format a list of spec refs as inline code.
164
+ */
165
+ function formatRefs(refs) {
166
+ return refs.map((r) => `\`${r.name}\``).join(", ");
167
+ }
168
+ /**
169
+ * Append feature refs in summary format.
170
+ */
171
+ function appendFeatureRefs(spec, lines, indent) {
172
+ if (spec.operations?.length) lines.push(`${indent}**Operations**: ${formatRefs(spec.operations)}`);
173
+ if (spec.events?.length) lines.push(`${indent}**Events**: ${formatRefs(spec.events)}`);
174
+ if (spec.presentations?.length) lines.push(`${indent}**Presentations**: ${formatRefs(spec.presentations)}`);
175
+ lines.push("");
176
+ }
177
+ /**
178
+ * Append feature child sections with full detail.
179
+ */
180
+ function appendFeatureSections(spec, lines, indent) {
181
+ if (spec.operations?.length) {
182
+ lines.push(`${indent}## Operations (${spec.operations.length})`);
183
+ lines.push("");
184
+ for (const op of spec.operations) lines.push(`${indent}- \`${op.name}\` (v${op.version})`);
185
+ lines.push("");
186
+ }
187
+ if (spec.events?.length) {
188
+ lines.push(`${indent}## Events (${spec.events.length})`);
189
+ lines.push("");
190
+ for (const ev of spec.events) lines.push(`${indent}- \`${ev.name}\` (v${ev.version})`);
191
+ lines.push("");
192
+ }
193
+ if (spec.presentations?.length) {
194
+ lines.push(`${indent}## Presentations (${spec.presentations.length})`);
195
+ lines.push("");
196
+ for (const pres of spec.presentations) lines.push(`${indent}- \`${pres.name}\` (v${pres.version})`);
197
+ lines.push("");
198
+ }
199
+ }
200
+ /**
201
+ * Append implementation instructions based on spec type.
202
+ */
203
+ function appendImplementationInstructions(spec, lines, indent) {
204
+ if (spec.specType === "operation") {
205
+ lines.push(`${indent}Implement the \`${spec.meta.key}\` ${spec.kind ?? "operation"} ensuring:`);
206
+ if (spec.hasIo) {
207
+ lines.push(`${indent}- Input validation per schema`);
208
+ lines.push(`${indent}- Output matches expected schema`);
209
+ }
210
+ if (spec.hasPolicy) lines.push(`${indent}- Policy rules are enforced`);
211
+ if (spec.emittedEvents?.length) lines.push(`${indent}- Events are emitted on success`);
212
+ } else if (spec.specType === "feature") {
213
+ lines.push(`${indent}Implement the \`${spec.meta.key}\` feature including:`);
214
+ if (spec.operations?.length) lines.push(`${indent}- ${spec.operations.length} operation(s)`);
215
+ if (spec.presentations?.length) lines.push(`${indent}- ${spec.presentations.length} presentation(s)`);
216
+ } else if (spec.specType === "event") {
217
+ lines.push(`${indent}Implement the \`${spec.meta.key}\` event ensuring:`);
218
+ lines.push(`${indent}- Payload matches expected schema`);
219
+ lines.push(`${indent}- Event is properly typed`);
220
+ } else if (spec.specType === "presentation") {
221
+ lines.push(`${indent}Implement the \`${spec.meta.key}\` presentation ensuring:`);
222
+ lines.push(`${indent}- Component renders correctly`);
223
+ lines.push(`${indent}- Accessibility requirements are met`);
224
+ } else lines.push(`${indent}Implement the \`${spec.meta.key}\` ${spec.specType} according to the specification.`);
225
+ lines.push("");
226
+ }
227
+ /**
228
+ * Convert spec to markdown with custom options.
229
+ */
230
+ function specToMarkdownWithOptions(spec, options) {
231
+ return specToMarkdown(spec, options.format, options.depth ?? 0);
232
+ }
233
+ /**
234
+ * Generate a summary header for multiple specs.
235
+ */
236
+ function generateSpecsSummaryHeader(specs, format) {
237
+ const lines = [];
238
+ lines.push("# ContractSpec Export");
239
+ lines.push("");
240
+ lines.push(`**Format**: ${format}`);
241
+ lines.push(`**Specs**: ${specs.length}`);
242
+ lines.push("");
243
+ const byType = /* @__PURE__ */ new Map();
244
+ for (const spec of specs) byType.set(spec.specType, (byType.get(spec.specType) ?? 0) + 1);
245
+ if (byType.size > 0) {
246
+ lines.push("**Contents**:");
247
+ for (const [type, count] of byType) lines.push(`- ${count} ${type}(s)`);
248
+ lines.push("");
249
+ }
250
+ lines.push("---");
251
+ lines.push("");
252
+ return lines.join("\n");
253
+ }
254
+ /**
255
+ * Combine multiple spec markdowns into a single document.
256
+ */
257
+ function combineSpecMarkdowns(specs, format) {
258
+ return generateSpecsSummaryHeader(specs, format) + specs.map((spec) => specToMarkdown(spec, format)).join("\n---\n\n");
259
+ }
260
+
261
+ //#endregion
262
+ export { combineSpecMarkdowns, generateSpecsSummaryHeader, specToMarkdown, specToMarkdownWithOptions };
263
+ //# sourceMappingURL=spec-markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-markdown.js","names":[],"sources":["../../src/formatters/spec-markdown.ts"],"sourcesContent":["/**\n * Spec to Markdown Formatter\n *\n * Pure functions for converting parsed specs to LLM-friendly markdown formats.\n * Extracted from vscode-contractspec/src/commands/llm.ts for reuse.\n */\n\nimport type {\n LLMExportFormat,\n ParsedSpec,\n SpecRef,\n SpecToMarkdownOptions,\n} from '../types/llm-types';\nimport * as path from 'node:path';\n\n/**\n * Generate markdown from a parsed spec.\n *\n * Formats:\n * - **full**: Complete information including source code and all details (for deep LLM context)\n * - **prompt**: Concise with implementation instructions (actionable for LLM)\n * - **context**: Brief summary with counts and key fields (lightweight overview)\n */\nexport function specToMarkdown(\n spec: ParsedSpec,\n format: LLMExportFormat,\n optionsOrDepth: number | { depth?: number; rootPath?: string } = 0\n): string {\n const options =\n typeof optionsOrDepth === 'number'\n ? { depth: optionsOrDepth }\n : optionsOrDepth;\n const depth = options.depth ?? 0;\n const rootPath = options.rootPath;\n\n const lines: string[] = [];\n const indent = depth > 0 ? ' '.repeat(depth) : '';\n const headerLevel = Math.min(depth + 1, 6);\n const headerPrefix = '#'.repeat(headerLevel);\n\n // Header\n lines.push(`${indent}${headerPrefix} ${spec.meta.key}`);\n lines.push('');\n\n // Description (always included if present)\n if (spec.meta.description) {\n lines.push(`${indent}${spec.meta.description}`);\n lines.push('');\n }\n\n // ===== CONTEXT FORMAT: Brief summary only =====\n if (format === 'context') {\n return formatContextMode(spec, lines, indent);\n }\n\n // ===== PROMPT FORMAT: Implementation-focused =====\n if (format === 'prompt') {\n return formatPromptMode(spec, lines, indent);\n }\n\n // ===== FULL FORMAT: Complete with source code =====\n return formatFullMode(spec, lines, indent, rootPath);\n}\n\n/**\n * Format spec in context mode (brief summary).\n */\nfunction formatContextMode(\n spec: ParsedSpec,\n lines: string[],\n indent: string\n): string {\n // Compact metadata line\n const metaParts: string[] = [];\n metaParts.push(`**${spec.specType}**`);\n if (spec.kind && spec.kind !== 'unknown') metaParts.push(`(${spec.kind})`);\n metaParts.push(`v${spec.meta.version}`);\n if (spec.meta.stability) metaParts.push(`[${spec.meta.stability}]`);\n lines.push(`${indent}${metaParts.join(' ')}`);\n lines.push('');\n\n // Key counts for features\n if (spec.specType === 'feature') {\n const counts: string[] = [];\n if (spec.operations?.length)\n counts.push(`${spec.operations.length} operation(s)`);\n if (spec.events?.length) counts.push(`${spec.events.length} event(s)`);\n if (spec.presentations?.length)\n counts.push(`${spec.presentations.length} presentation(s)`);\n if (counts.length > 0) {\n lines.push(`${indent}Contains: ${counts.join(', ')}`);\n lines.push('');\n }\n }\n\n // Key indicators for operations\n if (spec.specType === 'operation') {\n const indicators: string[] = [];\n if (spec.hasIo) indicators.push('I/O');\n if (spec.hasPolicy) indicators.push('Policy');\n if (spec.emittedEvents?.length)\n indicators.push(`${spec.emittedEvents.length} event(s)`);\n if (indicators.length > 0) {\n lines.push(`${indent}Includes: ${indicators.join(', ')}`);\n lines.push('');\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Format spec in prompt mode (implementation-focused).\n */\nfunction formatPromptMode(\n spec: ParsedSpec,\n lines: string[],\n indent: string\n): string {\n // Metadata\n lines.push(\n `${indent}**Type**: ${spec.specType}${spec.kind && spec.kind !== 'unknown' ? ` (${spec.kind})` : ''}`\n );\n lines.push(`${indent}**Version**: ${spec.meta.version}`);\n if (spec.meta.stability)\n lines.push(`${indent}**Stability**: ${spec.meta.stability}`);\n if (spec.meta.owners?.length)\n lines.push(`${indent}**Owners**: ${spec.meta.owners.join(', ')}`);\n if (spec.meta.tags?.length)\n lines.push(`${indent}**Tags**: ${spec.meta.tags.join(', ')}`);\n lines.push('');\n\n // Goal and Context\n if (spec.meta.goal) {\n lines.push(`${indent}**Goal**: ${spec.meta.goal}`);\n lines.push('');\n }\n if (spec.meta.context) {\n lines.push(`${indent}**Context**: ${spec.meta.context}`);\n lines.push('');\n }\n\n // Structure for operations\n if (spec.specType === 'operation') {\n const structure: string[] = [];\n if (spec.hasIo) structure.push('Input/Output Schema');\n if (spec.hasPolicy) structure.push('Policy Enforcement');\n if (spec.hasPayload) structure.push('Payload');\n if (spec.hasContent) structure.push('Content');\n if (structure.length > 0) {\n lines.push(`${indent}**Structure**: ${structure.join(', ')}`);\n lines.push('');\n }\n }\n\n // Child refs for features (summary only)\n if (spec.specType === 'feature') {\n appendFeatureRefs(spec, lines, indent);\n }\n\n // Emitted events\n if (spec.emittedEvents?.length) {\n lines.push(`${indent}**Emits**: ${formatRefs(spec.emittedEvents)}`);\n lines.push('');\n }\n\n // Implementation instructions\n lines.push(`${indent}---`);\n lines.push('');\n lines.push(`${indent}**Implementation Instructions**:`);\n lines.push('');\n appendImplementationInstructions(spec, lines, indent);\n\n return lines.join('\\n');\n}\n\n/**\n * Format spec in full mode (complete with source code).\n */\nfunction formatFullMode(\n spec: ParsedSpec,\n lines: string[],\n indent: string,\n rootPath?: string\n): string {\n // Full metadata section\n lines.push(`${indent}## Metadata`);\n lines.push('');\n lines.push(\n `${indent}- **Type**: ${spec.specType}${spec.kind && spec.kind !== 'unknown' ? ` (${spec.kind})` : ''}`\n );\n lines.push(`${indent}- **Version**: ${spec.meta.version}`);\n if (spec.meta.stability) {\n lines.push(`${indent}- **Stability**: ${spec.meta.stability}`);\n }\n if (spec.meta.owners?.length) {\n lines.push(`${indent}- **Owners**: ${spec.meta.owners.join(', ')}`);\n }\n if (spec.meta.tags?.length) {\n lines.push(`${indent}- **Tags**: ${spec.meta.tags.join(', ')}`);\n }\n if (spec.filePath) {\n const displayPath = rootPath\n ? path.relative(rootPath, spec.filePath)\n : spec.filePath;\n lines.push(`${indent}- **File**: \\`${displayPath}\\``);\n }\n lines.push('');\n\n // Goal and Context\n if (spec.meta.goal) {\n lines.push(`${indent}## Goal`);\n lines.push('');\n lines.push(`${indent}${spec.meta.goal}`);\n lines.push('');\n }\n if (spec.meta.context) {\n lines.push(`${indent}## Context`);\n lines.push('');\n lines.push(`${indent}${spec.meta.context}`);\n lines.push('');\n }\n\n // Child specs for features (with full detail)\n if (spec.specType === 'feature') {\n appendFeatureSections(spec, lines, indent);\n }\n\n // Emitted events (for operations)\n if (spec.emittedEvents?.length) {\n lines.push(`${indent}## Emitted Events`);\n lines.push('');\n for (const ev of spec.emittedEvents) {\n lines.push(`${indent}- \\`${ev.name}\\` (v${ev.version})`);\n }\n lines.push('');\n }\n\n // Policy references\n if (spec.policyRefs?.length) {\n lines.push(`${indent}## Policy References`);\n lines.push('');\n for (const policy of spec.policyRefs) {\n lines.push(`${indent}- \\`${policy.name}\\` (v${policy.version})`);\n }\n lines.push('');\n }\n\n // Test references\n if (spec.testRefs?.length) {\n lines.push(`${indent}## Test Specifications`);\n lines.push('');\n for (const test of spec.testRefs) {\n lines.push(`${indent}- \\`${test.name}\\` (v${test.version})`);\n }\n lines.push('');\n }\n\n // Source code block (the key differentiator for full format!)\n if (spec.sourceBlock) {\n lines.push(`${indent}## Source Definition`);\n lines.push('');\n lines.push(`${indent}\\`\\`\\`typescript`);\n // Add source block with proper indentation\n const sourceLines = spec.sourceBlock.split('\\n');\n for (const sourceLine of sourceLines) {\n lines.push(`${indent}${sourceLine}`);\n }\n lines.push(`${indent}\\`\\`\\``);\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Format a list of spec refs as inline code.\n */\nfunction formatRefs(refs: SpecRef[]): string {\n return refs.map((r) => `\\`${r.name}\\``).join(', ');\n}\n\n/**\n * Append feature refs in summary format.\n */\nfunction appendFeatureRefs(\n spec: ParsedSpec,\n lines: string[],\n indent: string\n): void {\n if (spec.operations?.length) {\n lines.push(`${indent}**Operations**: ${formatRefs(spec.operations)}`);\n }\n if (spec.events?.length) {\n lines.push(`${indent}**Events**: ${formatRefs(spec.events)}`);\n }\n if (spec.presentations?.length) {\n lines.push(`${indent}**Presentations**: ${formatRefs(spec.presentations)}`);\n }\n lines.push('');\n}\n\n/**\n * Append feature child sections with full detail.\n */\nfunction appendFeatureSections(\n spec: ParsedSpec,\n lines: string[],\n indent: string\n): void {\n if (spec.operations?.length) {\n lines.push(`${indent}## Operations (${spec.operations.length})`);\n lines.push('');\n for (const op of spec.operations) {\n lines.push(`${indent}- \\`${op.name}\\` (v${op.version})`);\n }\n lines.push('');\n }\n if (spec.events?.length) {\n lines.push(`${indent}## Events (${spec.events.length})`);\n lines.push('');\n for (const ev of spec.events) {\n lines.push(`${indent}- \\`${ev.name}\\` (v${ev.version})`);\n }\n lines.push('');\n }\n if (spec.presentations?.length) {\n lines.push(`${indent}## Presentations (${spec.presentations.length})`);\n lines.push('');\n for (const pres of spec.presentations) {\n lines.push(`${indent}- \\`${pres.name}\\` (v${pres.version})`);\n }\n lines.push('');\n }\n}\n\n/**\n * Append implementation instructions based on spec type.\n */\nfunction appendImplementationInstructions(\n spec: ParsedSpec,\n lines: string[],\n indent: string\n): void {\n if (spec.specType === 'operation') {\n lines.push(\n `${indent}Implement the \\`${spec.meta.key}\\` ${spec.kind ?? 'operation'} ensuring:`\n );\n if (spec.hasIo) {\n lines.push(`${indent}- Input validation per schema`);\n lines.push(`${indent}- Output matches expected schema`);\n }\n if (spec.hasPolicy) {\n lines.push(`${indent}- Policy rules are enforced`);\n }\n if (spec.emittedEvents?.length) {\n lines.push(`${indent}- Events are emitted on success`);\n }\n } else if (spec.specType === 'feature') {\n lines.push(\n `${indent}Implement the \\`${spec.meta.key}\\` feature including:`\n );\n if (spec.operations?.length) {\n lines.push(`${indent}- ${spec.operations.length} operation(s)`);\n }\n if (spec.presentations?.length) {\n lines.push(`${indent}- ${spec.presentations.length} presentation(s)`);\n }\n } else if (spec.specType === 'event') {\n lines.push(`${indent}Implement the \\`${spec.meta.key}\\` event ensuring:`);\n lines.push(`${indent}- Payload matches expected schema`);\n lines.push(`${indent}- Event is properly typed`);\n } else if (spec.specType === 'presentation') {\n lines.push(\n `${indent}Implement the \\`${spec.meta.key}\\` presentation ensuring:`\n );\n lines.push(`${indent}- Component renders correctly`);\n lines.push(`${indent}- Accessibility requirements are met`);\n } else {\n lines.push(\n `${indent}Implement the \\`${spec.meta.key}\\` ${spec.specType} according to the specification.`\n );\n }\n lines.push('');\n}\n\n/**\n * Convert spec to markdown with custom options.\n */\nexport function specToMarkdownWithOptions(\n spec: ParsedSpec,\n options: SpecToMarkdownOptions\n): string {\n return specToMarkdown(spec, options.format, options.depth ?? 0);\n}\n\n/**\n * Generate a summary header for multiple specs.\n */\nexport function generateSpecsSummaryHeader(\n specs: ParsedSpec[],\n format: LLMExportFormat\n): string {\n const lines: string[] = [];\n\n lines.push('# ContractSpec Export');\n lines.push('');\n lines.push(`**Format**: ${format}`);\n lines.push(`**Specs**: ${specs.length}`);\n lines.push('');\n\n // Group by type\n const byType = new Map<string, number>();\n for (const spec of specs) {\n byType.set(spec.specType, (byType.get(spec.specType) ?? 0) + 1);\n }\n\n if (byType.size > 0) {\n lines.push('**Contents**:');\n for (const [type, count] of byType) {\n lines.push(`- ${count} ${type}(s)`);\n }\n lines.push('');\n }\n\n lines.push('---');\n lines.push('');\n\n return lines.join('\\n');\n}\n\n/**\n * Combine multiple spec markdowns into a single document.\n */\nexport function combineSpecMarkdowns(\n specs: ParsedSpec[],\n format: LLMExportFormat\n): string {\n const header = generateSpecsSummaryHeader(specs, format);\n const specMarkdowns = specs.map((spec) => specToMarkdown(spec, format));\n\n return header + specMarkdowns.join('\\n---\\n\\n');\n}\n"],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { ParsedSpec } from "../types/llm-types.js";
2
+ import { DocBlock } from "@contractspec/lib.contracts/docs";
3
+
4
+ //#region src/formatters/spec-to-docblock.d.ts
5
+
6
+ /**
7
+ * Convert a parsed spec to a DocBlock for documentation generation.
8
+ */
9
+ declare function convertSpecToDocBlock(spec: ParsedSpec, options?: {
10
+ rootPath?: string;
11
+ }): DocBlock;
12
+ //#endregion
13
+ export { convertSpecToDocBlock };
14
+ //# sourceMappingURL=spec-to-docblock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-to-docblock.d.ts","names":[],"sources":["../../src/formatters/spec-to-docblock.ts"],"sourcesContent":[],"mappings":";;;;;;;AAOA;iBAAgB,qBAAA,OACR;;IAEL"}
@@ -0,0 +1,48 @@
1
+ import { specToMarkdown } from "./spec-markdown.js";
2
+
3
+ //#region src/formatters/spec-to-docblock.ts
4
+ /**
5
+ * Convert a parsed spec to a DocBlock for documentation generation.
6
+ */
7
+ function convertSpecToDocBlock(spec, options) {
8
+ const body = specToMarkdown(spec, "full", { rootPath: options?.rootPath });
9
+ return {
10
+ id: spec.meta.key,
11
+ title: spec.meta.description ? `${spec.meta.key} - ${spec.meta.description}` : spec.meta.key,
12
+ body,
13
+ summary: spec.meta.description,
14
+ kind: mapSpecTypeToDocKind(spec.specType),
15
+ visibility: "public",
16
+ version: spec.meta.version,
17
+ tags: spec.meta.tags,
18
+ owners: spec.meta.owners,
19
+ stability: spec.meta.stability,
20
+ domain: inferDomain(spec.meta.key),
21
+ relatedSpecs: extractRelatedSpecs(spec)
22
+ };
23
+ }
24
+ function mapSpecTypeToDocKind(specType) {
25
+ switch (specType) {
26
+ case "feature": return "goal";
27
+ case "operation": return "reference";
28
+ case "event": return "reference";
29
+ case "presentation": return "usage";
30
+ default: return "reference";
31
+ }
32
+ }
33
+ function inferDomain(key) {
34
+ const parts = key.split(".");
35
+ if (parts.length > 2) return parts[0];
36
+ }
37
+ function extractRelatedSpecs(spec) {
38
+ const related = [];
39
+ if (spec.emittedEvents) related.push(...spec.emittedEvents.map((r) => r.name));
40
+ if (spec.operations) related.push(...spec.operations.map((r) => r.name));
41
+ if (spec.events) related.push(...spec.events.map((r) => r.name));
42
+ if (spec.testRefs) related.push(...spec.testRefs.map((r) => r.name));
43
+ return [...new Set(related)];
44
+ }
45
+
46
+ //#endregion
47
+ export { convertSpecToDocBlock };
48
+ //# sourceMappingURL=spec-to-docblock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-to-docblock.js","names":[],"sources":["../../src/formatters/spec-to-docblock.ts"],"sourcesContent":["import type { ParsedSpec } from '../types/llm-types';\nimport type { DocBlock, DocKind } from '@contractspec/lib.contracts/docs';\nimport { specToMarkdown } from './spec-markdown';\n\n/**\n * Convert a parsed spec to a DocBlock for documentation generation.\n */\nexport function convertSpecToDocBlock(\n spec: ParsedSpec,\n options?: { rootPath?: string }\n): DocBlock {\n const body = specToMarkdown(spec, 'full', { rootPath: options?.rootPath });\n\n return {\n id: spec.meta.key,\n title: spec.meta.description\n ? `${spec.meta.key} - ${spec.meta.description}`\n : spec.meta.key,\n body: body,\n summary: spec.meta.description,\n kind: mapSpecTypeToDocKind(spec.specType),\n visibility: 'public', // Default to public for now\n version: spec.meta.version,\n tags: spec.meta.tags,\n owners: spec.meta.owners,\n stability: spec.meta.stability,\n domain: inferDomain(spec.meta.key),\n relatedSpecs: extractRelatedSpecs(spec),\n };\n}\n\nfunction mapSpecTypeToDocKind(specType: string): DocKind {\n switch (specType) {\n case 'feature':\n return 'goal'; // Features often describe goals\n case 'operation':\n return 'reference';\n case 'event':\n return 'reference';\n case 'presentation':\n return 'usage';\n default:\n return 'reference';\n }\n}\n\nfunction inferDomain(key: string): string | undefined {\n const parts = key.split('.');\n if (parts.length > 2) {\n return parts[0]; // e.g. \"crm.users.create\" -> \"crm\"\n }\n return undefined;\n}\n\nfunction extractRelatedSpecs(spec: ParsedSpec): string[] {\n const related: string[] = [];\n\n if (spec.emittedEvents) {\n related.push(...spec.emittedEvents.map((r) => r.name));\n }\n if (spec.operations) {\n related.push(...spec.operations.map((r) => r.name));\n }\n if (spec.events) {\n related.push(...spec.events.map((r) => r.name));\n }\n if (spec.testRefs) {\n related.push(...spec.testRefs.map((r) => r.name));\n }\n\n return [...new Set(related)];\n}\n"],"mappings":";;;;;;AAOA,SAAgB,sBACd,MACA,SACU;CACV,MAAM,OAAO,eAAe,MAAM,QAAQ,EAAE,UAAU,SAAS,UAAU,CAAC;AAE1E,QAAO;EACL,IAAI,KAAK,KAAK;EACd,OAAO,KAAK,KAAK,cACb,GAAG,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,gBAChC,KAAK,KAAK;EACR;EACN,SAAS,KAAK,KAAK;EACnB,MAAM,qBAAqB,KAAK,SAAS;EACzC,YAAY;EACZ,SAAS,KAAK,KAAK;EACnB,MAAM,KAAK,KAAK;EAChB,QAAQ,KAAK,KAAK;EAClB,WAAW,KAAK,KAAK;EACrB,QAAQ,YAAY,KAAK,KAAK,IAAI;EAClC,cAAc,oBAAoB,KAAK;EACxC;;AAGH,SAAS,qBAAqB,UAA2B;AACvD,SAAQ,UAAR;EACE,KAAK,UACH,QAAO;EACT,KAAK,YACH,QAAO;EACT,KAAK,QACH,QAAO;EACT,KAAK,eACH,QAAO;EACT,QACE,QAAO;;;AAIb,SAAS,YAAY,KAAiC;CACpD,MAAM,QAAQ,IAAI,MAAM,IAAI;AAC5B,KAAI,MAAM,SAAS,EACjB,QAAO,MAAM;;AAKjB,SAAS,oBAAoB,MAA4B;CACvD,MAAM,UAAoB,EAAE;AAE5B,KAAI,KAAK,cACP,SAAQ,KAAK,GAAG,KAAK,cAAc,KAAK,MAAM,EAAE,KAAK,CAAC;AAExD,KAAI,KAAK,WACP,SAAQ,KAAK,GAAG,KAAK,WAAW,KAAK,MAAM,EAAE,KAAK,CAAC;AAErD,KAAI,KAAK,OACP,SAAQ,KAAK,GAAG,KAAK,OAAO,KAAK,MAAM,EAAE,KAAK,CAAC;AAEjD,KAAI,KAAK,SACP,SAAQ,KAAK,GAAG,KAAK,SAAS,KAAK,MAAM,EAAE,KAAK,CAAC;AAGnD,QAAO,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC"}