@contractspec/module.workspace 1.57.0 → 1.58.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 (248) hide show
  1. package/dist/ai/code-generation.d.ts +25 -0
  2. package/dist/ai/code-generation.d.ts.map +1 -0
  3. package/dist/ai/index.d.ts +5 -0
  4. package/dist/ai/index.d.ts.map +1 -0
  5. package/dist/ai/prompts/code-generation.d.ts +5 -8
  6. package/dist/ai/prompts/code-generation.d.ts.map +1 -1
  7. package/dist/ai/prompts/index.d.ts +3 -0
  8. package/dist/ai/prompts/index.d.ts.map +1 -0
  9. package/dist/ai/prompts/spec-creation.d.ts +7 -11
  10. package/dist/ai/prompts/spec-creation.d.ts.map +1 -1
  11. package/dist/ai/spec-creation.d.ts +27 -0
  12. package/dist/ai/spec-creation.d.ts.map +1 -0
  13. package/dist/analysis/deps/graph.d.ts +14 -13
  14. package/dist/analysis/deps/graph.d.ts.map +1 -1
  15. package/dist/analysis/deps/index.d.ts +6 -0
  16. package/dist/analysis/deps/index.d.ts.map +1 -0
  17. package/dist/analysis/deps/parse-imports.d.ts +1 -4
  18. package/dist/analysis/deps/parse-imports.d.ts.map +1 -1
  19. package/dist/analysis/diff/deep-diff.d.ts +17 -15
  20. package/dist/analysis/diff/deep-diff.d.ts.map +1 -1
  21. package/dist/analysis/diff/deep-diff.test.d.ts +5 -0
  22. package/dist/analysis/diff/deep-diff.test.d.ts.map +1 -0
  23. package/dist/analysis/diff/index.d.ts +6 -0
  24. package/dist/analysis/diff/index.d.ts.map +1 -0
  25. package/dist/analysis/diff/semantic.d.ts +6 -6
  26. package/dist/analysis/diff/semantic.d.ts.map +1 -1
  27. package/dist/analysis/example-scan.d.ts +3 -7
  28. package/dist/analysis/example-scan.d.ts.map +1 -1
  29. package/dist/analysis/example-scan.test.d.ts +7 -0
  30. package/dist/analysis/example-scan.test.d.ts.map +1 -0
  31. package/dist/analysis/feature-extractor.d.ts +25 -0
  32. package/dist/analysis/feature-extractor.d.ts.map +1 -0
  33. package/dist/analysis/feature-scan.d.ts +3 -7
  34. package/dist/analysis/feature-scan.d.ts.map +1 -1
  35. package/dist/analysis/feature-scan.test.d.ts +2 -0
  36. package/dist/analysis/feature-scan.test.d.ts.map +1 -0
  37. package/dist/analysis/grouping.d.ts +41 -35
  38. package/dist/analysis/grouping.d.ts.map +1 -1
  39. package/dist/analysis/impact/classifier.d.ts +9 -8
  40. package/dist/analysis/impact/classifier.d.ts.map +1 -1
  41. package/dist/analysis/impact/classifier.test.d.ts +5 -0
  42. package/dist/analysis/impact/classifier.test.d.ts.map +1 -0
  43. package/dist/analysis/impact/index.d.ts +9 -0
  44. package/dist/analysis/impact/index.d.ts.map +1 -0
  45. package/dist/analysis/impact/rules.d.ts +15 -14
  46. package/dist/analysis/impact/rules.d.ts.map +1 -1
  47. package/dist/analysis/impact/types.d.ts +73 -76
  48. package/dist/analysis/impact/types.d.ts.map +1 -1
  49. package/dist/analysis/index.d.ts +14 -0
  50. package/dist/analysis/index.d.ts.map +1 -0
  51. package/dist/analysis/snapshot/index.d.ts +9 -0
  52. package/dist/analysis/snapshot/index.d.ts.map +1 -0
  53. package/dist/analysis/snapshot/normalizer.d.ts +7 -10
  54. package/dist/analysis/snapshot/normalizer.d.ts.map +1 -1
  55. package/dist/analysis/snapshot/snapshot.d.ts +10 -8
  56. package/dist/analysis/snapshot/snapshot.d.ts.map +1 -1
  57. package/dist/analysis/snapshot/snapshot.test.d.ts +5 -0
  58. package/dist/analysis/snapshot/snapshot.test.d.ts.map +1 -0
  59. package/dist/analysis/snapshot/types.d.ts +58 -56
  60. package/dist/analysis/snapshot/types.d.ts.map +1 -1
  61. package/dist/analysis/spec-parser.d.ts +8 -6
  62. package/dist/analysis/spec-parser.d.ts.map +1 -1
  63. package/dist/analysis/spec-parsing-utils.d.ts +20 -10
  64. package/dist/analysis/spec-parsing-utils.d.ts.map +1 -1
  65. package/dist/analysis/spec-scan.d.ts +13 -12
  66. package/dist/analysis/spec-scan.d.ts.map +1 -1
  67. package/dist/analysis/spec-scan.test.d.ts +2 -0
  68. package/dist/analysis/spec-scan.test.d.ts.map +1 -0
  69. package/dist/analysis/utils/matchers.d.ts +39 -0
  70. package/dist/analysis/utils/matchers.d.ts.map +1 -0
  71. package/dist/analysis/utils/variables.d.ts +15 -0
  72. package/dist/analysis/utils/variables.d.ts.map +1 -0
  73. package/dist/analysis/validate/index.d.ts +5 -0
  74. package/dist/analysis/validate/index.d.ts.map +1 -0
  75. package/dist/analysis/validate/spec-structure.d.ts +15 -14
  76. package/dist/analysis/validate/spec-structure.d.ts.map +1 -1
  77. package/dist/analysis/validate/spec-structure.test.d.ts +2 -0
  78. package/dist/analysis/validate/spec-structure.test.d.ts.map +1 -0
  79. package/dist/formatter.d.ts +28 -27
  80. package/dist/formatter.d.ts.map +1 -1
  81. package/dist/formatters/index.d.ts +8 -0
  82. package/dist/formatters/index.d.ts.map +1 -0
  83. package/dist/formatters/spec-markdown.d.ts +13 -11
  84. package/dist/formatters/spec-markdown.d.ts.map +1 -1
  85. package/dist/formatters/spec-markdown.test.d.ts +5 -0
  86. package/dist/formatters/spec-markdown.test.d.ts.map +1 -0
  87. package/dist/formatters/spec-to-docblock.d.ts +4 -8
  88. package/dist/formatters/spec-to-docblock.d.ts.map +1 -1
  89. package/dist/index.d.ts +13 -42
  90. package/dist/index.d.ts.map +1 -0
  91. package/dist/index.js +4302 -38
  92. package/dist/node/index.js +4301 -0
  93. package/dist/templates/app-config.d.ts +2 -6
  94. package/dist/templates/app-config.d.ts.map +1 -1
  95. package/dist/templates/app-config.test.d.ts +2 -0
  96. package/dist/templates/app-config.test.d.ts.map +1 -0
  97. package/dist/templates/data-view.d.ts +2 -6
  98. package/dist/templates/data-view.d.ts.map +1 -1
  99. package/dist/templates/data-view.test.d.ts +2 -0
  100. package/dist/templates/data-view.test.d.ts.map +1 -0
  101. package/dist/templates/event.d.ts +6 -6
  102. package/dist/templates/event.d.ts.map +1 -1
  103. package/dist/templates/event.test.d.ts +2 -0
  104. package/dist/templates/event.test.d.ts.map +1 -0
  105. package/dist/templates/experiment.d.ts +2 -6
  106. package/dist/templates/experiment.d.ts.map +1 -1
  107. package/dist/templates/experiment.test.d.ts +2 -0
  108. package/dist/templates/experiment.test.d.ts.map +1 -0
  109. package/dist/templates/handler.d.ts +3 -6
  110. package/dist/templates/handler.d.ts.map +1 -1
  111. package/dist/templates/handler.test.d.ts +2 -0
  112. package/dist/templates/handler.test.d.ts.map +1 -0
  113. package/dist/templates/index.d.ts +18 -0
  114. package/dist/templates/index.d.ts.map +1 -0
  115. package/dist/templates/integration-utils.d.ts +13 -0
  116. package/dist/templates/integration-utils.d.ts.map +1 -0
  117. package/dist/templates/integration-utils.test.d.ts +2 -0
  118. package/dist/templates/integration-utils.test.d.ts.map +1 -0
  119. package/dist/templates/integration.d.ts +2 -6
  120. package/dist/templates/integration.d.ts.map +1 -1
  121. package/dist/templates/integration.test.d.ts +2 -0
  122. package/dist/templates/integration.test.d.ts.map +1 -0
  123. package/dist/templates/knowledge.d.ts +2 -6
  124. package/dist/templates/knowledge.d.ts.map +1 -1
  125. package/dist/templates/knowledge.test.d.ts +2 -0
  126. package/dist/templates/knowledge.test.d.ts.map +1 -0
  127. package/dist/templates/migration.d.ts +2 -6
  128. package/dist/templates/migration.d.ts.map +1 -1
  129. package/dist/templates/migration.test.d.ts +2 -0
  130. package/dist/templates/migration.test.d.ts.map +1 -0
  131. package/dist/templates/operation.d.ts +6 -6
  132. package/dist/templates/operation.d.ts.map +1 -1
  133. package/dist/templates/operation.test.d.ts +2 -0
  134. package/dist/templates/operation.test.d.ts.map +1 -0
  135. package/dist/templates/presentation.d.ts +6 -6
  136. package/dist/templates/presentation.d.ts.map +1 -1
  137. package/dist/templates/presentation.test.d.ts +2 -0
  138. package/dist/templates/presentation.test.d.ts.map +1 -0
  139. package/dist/templates/telemetry.d.ts +2 -6
  140. package/dist/templates/telemetry.d.ts.map +1 -1
  141. package/dist/templates/telemetry.test.d.ts +2 -0
  142. package/dist/templates/telemetry.test.d.ts.map +1 -0
  143. package/dist/templates/utils.d.ts +5 -8
  144. package/dist/templates/utils.d.ts.map +1 -1
  145. package/dist/templates/utils.test.d.ts +2 -0
  146. package/dist/templates/utils.test.d.ts.map +1 -0
  147. package/dist/templates/workflow-runner.d.ts +6 -13
  148. package/dist/templates/workflow-runner.d.ts.map +1 -1
  149. package/dist/templates/workflow-runner.test.d.ts +2 -0
  150. package/dist/templates/workflow-runner.test.d.ts.map +1 -0
  151. package/dist/templates/workflow.d.ts +6 -6
  152. package/dist/templates/workflow.d.ts.map +1 -1
  153. package/dist/templates/workflow.test.d.ts +2 -0
  154. package/dist/templates/workflow.test.d.ts.map +1 -0
  155. package/dist/types/analysis-types.d.ts +135 -136
  156. package/dist/types/analysis-types.d.ts.map +1 -1
  157. package/dist/types/generation-types.d.ts +36 -37
  158. package/dist/types/generation-types.d.ts.map +1 -1
  159. package/dist/types/index.d.ts +9 -0
  160. package/dist/types/index.d.ts.map +1 -0
  161. package/dist/types/llm-types.d.ts +97 -96
  162. package/dist/types/llm-types.d.ts.map +1 -1
  163. package/dist/types/rulesync-types.d.ts +17 -18
  164. package/dist/types/rulesync-types.d.ts.map +1 -1
  165. package/dist/types/spec-types.d.ts +329 -329
  166. package/dist/types/spec-types.d.ts.map +1 -1
  167. package/package.json +20 -16
  168. package/dist/ai/prompts/code-generation.js +0 -134
  169. package/dist/ai/prompts/code-generation.js.map +0 -1
  170. package/dist/ai/prompts/spec-creation.js +0 -102
  171. package/dist/ai/prompts/spec-creation.js.map +0 -1
  172. package/dist/analysis/deps/graph.js +0 -85
  173. package/dist/analysis/deps/graph.js.map +0 -1
  174. package/dist/analysis/deps/parse-imports.js +0 -31
  175. package/dist/analysis/deps/parse-imports.js.map +0 -1
  176. package/dist/analysis/diff/deep-diff.js +0 -114
  177. package/dist/analysis/diff/deep-diff.js.map +0 -1
  178. package/dist/analysis/diff/semantic.js +0 -97
  179. package/dist/analysis/diff/semantic.js.map +0 -1
  180. package/dist/analysis/example-scan.js +0 -116
  181. package/dist/analysis/example-scan.js.map +0 -1
  182. package/dist/analysis/feature-extractor.js +0 -203
  183. package/dist/analysis/feature-extractor.js.map +0 -1
  184. package/dist/analysis/feature-scan.js +0 -56
  185. package/dist/analysis/feature-scan.js.map +0 -1
  186. package/dist/analysis/grouping.js +0 -115
  187. package/dist/analysis/grouping.js.map +0 -1
  188. package/dist/analysis/impact/classifier.js +0 -135
  189. package/dist/analysis/impact/classifier.js.map +0 -1
  190. package/dist/analysis/impact/index.js +0 -2
  191. package/dist/analysis/impact/rules.js +0 -154
  192. package/dist/analysis/impact/rules.js.map +0 -1
  193. package/dist/analysis/index.js +0 -18
  194. package/dist/analysis/snapshot/index.js +0 -2
  195. package/dist/analysis/snapshot/normalizer.js +0 -67
  196. package/dist/analysis/snapshot/normalizer.js.map +0 -1
  197. package/dist/analysis/snapshot/snapshot.js +0 -163
  198. package/dist/analysis/snapshot/snapshot.js.map +0 -1
  199. package/dist/analysis/spec-parser.js +0 -89
  200. package/dist/analysis/spec-parser.js.map +0 -1
  201. package/dist/analysis/spec-parsing-utils.js +0 -98
  202. package/dist/analysis/spec-parsing-utils.js.map +0 -1
  203. package/dist/analysis/spec-scan.js +0 -157
  204. package/dist/analysis/spec-scan.js.map +0 -1
  205. package/dist/analysis/utils/matchers.js +0 -77
  206. package/dist/analysis/utils/matchers.js.map +0 -1
  207. package/dist/analysis/utils/variables.js +0 -45
  208. package/dist/analysis/utils/variables.js.map +0 -1
  209. package/dist/analysis/validate/index.js +0 -1
  210. package/dist/analysis/validate/spec-structure.js +0 -475
  211. package/dist/analysis/validate/spec-structure.js.map +0 -1
  212. package/dist/formatter.js +0 -163
  213. package/dist/formatter.js.map +0 -1
  214. package/dist/formatters/index.js +0 -2
  215. package/dist/formatters/spec-markdown.js +0 -263
  216. package/dist/formatters/spec-markdown.js.map +0 -1
  217. package/dist/formatters/spec-to-docblock.js +0 -48
  218. package/dist/formatters/spec-to-docblock.js.map +0 -1
  219. package/dist/templates/app-config.js +0 -107
  220. package/dist/templates/app-config.js.map +0 -1
  221. package/dist/templates/data-view.js +0 -69
  222. package/dist/templates/data-view.js.map +0 -1
  223. package/dist/templates/event.js +0 -41
  224. package/dist/templates/event.js.map +0 -1
  225. package/dist/templates/experiment.js +0 -88
  226. package/dist/templates/experiment.js.map +0 -1
  227. package/dist/templates/handler.js +0 -96
  228. package/dist/templates/handler.js.map +0 -1
  229. package/dist/templates/integration-utils.js +0 -102
  230. package/dist/templates/integration-utils.js.map +0 -1
  231. package/dist/templates/integration.js +0 -62
  232. package/dist/templates/integration.js.map +0 -1
  233. package/dist/templates/knowledge.js +0 -68
  234. package/dist/templates/knowledge.js.map +0 -1
  235. package/dist/templates/migration.js +0 -60
  236. package/dist/templates/migration.js.map +0 -1
  237. package/dist/templates/operation.js +0 -101
  238. package/dist/templates/operation.js.map +0 -1
  239. package/dist/templates/presentation.js +0 -79
  240. package/dist/templates/presentation.js.map +0 -1
  241. package/dist/templates/telemetry.js +0 -90
  242. package/dist/templates/telemetry.js.map +0 -1
  243. package/dist/templates/utils.js +0 -39
  244. package/dist/templates/utils.js.map +0 -1
  245. package/dist/templates/workflow-runner.js +0 -49
  246. package/dist/templates/workflow-runner.js.map +0 -1
  247. package/dist/templates/workflow.js +0 -68
  248. package/dist/templates/workflow.js.map +0 -1
@@ -1,163 +0,0 @@
1
- import { scanSpecSource } from "../spec-scan.js";
2
- import { computeHash, sortFields, sortSpecs } from "./normalizer.js";
3
-
4
- //#region src/analysis/snapshot/snapshot.ts
5
- /**
6
- * Contract snapshot generation.
7
- *
8
- * Generates canonical, deterministic snapshots from spec source files
9
- * for comparison and impact detection.
10
- */
11
- /**
12
- * Generate a contract snapshot from spec source files.
13
- *
14
- * @param specs - Array of { path, content } for each spec file
15
- * @param options - Snapshot generation options
16
- * @returns Canonical contract snapshot
17
- */
18
- function generateSnapshot(specs, options = {}) {
19
- const snapshots = [];
20
- for (const { path, content } of specs) {
21
- const scanned = scanSpecSource(content, path);
22
- if (options.types && !options.types.includes(scanned.specType)) continue;
23
- if (scanned.specType === "operation" && scanned.key && scanned.version !== void 0) {
24
- const opSnapshot = createOperationSnapshot(scanned, content);
25
- if (opSnapshot) snapshots.push(opSnapshot);
26
- } else if (scanned.specType === "event" && scanned.key && scanned.version !== void 0) {
27
- const eventSnapshot = createEventSnapshot(scanned, content);
28
- if (eventSnapshot) snapshots.push(eventSnapshot);
29
- }
30
- }
31
- const sortedSpecs = sortSpecs(snapshots);
32
- const hash = computeHash({ specs: sortedSpecs });
33
- return {
34
- version: "1.0.0",
35
- generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
36
- specs: sortedSpecs,
37
- hash
38
- };
39
- }
40
- /**
41
- * Create an operation snapshot from scanned spec data.
42
- */
43
- function createOperationSnapshot(scanned, content) {
44
- if (!scanned.key || scanned.version === void 0) return null;
45
- const io = extractIoFromSource(content);
46
- const http = extractHttpBinding(content);
47
- return {
48
- type: "operation",
49
- key: scanned.key,
50
- version: scanned.version,
51
- kind: scanned.kind === "command" || scanned.kind === "query" ? scanned.kind : "command",
52
- stability: scanned.stability ?? "experimental",
53
- http: http ?? void 0,
54
- io,
55
- authLevel: extractAuthLevel(content),
56
- emittedEvents: scanned.emittedEvents
57
- };
58
- }
59
- /**
60
- * Create an event snapshot from scanned spec data.
61
- */
62
- function createEventSnapshot(scanned, content) {
63
- if (!scanned.key || scanned.version === void 0) return null;
64
- const payload = extractPayloadFromSource(content);
65
- return {
66
- type: "event",
67
- key: scanned.key,
68
- version: scanned.version,
69
- stability: scanned.stability ?? "experimental",
70
- payload
71
- };
72
- }
73
- /**
74
- * Extract IO schema from source code.
75
- * This is a heuristic extraction - not full Zod introspection.
76
- */
77
- function extractIoFromSource(content) {
78
- const input = extractSchemaFields(content, "input");
79
- const output = extractSchemaFields(content, "output");
80
- return {
81
- input: sortFields(input),
82
- output: sortFields(output)
83
- };
84
- }
85
- /**
86
- * Extract payload schema from event source code.
87
- */
88
- function extractPayloadFromSource(content) {
89
- return sortFields(extractSchemaFields(content, "payload"));
90
- }
91
- /**
92
- * Extract schema fields from a specific section of the source.
93
- */
94
- function extractSchemaFields(content, section) {
95
- const fields = {};
96
- const sectionPattern = new RegExp(`${section}\\s*:\\s*z\\.object\\(\\{([^}]+)\\}`, "s");
97
- const sectionMatch = content.match(sectionPattern);
98
- if (!sectionMatch?.[1]) return fields;
99
- const sectionContent = sectionMatch[1];
100
- const fieldPattern = /(\w+)\s*:\s*z\.(\w+)\((.*?)\)/g;
101
- let match;
102
- while ((match = fieldPattern.exec(sectionContent)) !== null) {
103
- const [, fieldName, zodType] = match;
104
- if (!fieldName || !zodType) continue;
105
- const isOptional = sectionContent.includes(`${fieldName}:`) && sectionContent.slice(sectionContent.indexOf(`${fieldName}:`)).includes(".optional()");
106
- const isNullable = sectionContent.includes(`${fieldName}:`) && sectionContent.slice(sectionContent.indexOf(`${fieldName}:`)).includes(".nullable()");
107
- fields[fieldName] = {
108
- name: fieldName,
109
- type: mapZodTypeToFieldType(zodType),
110
- required: !isOptional,
111
- nullable: isNullable
112
- };
113
- }
114
- return fields;
115
- }
116
- /**
117
- * Map Zod type to FieldType.
118
- */
119
- function mapZodTypeToFieldType(zodType) {
120
- return {
121
- string: "string",
122
- number: "number",
123
- boolean: "boolean",
124
- object: "object",
125
- array: "array",
126
- enum: "enum",
127
- union: "union",
128
- literal: "literal",
129
- date: "date",
130
- coerce: "unknown"
131
- }[zodType] ?? "unknown";
132
- }
133
- /**
134
- * Extract HTTP binding from source code.
135
- */
136
- function extractHttpBinding(content) {
137
- const methodMatch = content.match(/method\s*:\s*['"](\w+)['"]/);
138
- const pathMatch = content.match(/path\s*:\s*['"]([^'"]+)['"]/);
139
- if (methodMatch?.[1] && pathMatch?.[1]) {
140
- const method = methodMatch[1].toUpperCase();
141
- if ([
142
- "GET",
143
- "POST",
144
- "PUT",
145
- "PATCH",
146
- "DELETE"
147
- ].includes(method)) return {
148
- method,
149
- path: pathMatch[1]
150
- };
151
- }
152
- return null;
153
- }
154
- /**
155
- * Extract auth level from source code.
156
- */
157
- function extractAuthLevel(content) {
158
- return content.match(/auth\s*:\s*['"](\w+)['"]/)?.[1];
159
- }
160
-
161
- //#endregion
162
- export { generateSnapshot };
163
- //# sourceMappingURL=snapshot.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"snapshot.js","names":[],"sources":["../../../src/analysis/snapshot/snapshot.ts"],"sourcesContent":["/**\n * Contract snapshot generation.\n *\n * Generates canonical, deterministic snapshots from spec source files\n * for comparison and impact detection.\n */\n\nimport { scanSpecSource } from '../spec-scan';\nimport { computeHash, sortSpecs, sortFields } from './normalizer';\nimport type {\n ContractSnapshot,\n EventSnapshot,\n FieldSnapshot,\n FieldType,\n IoSnapshot,\n OperationSnapshot,\n SnapshotOptions,\n SpecSnapshot,\n} from './types';\n\n/**\n * Generate a contract snapshot from spec source files.\n *\n * @param specs - Array of { path, content } for each spec file\n * @param options - Snapshot generation options\n * @returns Canonical contract snapshot\n */\nexport function generateSnapshot(\n specs: { path: string; content: string }[],\n options: SnapshotOptions = {}\n): ContractSnapshot {\n const snapshots: SpecSnapshot[] = [];\n\n for (const { path, content } of specs) {\n const scanned = scanSpecSource(content, path);\n\n // Filter by types if specified\n if (\n options.types &&\n !options.types.includes(scanned.specType as 'operation' | 'event')\n ) {\n continue;\n }\n\n if (\n scanned.specType === 'operation' &&\n scanned.key &&\n scanned.version !== undefined\n ) {\n const opSnapshot = createOperationSnapshot(scanned, content);\n if (opSnapshot) {\n snapshots.push(opSnapshot);\n }\n } else if (\n scanned.specType === 'event' &&\n scanned.key &&\n scanned.version !== undefined\n ) {\n const eventSnapshot = createEventSnapshot(scanned, content);\n if (eventSnapshot) {\n snapshots.push(eventSnapshot);\n }\n }\n }\n\n const sortedSpecs = sortSpecs(snapshots);\n const hash = computeHash({ specs: sortedSpecs });\n\n return {\n version: '1.0.0',\n generatedAt: new Date().toISOString(),\n specs: sortedSpecs,\n hash,\n };\n}\n\n/**\n * Create an operation snapshot from scanned spec data.\n */\nfunction createOperationSnapshot(\n scanned: ReturnType<typeof scanSpecSource>,\n content: string\n): OperationSnapshot | null {\n if (!scanned.key || scanned.version === undefined) {\n return null;\n }\n\n const io = extractIoFromSource(content);\n const http = extractHttpBinding(content);\n\n return {\n type: 'operation',\n key: scanned.key,\n version: scanned.version,\n kind:\n scanned.kind === 'command' || scanned.kind === 'query'\n ? scanned.kind\n : 'command',\n stability: scanned.stability ?? 'experimental',\n http: http ?? undefined,\n io,\n authLevel: extractAuthLevel(content),\n emittedEvents: scanned.emittedEvents,\n };\n}\n\n/**\n * Create an event snapshot from scanned spec data.\n */\nfunction createEventSnapshot(\n scanned: ReturnType<typeof scanSpecSource>,\n content: string\n): EventSnapshot | null {\n if (!scanned.key || scanned.version === undefined) {\n return null;\n }\n\n const payload = extractPayloadFromSource(content);\n\n return {\n type: 'event',\n key: scanned.key,\n version: scanned.version,\n stability: scanned.stability ?? 'experimental',\n payload,\n };\n}\n\n/**\n * Extract IO schema from source code.\n * This is a heuristic extraction - not full Zod introspection.\n */\nfunction extractIoFromSource(content: string): IoSnapshot {\n const input = extractSchemaFields(content, 'input');\n const output = extractSchemaFields(content, 'output');\n\n return {\n input: sortFields(input) as Record<string, FieldSnapshot>,\n output: sortFields(output) as Record<string, FieldSnapshot>,\n };\n}\n\n/**\n * Extract payload schema from event source code.\n */\nfunction extractPayloadFromSource(\n content: string\n): Record<string, FieldSnapshot> {\n const fields = extractSchemaFields(content, 'payload');\n return sortFields(fields) as Record<string, FieldSnapshot>;\n}\n\n/**\n * Extract schema fields from a specific section of the source.\n */\nfunction extractSchemaFields(\n content: string,\n section: 'input' | 'output' | 'payload'\n): Record<string, FieldSnapshot> {\n const fields: Record<string, FieldSnapshot> = {};\n\n // Look for z.object({ ... }) patterns within the section\n const sectionPattern = new RegExp(\n `${section}\\\\s*:\\\\s*z\\\\.object\\\\(\\\\{([^}]+)\\\\}`,\n 's'\n );\n const sectionMatch = content.match(sectionPattern);\n\n if (!sectionMatch?.[1]) {\n return fields;\n }\n\n const sectionContent = sectionMatch[1];\n\n // Match field definitions: fieldName: z.string(), z.number(), etc.\n const fieldPattern = /(\\w+)\\s*:\\s*z\\.(\\w+)\\((.*?)\\)/g;\n let match;\n\n while ((match = fieldPattern.exec(sectionContent)) !== null) {\n const [, fieldName, zodType] = match;\n if (!fieldName || !zodType) continue;\n\n const isOptional =\n sectionContent.includes(`${fieldName}:`) &&\n sectionContent\n .slice(sectionContent.indexOf(`${fieldName}:`))\n .includes('.optional()');\n const isNullable =\n sectionContent.includes(`${fieldName}:`) &&\n sectionContent\n .slice(sectionContent.indexOf(`${fieldName}:`))\n .includes('.nullable()');\n\n fields[fieldName] = {\n name: fieldName,\n type: mapZodTypeToFieldType(zodType),\n required: !isOptional,\n nullable: isNullable,\n };\n }\n\n return fields;\n}\n\n/**\n * Map Zod type to FieldType.\n */\nfunction mapZodTypeToFieldType(zodType: string): FieldType {\n const mapping: Record<string, FieldType> = {\n string: 'string',\n number: 'number',\n boolean: 'boolean',\n object: 'object',\n array: 'array',\n enum: 'enum',\n union: 'union',\n literal: 'literal',\n date: 'date',\n coerce: 'unknown',\n };\n return mapping[zodType] ?? 'unknown';\n}\n\n/**\n * Extract HTTP binding from source code.\n */\nfunction extractHttpBinding(content: string): {\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n path: string;\n} | null {\n // Look for http: { method: 'X', path: 'Y' } pattern\n const methodMatch = content.match(/method\\s*:\\s*['\"](\\w+)['\"]/);\n const pathMatch = content.match(/path\\s*:\\s*['\"]([^'\"]+)['\"]/);\n\n if (methodMatch?.[1] && pathMatch?.[1]) {\n const method = methodMatch[1].toUpperCase();\n if (['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) {\n return {\n method: method as 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',\n path: pathMatch[1],\n };\n }\n }\n\n return null;\n}\n\n/**\n * Extract auth level from source code.\n */\nfunction extractAuthLevel(content: string): string | undefined {\n const authMatch = content.match(/auth\\s*:\\s*['\"](\\w+)['\"]/);\n return authMatch?.[1];\n}\n"],"mappings":"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"}
@@ -1,89 +0,0 @@
1
- import { scanAllSpecsFromSource } from "./spec-scan.js";
2
- import { isFeatureFile, scanFeatureSource } from "./feature-scan.js";
3
- import { readFile } from "node:fs/promises";
4
-
5
- //#region src/analysis/spec-parser.ts
6
- /**
7
- * Spec Parser
8
- *
9
- * Coordinates scanning of source files and mapping to ParsedSpec format
10
- * for LLM consumption.
11
- */
12
- /**
13
- * Load and parse specs from a source file.
14
- */
15
- async function loadSpecFromSource(filePath) {
16
- try {
17
- const code = await readFile(filePath, "utf-8");
18
- if (isFeatureFile(filePath)) return [mapFeatureResultToParsedSpec(scanFeatureSource(code, filePath))];
19
- return scanAllSpecsFromSource(code, filePath).map(mapSpecResultToParsedSpec);
20
- } catch (error) {
21
- console.warn(`Failed to parse spec from ${filePath}:`, error);
22
- return [];
23
- }
24
- }
25
- /**
26
- * Map FeatureScanResult to ParsedSpec.
27
- */
28
- function mapFeatureResultToParsedSpec(result) {
29
- return {
30
- meta: {
31
- key: result.key,
32
- version: "1.0.0",
33
- description: result.description,
34
- stability: result.stability,
35
- owners: result.owners,
36
- tags: result.tags,
37
- goal: result.goal,
38
- context: result.context
39
- },
40
- specType: "feature",
41
- filePath: result.filePath,
42
- sourceBlock: result.sourceBlock,
43
- operations: result.operations.map(mapToSpecRef),
44
- events: result.events.map(mapToSpecRef),
45
- presentations: result.presentations.map(mapToSpecRef)
46
- };
47
- }
48
- /**
49
- * Map SpecScanResult to ParsedSpec.
50
- */
51
- function mapSpecResultToParsedSpec(result) {
52
- return {
53
- meta: {
54
- key: result.key ?? "unknown",
55
- version: result.version ?? "1.0.0",
56
- description: result.description,
57
- stability: result.stability,
58
- owners: result.owners,
59
- tags: result.tags,
60
- goal: result.goal,
61
- context: result.context
62
- },
63
- specType: result.specType,
64
- kind: result.kind,
65
- hasIo: result.hasIo,
66
- hasPolicy: result.hasPolicy,
67
- hasPayload: result.hasPayload,
68
- hasContent: result.hasContent,
69
- hasDefinition: result.hasDefinition,
70
- emittedEvents: result.emittedEvents?.map(mapToSpecRef),
71
- policyRefs: result.policyRefs?.map(mapToSpecRef),
72
- testRefs: result.testRefs?.map(mapToSpecRef),
73
- filePath: result.filePath,
74
- sourceBlock: result.sourceBlock
75
- };
76
- }
77
- /**
78
- * Map RefInfo to SpecRef.
79
- */
80
- function mapToSpecRef(ref) {
81
- return {
82
- name: ref.key,
83
- version: ref.version
84
- };
85
- }
86
-
87
- //#endregion
88
- export { loadSpecFromSource };
89
- //# sourceMappingURL=spec-parser.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"spec-parser.js","names":[],"sources":["../../src/analysis/spec-parser.ts"],"sourcesContent":["/**\n * Spec Parser\n *\n * Coordinates scanning of source files and mapping to ParsedSpec format\n * for LLM consumption.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { isFeatureFile, scanFeatureSource } from './feature-scan';\nimport { scanAllSpecsFromSource } from './spec-scan';\nimport type { ParsedSpec, ParsedSpecMeta, SpecRef } from '../types/llm-types';\nimport type {\n FeatureScanResult,\n RefInfo,\n SpecScanResult,\n} from '../types/analysis-types';\n\n/**\n * Load and parse specs from a source file.\n */\nexport async function loadSpecFromSource(\n filePath: string\n): Promise<ParsedSpec[]> {\n try {\n const code = await readFile(filePath, 'utf-8');\n\n if (isFeatureFile(filePath)) {\n const featureResult = scanFeatureSource(code, filePath);\n return [mapFeatureResultToParsedSpec(featureResult)];\n }\n\n const specResults = scanAllSpecsFromSource(code, filePath);\n return specResults.map(mapSpecResultToParsedSpec);\n } catch (error) {\n // Return empty array if file reading fails\n console.warn(`Failed to parse spec from ${filePath}:`, error);\n return [];\n }\n}\n\n/**\n * Map FeatureScanResult to ParsedSpec.\n */\nfunction mapFeatureResultToParsedSpec(result: FeatureScanResult): ParsedSpec {\n const meta: ParsedSpecMeta = {\n key: result.key,\n version: '1.0.0', // Default for features if not specified\n description: result.description,\n stability: result.stability,\n owners: result.owners,\n tags: result.tags,\n goal: result.goal,\n context: result.context,\n };\n\n return {\n meta,\n specType: 'feature',\n filePath: result.filePath,\n sourceBlock: result.sourceBlock,\n operations: result.operations.map(mapToSpecRef),\n events: result.events.map(mapToSpecRef),\n presentations: result.presentations.map(mapToSpecRef),\n };\n}\n\n/**\n * Map SpecScanResult to ParsedSpec.\n */\nfunction mapSpecResultToParsedSpec(result: SpecScanResult): ParsedSpec {\n const meta: ParsedSpecMeta = {\n key: result.key ?? 'unknown',\n version: result.version ?? '1.0.0',\n description: result.description,\n stability: result.stability,\n owners: result.owners,\n tags: result.tags,\n goal: result.goal,\n context: result.context,\n };\n\n return {\n meta,\n specType: result.specType,\n kind: result.kind,\n hasIo: result.hasIo,\n hasPolicy: result.hasPolicy,\n hasPayload: result.hasPayload,\n hasContent: result.hasContent,\n hasDefinition: result.hasDefinition,\n emittedEvents: result.emittedEvents?.map(mapToSpecRef),\n policyRefs: result.policyRefs?.map(mapToSpecRef),\n testRefs: result.testRefs?.map(mapToSpecRef),\n filePath: result.filePath,\n sourceBlock: result.sourceBlock,\n };\n}\n\n/**\n * Map RefInfo to SpecRef.\n */\nfunction mapToSpecRef(ref: RefInfo): SpecRef {\n return {\n name: ref.key,\n version: ref.version,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AAoBA,eAAsB,mBACpB,UACuB;AACvB,KAAI;EACF,MAAM,OAAO,MAAM,SAAS,UAAU,QAAQ;AAE9C,MAAI,cAAc,SAAS,CAEzB,QAAO,CAAC,6BADc,kBAAkB,MAAM,SAAS,CACJ,CAAC;AAItD,SADoB,uBAAuB,MAAM,SAAS,CACvC,IAAI,0BAA0B;UAC1C,OAAO;AAEd,UAAQ,KAAK,6BAA6B,SAAS,IAAI,MAAM;AAC7D,SAAO,EAAE;;;;;;AAOb,SAAS,6BAA6B,QAAuC;AAY3E,QAAO;EACL,MAZ2B;GAC3B,KAAK,OAAO;GACZ,SAAS;GACT,aAAa,OAAO;GACpB,WAAW,OAAO;GAClB,QAAQ,OAAO;GACf,MAAM,OAAO;GACb,MAAM,OAAO;GACb,SAAS,OAAO;GACjB;EAIC,UAAU;EACV,UAAU,OAAO;EACjB,aAAa,OAAO;EACpB,YAAY,OAAO,WAAW,IAAI,aAAa;EAC/C,QAAQ,OAAO,OAAO,IAAI,aAAa;EACvC,eAAe,OAAO,cAAc,IAAI,aAAa;EACtD;;;;;AAMH,SAAS,0BAA0B,QAAoC;AAYrE,QAAO;EACL,MAZ2B;GAC3B,KAAK,OAAO,OAAO;GACnB,SAAS,OAAO,WAAW;GAC3B,aAAa,OAAO;GACpB,WAAW,OAAO;GAClB,QAAQ,OAAO;GACf,MAAM,OAAO;GACb,MAAM,OAAO;GACb,SAAS,OAAO;GACjB;EAIC,UAAU,OAAO;EACjB,MAAM,OAAO;EACb,OAAO,OAAO;EACd,WAAW,OAAO;EAClB,YAAY,OAAO;EACnB,YAAY,OAAO;EACnB,eAAe,OAAO;EACtB,eAAe,OAAO,eAAe,IAAI,aAAa;EACtD,YAAY,OAAO,YAAY,IAAI,aAAa;EAChD,UAAU,OAAO,UAAU,IAAI,aAAa;EAC5C,UAAU,OAAO;EACjB,aAAa,OAAO;EACrB;;;;;AAMH,SAAS,aAAa,KAAuB;AAC3C,QAAO;EACL,MAAM,IAAI;EACV,SAAS,IAAI;EACd"}
@@ -1,98 +0,0 @@
1
- import { escapeRegex, findMatchingDelimiter, matchStringField, matchVersionField } from "./utils/matchers.js";
2
-
3
- //#region src/analysis/spec-parsing-utils.ts
4
- function parsePolicy(code) {
5
- const policyBlock = code.match(/policy\s*:\s*\{([\s\S]*?)\}/);
6
- if (!policyBlock?.[1]) return [];
7
- return extractRefList(policyBlock[1], "policies") ?? [];
8
- }
9
- function extractRefList(code, field) {
10
- const regex = new RegExp(`${escapeRegex(field)}\\s*:\\s*\\[([\\s\\S]*?)\\]`);
11
- const match = code.match(regex);
12
- if (!match?.[1]) return void 0;
13
- const inner = match[1];
14
- const items = [];
15
- const parts = inner.match(/\{[\s\S]*?\}/g);
16
- if (parts) for (const part of parts) {
17
- const k = matchStringField(part, "key");
18
- const v = matchVersionField(part, "version");
19
- if (k) items.push({
20
- key: k,
21
- version: v ?? "1.0.0"
22
- });
23
- }
24
- return items.length > 0 ? items : void 0;
25
- }
26
- function extractTestRefs(code) {
27
- const regex = new RegExp(`testRefs\\s*:\\s*\\[([\\s\\S]*?)\\]`);
28
- const match = code.match(regex);
29
- if (!match?.[1]) return void 0;
30
- const inner = match[1];
31
- const items = [];
32
- const parts = inner.match(/\{[\s\S]*?\}/g);
33
- if (parts) for (const part of parts) {
34
- const k = matchStringField(part, "key");
35
- const v = matchVersionField(part, "version");
36
- const t = matchStringField(part, "type");
37
- if (k) items.push({
38
- key: k,
39
- version: v ?? "1.0.0",
40
- type: t === "error" ? "error" : "success"
41
- });
42
- }
43
- return items.length > 0 ? items : void 0;
44
- }
45
- /**
46
- * Extract test target from a TestSpec source.
47
- * Parses the `target: { type: 'operation', key, version }` field OR
48
- * the nested format `target: { type: 'operation', operation: { key, version } }`.
49
- */
50
- function extractTestTarget(code) {
51
- const targetStartMatch = code.match(/target\s*:\s*\{/);
52
- if (!targetStartMatch || targetStartMatch.index === void 0) return void 0;
53
- const openBraceIndex = targetStartMatch.index + targetStartMatch[0].length - 1;
54
- const closeBraceIndex = findMatchingDelimiter(code, openBraceIndex, "{", "}");
55
- if (closeBraceIndex === -1) return void 0;
56
- const targetBlock = code.substring(openBraceIndex + 1, closeBraceIndex);
57
- const typeMatch = targetBlock.match(/type\s*:\s*['"](\w+)['"]/);
58
- if (!typeMatch?.[1]) return void 0;
59
- const type = typeMatch[1];
60
- if (type !== "operation" && type !== "workflow") return void 0;
61
- const flatKey = matchStringField(targetBlock, "key");
62
- if (flatKey) return {
63
- type,
64
- key: flatKey,
65
- version: matchVersionField(targetBlock, "version")
66
- };
67
- const refBlockMatch = targetBlock.match(new RegExp(`${type}\\s*:\\s*\\{([\\s\\S]*?)\\}`));
68
- if (!refBlockMatch?.[1]) return void 0;
69
- const refBlock = refBlockMatch[1];
70
- const key = matchStringField(refBlock, "key");
71
- if (!key) return void 0;
72
- return {
73
- type,
74
- key,
75
- version: matchVersionField(refBlock, "version")
76
- };
77
- }
78
- /**
79
- * Extract test coverage info from a TestSpec source.
80
- * Checks for presence of success (expectOutput) and failure (expectError) scenarios.
81
- * Supports both formats:
82
- * - New: `expectOutput: {}` and `expectError: {}`
83
- * - Old: `{ type: 'expectOutput', ... }` and `{ type: 'expectError', ... }`
84
- */
85
- function extractTestCoverage(code) {
86
- const hasSuccessNew = /expectOutput\s*:/.test(code);
87
- const hasErrorNew = /expectError\s*:/.test(code);
88
- const hasSuccessOld = /(['"]?)type\1\s*:\s*['"]expectOutput['"]/.test(code);
89
- const hasErrorOld = /(['"]?)type\1\s*:\s*['"]expectError['"]/.test(code);
90
- return {
91
- hasSuccess: hasSuccessNew || hasSuccessOld,
92
- hasError: hasErrorNew || hasErrorOld
93
- };
94
- }
95
-
96
- //#endregion
97
- export { extractRefList, extractTestCoverage, extractTestRefs, extractTestTarget, parsePolicy };
98
- //# sourceMappingURL=spec-parsing-utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"spec-parsing-utils.js","names":[],"sources":["../../src/analysis/spec-parsing-utils.ts"],"sourcesContent":["import {\n escapeRegex,\n matchStringField,\n matchVersionField,\n findMatchingDelimiter,\n} from './utils/matchers';\n\nexport function parsePolicy(code: string): { key: string; version: string }[] {\n const policyBlock = code.match(/policy\\s*:\\s*\\{([\\s\\S]*?)\\}/);\n if (!policyBlock?.[1]) return [];\n\n return extractRefList(policyBlock[1], 'policies') ?? [];\n}\n\nexport function extractRefList(\n code: string,\n field: string\n): { key: string; version: string }[] | undefined {\n const regex = new RegExp(`${escapeRegex(field)}\\\\s*:\\\\s*\\\\[([\\\\s\\\\S]*?)\\\\]`);\n const match = code.match(regex);\n if (!match?.[1]) return undefined;\n\n const inner = match[1];\n const items: { key: string; version: string }[] = [];\n\n const parts = inner.match(/\\{[\\s\\S]*?\\}/g);\n if (parts) {\n for (const part of parts) {\n const k = matchStringField(part, 'key');\n const v = matchVersionField(part, 'version');\n if (k) {\n items.push({ key: k, version: v ?? '1.0.0' });\n }\n }\n }\n\n return items.length > 0 ? items : undefined;\n}\n\nexport function extractTestRefs(\n code: string\n): { key: string; version: string; type: 'success' | 'error' }[] | undefined {\n const regex = new RegExp(`testRefs\\\\s*:\\\\s*\\\\[([\\\\s\\\\S]*?)\\\\]`);\n const match = code.match(regex);\n if (!match?.[1]) return undefined;\n\n const inner = match[1];\n const items: { key: string; version: string; type: 'success' | 'error' }[] =\n [];\n\n const parts = inner.match(/\\{[\\s\\S]*?\\}/g);\n if (parts) {\n for (const part of parts) {\n const k = matchStringField(part, 'key');\n const v = matchVersionField(part, 'version');\n const t = matchStringField(part, 'type');\n if (k) {\n items.push({\n key: k,\n version: v ?? '1.0.0',\n type: t === 'error' ? 'error' : 'success',\n });\n }\n }\n }\n\n return items.length > 0 ? items : undefined;\n}\n\n/**\n * Extract test target from a TestSpec source.\n * Parses the `target: { type: 'operation', key, version }` field OR\n * the nested format `target: { type: 'operation', operation: { key, version } }`.\n */\nexport function extractTestTarget(\n code: string\n):\n | { type: 'operation' | 'workflow'; key: string; version: string | undefined }\n | undefined {\n // Find target block start\n const targetStartMatch = code.match(/target\\s*:\\s*\\{/);\n if (!targetStartMatch || targetStartMatch.index === undefined)\n return undefined;\n\n const openBraceIndex =\n targetStartMatch.index + targetStartMatch[0].length - 1;\n const closeBraceIndex = findMatchingDelimiter(code, openBraceIndex, '{', '}');\n\n if (closeBraceIndex === -1) return undefined;\n\n const targetBlock = code.substring(openBraceIndex + 1, closeBraceIndex);\n\n // Extract the type\n const typeMatch = targetBlock.match(/type\\s*:\\s*['\"](\\w+)['\"]/);\n if (!typeMatch?.[1]) return undefined;\n\n const type = typeMatch[1];\n if (type !== 'operation' && type !== 'workflow') return undefined;\n\n // Try flat format first: { type: 'operation', key: '...', version: '...' }\n const flatKey = matchStringField(targetBlock, 'key');\n if (flatKey) {\n const flatVersion = matchVersionField(targetBlock, 'version');\n return {\n type,\n key: flatKey,\n version: flatVersion,\n };\n }\n\n // Try nested format: { type: 'operation', operation: { key: '...', version: '...' } }\n const refBlockMatch = targetBlock.match(\n new RegExp(`${type}\\\\s*:\\\\s*\\\\{([\\\\s\\\\S]*?)\\\\}`)\n );\n\n if (!refBlockMatch?.[1]) return undefined;\n\n const refBlock = refBlockMatch[1];\n\n // Extract key and version from the ref block\n const key = matchStringField(refBlock, 'key');\n if (!key) return undefined;\n\n const version = matchVersionField(refBlock, 'version');\n\n return {\n type,\n key,\n version,\n };\n}\n\n/**\n * Extract test coverage info from a TestSpec source.\n * Checks for presence of success (expectOutput) and failure (expectError) scenarios.\n * Supports both formats:\n * - New: `expectOutput: {}` and `expectError: {}`\n * - Old: `{ type: 'expectOutput', ... }` and `{ type: 'expectError', ... }`\n */\nexport function extractTestCoverage(code: string): {\n hasSuccess: boolean;\n hasError: boolean;\n} {\n // Check new format: expectOutput: or expectError: as keys\n const hasSuccessNew = /expectOutput\\s*:/.test(code);\n const hasErrorNew = /expectError\\s*:/.test(code);\n\n // Check old format: { type: 'expectOutput' } or { type: 'expectError' }\n const hasSuccessOld = /(['\"]?)type\\1\\s*:\\s*['\"]expectOutput['\"]/.test(code);\n const hasErrorOld = /(['\"]?)type\\1\\s*:\\s*['\"]expectError['\"]/.test(code);\n\n return {\n hasSuccess: hasSuccessNew || hasSuccessOld,\n hasError: hasErrorNew || hasErrorOld,\n };\n}\n"],"mappings":";;;AAOA,SAAgB,YAAY,MAAkD;CAC5E,MAAM,cAAc,KAAK,MAAM,8BAA8B;AAC7D,KAAI,CAAC,cAAc,GAAI,QAAO,EAAE;AAEhC,QAAO,eAAe,YAAY,IAAI,WAAW,IAAI,EAAE;;AAGzD,SAAgB,eACd,MACA,OACgD;CAChD,MAAM,QAAQ,IAAI,OAAO,GAAG,YAAY,MAAM,CAAC,6BAA6B;CAC5E,MAAM,QAAQ,KAAK,MAAM,MAAM;AAC/B,KAAI,CAAC,QAAQ,GAAI,QAAO;CAExB,MAAM,QAAQ,MAAM;CACpB,MAAM,QAA4C,EAAE;CAEpD,MAAM,QAAQ,MAAM,MAAM,gBAAgB;AAC1C,KAAI,MACF,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,IAAI,iBAAiB,MAAM,MAAM;EACvC,MAAM,IAAI,kBAAkB,MAAM,UAAU;AAC5C,MAAI,EACF,OAAM,KAAK;GAAE,KAAK;GAAG,SAAS,KAAK;GAAS,CAAC;;AAKnD,QAAO,MAAM,SAAS,IAAI,QAAQ;;AAGpC,SAAgB,gBACd,MAC2E;CAC3E,MAAM,QAAQ,IAAI,OAAO,sCAAsC;CAC/D,MAAM,QAAQ,KAAK,MAAM,MAAM;AAC/B,KAAI,CAAC,QAAQ,GAAI,QAAO;CAExB,MAAM,QAAQ,MAAM;CACpB,MAAM,QACJ,EAAE;CAEJ,MAAM,QAAQ,MAAM,MAAM,gBAAgB;AAC1C,KAAI,MACF,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,IAAI,iBAAiB,MAAM,MAAM;EACvC,MAAM,IAAI,kBAAkB,MAAM,UAAU;EAC5C,MAAM,IAAI,iBAAiB,MAAM,OAAO;AACxC,MAAI,EACF,OAAM,KAAK;GACT,KAAK;GACL,SAAS,KAAK;GACd,MAAM,MAAM,UAAU,UAAU;GACjC,CAAC;;AAKR,QAAO,MAAM,SAAS,IAAI,QAAQ;;;;;;;AAQpC,SAAgB,kBACd,MAGY;CAEZ,MAAM,mBAAmB,KAAK,MAAM,kBAAkB;AACtD,KAAI,CAAC,oBAAoB,iBAAiB,UAAU,OAClD,QAAO;CAET,MAAM,iBACJ,iBAAiB,QAAQ,iBAAiB,GAAG,SAAS;CACxD,MAAM,kBAAkB,sBAAsB,MAAM,gBAAgB,KAAK,IAAI;AAE7E,KAAI,oBAAoB,GAAI,QAAO;CAEnC,MAAM,cAAc,KAAK,UAAU,iBAAiB,GAAG,gBAAgB;CAGvE,MAAM,YAAY,YAAY,MAAM,2BAA2B;AAC/D,KAAI,CAAC,YAAY,GAAI,QAAO;CAE5B,MAAM,OAAO,UAAU;AACvB,KAAI,SAAS,eAAe,SAAS,WAAY,QAAO;CAGxD,MAAM,UAAU,iBAAiB,aAAa,MAAM;AACpD,KAAI,QAEF,QAAO;EACL;EACA,KAAK;EACL,SAJkB,kBAAkB,aAAa,UAAU;EAK5D;CAIH,MAAM,gBAAgB,YAAY,MAChC,IAAI,OAAO,GAAG,KAAK,6BAA6B,CACjD;AAED,KAAI,CAAC,gBAAgB,GAAI,QAAO;CAEhC,MAAM,WAAW,cAAc;CAG/B,MAAM,MAAM,iBAAiB,UAAU,MAAM;AAC7C,KAAI,CAAC,IAAK,QAAO;AAIjB,QAAO;EACL;EACA;EACA,SALc,kBAAkB,UAAU,UAAU;EAMrD;;;;;;;;;AAUH,SAAgB,oBAAoB,MAGlC;CAEA,MAAM,gBAAgB,mBAAmB,KAAK,KAAK;CACnD,MAAM,cAAc,kBAAkB,KAAK,KAAK;CAGhD,MAAM,gBAAgB,2CAA2C,KAAK,KAAK;CAC3E,MAAM,cAAc,0CAA0C,KAAK,KAAK;AAExE,QAAO;EACL,YAAY,iBAAiB;EAC7B,UAAU,eAAe;EAC1B"}
@@ -1,157 +0,0 @@
1
- import { findMatchingDelimiter, isStability, matchStringArrayField, matchStringField, matchVersionField } from "./utils/matchers.js";
2
- import { extractArrayConstants, resolveVariablesInBlock } from "./utils/variables.js";
3
- import { extractRefList, extractTestCoverage, extractTestRefs, extractTestTarget, parsePolicy } from "./spec-parsing-utils.js";
4
-
5
- //#region src/analysis/spec-scan.ts
6
- /**
7
- * Scan all specs from a single source file.
8
- */
9
- function scanAllSpecsFromSource(code, filePath) {
10
- const results = [];
11
- const variables = extractArrayConstants(code);
12
- const definitionRegex = /export\s+const\s+(\w+)\s*=\s*define(Command|Query|Event|Presentation|Capability|Policy|Type|Example|AppConfig|Integration|Workflow|TestSpec|Feature)\s*\(/g;
13
- let match;
14
- while ((match = definitionRegex.exec(code)) !== null) {
15
- const start = match.index;
16
- const end = findMatchingDelimiter(code, start + match[0].length - 1, "(", ")");
17
- if (end === -1) continue;
18
- let finalEnd = end;
19
- if (code[finalEnd + 1] === ";") finalEnd++;
20
- const resolvedBlock = resolveVariablesInBlock(code.substring(start, finalEnd + 1), variables);
21
- const result = scanSpecSource(resolvedBlock, filePath);
22
- if (result) results.push({
23
- ...result,
24
- sourceBlock: resolvedBlock
25
- });
26
- }
27
- if (results.length === 0 && filePath.includes(".spec.")) {
28
- if (scanSpecSource(code, filePath).key !== "unknown") {
29
- const result = scanSpecSource(resolveVariablesInBlock(code, variables), filePath);
30
- results.push(result);
31
- }
32
- }
33
- return results;
34
- }
35
- function inferSpecTypeFromCodeBlock(fileSourceCode) {
36
- if (fileSourceCode.includes("defineCommand")) return {
37
- specType: "operation",
38
- kind: "command"
39
- };
40
- if (fileSourceCode.includes("defineQuery")) return {
41
- specType: "operation",
42
- kind: "query"
43
- };
44
- if (fileSourceCode.includes("defineEvent")) return {
45
- specType: "event",
46
- kind: "event"
47
- };
48
- if (fileSourceCode.includes("definePresentation")) return {
49
- specType: "presentation",
50
- kind: "presentation"
51
- };
52
- if (fileSourceCode.includes("definePolicy")) return {
53
- specType: "policy",
54
- kind: "policy"
55
- };
56
- if (fileSourceCode.includes("defineCapability")) return {
57
- specType: "capability",
58
- kind: "capability"
59
- };
60
- if (fileSourceCode.includes("defineExample")) return {
61
- specType: "example",
62
- kind: "example"
63
- };
64
- if (fileSourceCode.includes("defineAppConfig") && !fileSourceCode.includes("export const defineAppConfig")) return {
65
- specType: "app-config",
66
- kind: "app-config"
67
- };
68
- if (fileSourceCode.includes("defineIntegration")) return {
69
- specType: "integration",
70
- kind: "integration"
71
- };
72
- if (fileSourceCode.includes("defineWorkflow")) return {
73
- specType: "workflow",
74
- kind: "workflow"
75
- };
76
- if (fileSourceCode.includes("defineTestSpec")) return {
77
- specType: "test-spec",
78
- kind: "test-spec"
79
- };
80
- if (fileSourceCode.includes("defineFeature")) return {
81
- specType: "feature",
82
- kind: "feature"
83
- };
84
- return {
85
- specType: "unknown",
86
- kind: "unknown"
87
- };
88
- }
89
- /**
90
- * Scan a single spec source string.
91
- */
92
- function scanSpecSource(code, filePath) {
93
- const key = (code.match(/key\s*:\s*['"]([^'"]+)['"]/) ?? code.match(/export\s+const\s+(\w+)\s*=/))?.[1] ?? "unknown";
94
- const version = matchVersionField(code, "version");
95
- const description = matchStringField(code, "description") ?? void 0;
96
- const goal = matchStringField(code, "goal") ?? void 0;
97
- const context = matchStringField(code, "context") ?? void 0;
98
- const stabilityRaw = matchStringField(code, "stability");
99
- const stability = isStability(stabilityRaw) ? stabilityRaw : void 0;
100
- const owners = matchStringArrayField(code, "owners");
101
- const tags = matchStringArrayField(code, "tags");
102
- const inferredSpecType = inferSpecTypeFromCodeBlock(code);
103
- const hasMeta = /meta\s*:\s*\{/.test(code);
104
- const hasIo = /io\s*:\s*\{/.test(code);
105
- const hasPolicy = /policy\s*:\s*\{/.test(code);
106
- const hasPayload = /payload\s*:\s*\{/.test(code);
107
- const hasContent = /content\s*:\s*\{/.test(code);
108
- const hasDefinition = /definition\s*:\s*\{/.test(code);
109
- const emittedEvents = extractRefList(code, "emits") ?? extractRefList(code, "emittedEvents");
110
- const testRefs = extractTestRefs(code);
111
- const policyRefs = hasPolicy ? parsePolicy(code) : void 0;
112
- return {
113
- filePath,
114
- key,
115
- version,
116
- specType: inferredSpecType.specType,
117
- kind: inferredSpecType.kind,
118
- description,
119
- goal,
120
- context,
121
- stability,
122
- owners,
123
- tags,
124
- hasMeta,
125
- hasIo,
126
- hasPolicy,
127
- hasPayload,
128
- hasContent,
129
- hasDefinition,
130
- emittedEvents,
131
- policyRefs,
132
- testRefs,
133
- testTarget: extractTestTarget(code),
134
- testCoverage: extractTestCoverage(code),
135
- sourceBlock: code
136
- };
137
- }
138
- /**
139
- * Infer spec type from file path convention.
140
- */
141
- function inferSpecTypeFromFilePath(filePath) {
142
- if (filePath.includes(".contracts.") || /\/operations?\//.test(filePath)) return "operation";
143
- if (filePath.includes(".event.") || /\/events?\//.test(filePath)) return "event";
144
- if (filePath.includes(".presentation.") || /\/presentations?\//.test(filePath)) return "presentation";
145
- if (filePath.includes(".policy.") || /\/policies?\//.test(filePath)) return "policy";
146
- if (filePath.includes(".feature.") || /\/features?\//.test(filePath)) return "feature";
147
- if (filePath.includes(".type.") || /\/types?\//.test(filePath)) return "type";
148
- if (filePath.includes(".example.") || /\/examples?\//.test(filePath)) return "example";
149
- if (filePath.includes(".app-config.")) return "app-config";
150
- if (filePath.includes(".workflow.") || /\/workflows?\//.test(filePath)) return "workflow";
151
- if (filePath.includes(".integration.") || /\/integrations?\//.test(filePath)) return "integration";
152
- return "unknown";
153
- }
154
-
155
- //#endregion
156
- export { inferSpecTypeFromCodeBlock, inferSpecTypeFromFilePath, scanAllSpecsFromSource, scanSpecSource };
157
- //# sourceMappingURL=spec-scan.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"spec-scan.js","names":[],"sources":["../../src/analysis/spec-scan.ts"],"sourcesContent":["/**\n * Spec scanning utilities.\n *\n * Scans source code to extract spec definitions and metadata without execution.\n */\n\nimport type {\n AnalyzedOperationKind,\n AnalyzedSpecType,\n SpecScanResult,\n} from '../types/analysis-types';\nimport {\n extractArrayConstants,\n resolveVariablesInBlock,\n} from './utils/variables';\n\nimport {\n findMatchingDelimiter,\n isStability,\n matchStringArrayField,\n matchStringField,\n matchVersionField,\n} from './utils/matchers';\n\nimport {\n extractRefList,\n extractTestCoverage,\n extractTestRefs,\n extractTestTarget,\n parsePolicy,\n} from './spec-parsing-utils';\n\nexport { extractTestTarget, extractTestCoverage } from './spec-parsing-utils';\n\n/**\n * Scan all specs from a single source file.\n */\nexport function scanAllSpecsFromSource(\n code: string,\n filePath: string\n): SpecScanResult[] {\n const results: SpecScanResult[] = [];\n\n // Pre-scan for variables available in file scope\n const variables = extractArrayConstants(code);\n\n // Match export definitions: export const X = defineXXX calls\n const definitionRegex =\n /export\\s+const\\s+(\\w+)\\s*=\\s*define(Command|Query|Event|Presentation|Capability|Policy|Type|Example|AppConfig|Integration|Workflow|TestSpec|Feature)\\s*\\(/g;\n let match;\n\n while ((match = definitionRegex.exec(code)) !== null) {\n const start = match.index;\n const openParenIndex = start + match[0].length - 1;\n const end = findMatchingDelimiter(code, openParenIndex, '(', ')');\n if (end === -1) continue;\n\n // Optional: include trailing semicolon\n let finalEnd = end;\n if (code[finalEnd + 1] === ';') {\n finalEnd++;\n }\n\n const block = code.substring(start, finalEnd + 1);\n\n // Resolve variables in the block\n const resolvedBlock = resolveVariablesInBlock(block, variables);\n\n const result = scanSpecSource(resolvedBlock, filePath);\n if (result) {\n results.push({\n ...result,\n sourceBlock: resolvedBlock, // Ensure the result has the resolved block\n });\n }\n }\n\n // Fallback: legacy file scan if no explicit exports found\n if (results.length === 0 && filePath.includes('.spec.')) {\n const result = scanSpecSource(code, filePath);\n if (result.key !== 'unknown') {\n // Try to resolve globally even for fallback (though scope is harder)\n const resolvedBlock = resolveVariablesInBlock(code, variables);\n const result = scanSpecSource(resolvedBlock, filePath);\n results.push(result);\n }\n }\n\n return results;\n}\n\nexport function inferSpecTypeFromCodeBlock(fileSourceCode: string): {\n specType: AnalyzedSpecType;\n kind: AnalyzedOperationKind;\n} {\n if (fileSourceCode.includes('defineCommand')) {\n return {\n specType: 'operation',\n kind: 'command',\n };\n }\n if (fileSourceCode.includes('defineQuery')) {\n return {\n specType: 'operation',\n kind: 'query',\n };\n }\n if (fileSourceCode.includes('defineEvent')) {\n return {\n specType: 'event',\n kind: 'event',\n };\n }\n if (fileSourceCode.includes('definePresentation')) {\n return {\n specType: 'presentation',\n kind: 'presentation',\n };\n }\n if (fileSourceCode.includes('definePolicy')) {\n return {\n specType: 'policy',\n kind: 'policy',\n };\n }\n if (fileSourceCode.includes('defineCapability')) {\n return {\n specType: 'capability',\n kind: 'capability',\n };\n }\n if (fileSourceCode.includes('defineExample')) {\n return {\n specType: 'example',\n kind: 'example',\n };\n }\n if (\n fileSourceCode.includes('defineAppConfig') &&\n !fileSourceCode.includes('export const defineAppConfig')\n ) {\n return {\n specType: 'app-config',\n kind: 'app-config',\n };\n }\n if (fileSourceCode.includes('defineIntegration')) {\n return {\n specType: 'integration',\n kind: 'integration',\n };\n }\n if (fileSourceCode.includes('defineWorkflow')) {\n return {\n specType: 'workflow',\n kind: 'workflow',\n };\n }\n if (fileSourceCode.includes('defineTestSpec')) {\n return {\n specType: 'test-spec',\n kind: 'test-spec',\n };\n }\n\n if (fileSourceCode.includes('defineFeature')) {\n return {\n specType: 'feature',\n kind: 'feature',\n };\n }\n\n return {\n specType: 'unknown',\n kind: 'unknown',\n };\n}\n\n/**\n * Scan a single spec source string.\n */\nexport function scanSpecSource(code: string, filePath: string): SpecScanResult {\n const keyMatch =\n code.match(/key\\s*:\\s*['\"]([^'\"]+)['\"]/) ??\n code.match(/export\\s+const\\s+(\\w+)\\s*=/);\n const key = keyMatch?.[1] ?? 'unknown';\n\n const version = matchVersionField(code, 'version');\n const description = matchStringField(code, 'description') ?? undefined;\n const goal = matchStringField(code, 'goal') ?? undefined;\n const context = matchStringField(code, 'context') ?? undefined;\n const stabilityRaw = matchStringField(code, 'stability');\n const stability = isStability(stabilityRaw) ? stabilityRaw : undefined;\n const owners = matchStringArrayField(code, 'owners');\n const tags = matchStringArrayField(code, 'tags');\n\n // Determine type\n const inferredSpecType = inferSpecTypeFromCodeBlock(code);\n\n // Check feature flags/sections\n const hasMeta = /meta\\s*:\\s*\\{/.test(code);\n const hasIo = /io\\s*:\\s*\\{/.test(code);\n const hasPolicy = /policy\\s*:\\s*\\{/.test(code);\n const hasPayload = /payload\\s*:\\s*\\{/.test(code);\n const hasContent = /content\\s*:\\s*\\{/.test(code);\n const hasDefinition = /definition\\s*:\\s*\\{/.test(code);\n\n // References\n const emittedEvents =\n extractRefList(code, 'emits') ?? extractRefList(code, 'emittedEvents');\n const testRefs = extractTestRefs(code);\n\n const policyRefs = hasPolicy ? parsePolicy(code) : undefined;\n\n return {\n filePath,\n key,\n version,\n specType: inferredSpecType.specType,\n kind: inferredSpecType.kind,\n description,\n goal,\n context,\n stability,\n owners,\n tags,\n hasMeta,\n hasIo,\n hasPolicy,\n hasPayload,\n hasContent,\n hasDefinition,\n emittedEvents,\n policyRefs,\n testRefs,\n testTarget: extractTestTarget(code),\n testCoverage: extractTestCoverage(code),\n sourceBlock: code,\n };\n}\n\n/**\n * Infer spec type from file path convention.\n */\nexport function inferSpecTypeFromFilePath(\n filePath: string\n): SpecScanResult['specType'] | 'feature' | 'unknown' {\n if (filePath.includes('.contracts.') || /\\/operations?\\//.test(filePath)) {\n return 'operation';\n }\n if (filePath.includes('.event.') || /\\/events?\\//.test(filePath)) {\n return 'event';\n }\n if (\n filePath.includes('.presentation.') ||\n /\\/presentations?\\//.test(filePath)\n ) {\n return 'presentation';\n }\n if (filePath.includes('.policy.') || /\\/policies?\\//.test(filePath)) {\n return 'policy';\n }\n if (filePath.includes('.feature.') || /\\/features?\\//.test(filePath)) {\n return 'feature';\n }\n if (filePath.includes('.type.') || /\\/types?\\//.test(filePath)) {\n return 'type';\n }\n if (filePath.includes('.example.') || /\\/examples?\\//.test(filePath)) {\n return 'example';\n }\n if (filePath.includes('.app-config.')) {\n return 'app-config';\n }\n if (filePath.includes('.workflow.') || /\\/workflows?\\//.test(filePath)) {\n return 'workflow';\n }\n if (\n filePath.includes('.integration.') ||\n /\\/integrations?\\//.test(filePath)\n ) {\n return 'integration';\n }\n return 'unknown';\n}\n"],"mappings":"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"}
@@ -1,77 +0,0 @@
1
- //#region src/analysis/utils/matchers.ts
2
- /**
3
- * Escape regex special characters.
4
- */
5
- function escapeRegex(value) {
6
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7
- }
8
- /**
9
- * Match a string field in source code.
10
- */
11
- function matchStringField(code, field) {
12
- const regex = new RegExp(`${escapeRegex(field)}\\s*:\\s*['"]([^'"]+)['"]`);
13
- return code.match(regex)?.[1] ?? null;
14
- }
15
- /**
16
- * Match a string field within a limited scope.
17
- */
18
- function matchStringFieldIn(code, field) {
19
- return matchStringField(code, field);
20
- }
21
- /**
22
- * Match a version field which can be a string or number.
23
- */
24
- function matchVersionField(code, field) {
25
- const regex = new RegExp(`${escapeRegex(field)}\\s*:\\s*(?:['"]([^'"]+)['"]|(\\d+(?:\\.\\d+)*))`);
26
- const match = code.match(regex);
27
- if (match?.[1]) return match[1];
28
- if (match?.[2]) return match[2];
29
- }
30
- /**
31
- * Match a string array field in source code.
32
- */
33
- function matchStringArrayField(code, field) {
34
- const regex = new RegExp(`${escapeRegex(field)}\\s*:\\s*\\[([\\s\\S]*?)\\]`);
35
- const match = code.match(regex);
36
- if (!match?.[1]) return void 0;
37
- const inner = match[1];
38
- const items = Array.from(inner.matchAll(/['"]([^'"]+)['"]/g)).map((m) => m[1]).filter((value) => typeof value === "string" && value.length > 0);
39
- return items.length > 0 ? items : void 0;
40
- }
41
- /**
42
- * Check if a value is a valid stability.
43
- */
44
- function isStability(value) {
45
- return value === "experimental" || value === "beta" || value === "stable" || value === "deprecated";
46
- }
47
- /**
48
- * Find matching closing delimiter for an opening delimiter.
49
- * Returns the index of the closing delimiter or -1 if not found.
50
- */
51
- function findMatchingDelimiter(code, startIndex, openChar, closeChar) {
52
- let depth = 0;
53
- let inString = false;
54
- let stringChar = "";
55
- for (let i = startIndex; i < code.length; i++) {
56
- const char = code[i];
57
- const prevChar = i > 0 ? code[i - 1] : "";
58
- if ((char === "\"" || char === "'" || char === "`") && prevChar !== "\\") {
59
- if (!inString) {
60
- inString = true;
61
- stringChar = char;
62
- } else if (char === stringChar) inString = false;
63
- continue;
64
- }
65
- if (inString) continue;
66
- if (char === openChar) depth++;
67
- else if (char === closeChar) {
68
- depth--;
69
- if (depth === 0) return i;
70
- }
71
- }
72
- return -1;
73
- }
74
-
75
- //#endregion
76
- export { escapeRegex, findMatchingDelimiter, isStability, matchStringArrayField, matchStringField, matchStringFieldIn, matchVersionField };
77
- //# sourceMappingURL=matchers.js.map