@contractspec/module.workspace 1.56.1 → 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 -12
  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 -14
  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 -16
  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 -7
  26. package/dist/analysis/diff/semantic.d.ts.map +1 -1
  27. package/dist/analysis/example-scan.d.ts +3 -8
  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 -8
  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 -42
  38. package/dist/analysis/grouping.d.ts.map +1 -1
  39. package/dist/analysis/impact/classifier.d.ts +9 -9
  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 -15
  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 -9
  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 -57
  60. package/dist/analysis/snapshot/types.d.ts.map +1 -1
  61. package/dist/analysis/spec-parser.d.ts +8 -7
  62. package/dist/analysis/spec-parser.d.ts.map +1 -1
  63. package/dist/analysis/spec-parsing-utils.d.ts +20 -11
  64. package/dist/analysis/spec-parsing-utils.d.ts.map +1 -1
  65. package/dist/analysis/spec-scan.d.ts +13 -13
  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 -15
  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 -28
  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 -12
  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 -9
  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 -7
  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 -7
  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 -7
  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 -7
  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 -137
  156. package/dist/types/analysis-types.d.ts.map +1 -1
  157. package/dist/types/generation-types.d.ts +36 -38
  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 -97
  162. package/dist/types/llm-types.d.ts.map +1 -1
  163. package/dist/types/rulesync-types.d.ts +17 -19
  164. package/dist/types/rulesync-types.d.ts.map +1 -1
  165. package/dist/types/spec-types.d.ts +329 -330
  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 -105
  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 -69
  234. package/dist/templates/knowledge.js.map +0 -1
  235. package/dist/templates/migration.js +0 -61
  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 +0,0 @@
1
- {"version":3,"file":"deep-diff.js","names":[],"sources":["../../../src/analysis/diff/deep-diff.ts"],"sourcesContent":["/**\n * Deep diff engine for IO schema comparison.\n *\n * Compares input/output schemas field-by-field to detect\n * breaking and non-breaking changes.\n */\n\nimport type { FieldSnapshot, IoSnapshot } from '../snapshot/types';\nimport type { SemanticDiffItem } from '../../types/analysis-types';\n\n/**\n * Deep diff options.\n */\nexport interface DeepDiffOptions {\n /** Only report breaking changes */\n breakingOnly?: boolean;\n /** Path prefix for nested diffs */\n pathPrefix?: string;\n}\n\n/**\n * Compute deep differences between two IO schemas.\n */\nexport function computeIoDiff(\n base: IoSnapshot,\n head: IoSnapshot,\n options: DeepDiffOptions = {}\n): SemanticDiffItem[] {\n const diffs: SemanticDiffItem[] = [];\n\n // Compare input schemas\n diffs.push(...computeFieldsDiff(base.input, head.input, 'io.input', options));\n\n // Compare output schemas\n diffs.push(\n ...computeFieldsDiff(base.output, head.output, 'io.output', options)\n );\n\n return options.breakingOnly\n ? diffs.filter((d) => d.type === 'breaking')\n : diffs;\n}\n\n/**\n * Compute differences between two field maps.\n */\nexport function computeFieldsDiff(\n baseFields: Record<string, FieldSnapshot>,\n headFields: Record<string, FieldSnapshot>,\n pathPrefix: string,\n options: DeepDiffOptions = {}\n): SemanticDiffItem[] {\n const diffs: SemanticDiffItem[] = [];\n const baseNames = new Set(Object.keys(baseFields));\n const headNames = new Set(Object.keys(headFields));\n\n // Check for removed fields\n for (const name of baseNames) {\n if (!headNames.has(name)) {\n const baseField = baseFields[name];\n diffs.push({\n type: 'breaking',\n path: `${pathPrefix}.${name}`,\n oldValue: baseField,\n newValue: undefined,\n description: `Field '${name}' was removed`,\n });\n }\n }\n\n // Check for added fields\n for (const name of headNames) {\n if (!baseNames.has(name)) {\n const headField = headFields[name];\n const isBreaking = headField?.required === true;\n diffs.push({\n type: isBreaking ? 'breaking' : 'added',\n path: `${pathPrefix}.${name}`,\n oldValue: undefined,\n newValue: headField,\n description: isBreaking\n ? `Required field '${name}' was added`\n : `Optional field '${name}' was added`,\n });\n }\n }\n\n // Check for changed fields\n for (const name of baseNames) {\n if (headNames.has(name)) {\n const baseField = baseFields[name];\n const headField = headFields[name];\n if (baseField && headField) {\n diffs.push(\n ...computeFieldDiff(\n baseField,\n headField,\n `${pathPrefix}.${name}`,\n options\n )\n );\n }\n }\n }\n\n return diffs;\n}\n\n/**\n * Compute differences between two field definitions.\n */\nexport function computeFieldDiff(\n base: FieldSnapshot,\n head: FieldSnapshot,\n path: string,\n _options: DeepDiffOptions = {}\n): SemanticDiffItem[] {\n const diffs: SemanticDiffItem[] = [];\n\n // Type change is always breaking\n if (base.type !== head.type) {\n diffs.push({\n type: 'breaking',\n path: `${path}.type`,\n oldValue: base.type,\n newValue: head.type,\n description: `Field type changed from '${base.type}' to '${head.type}'`,\n });\n }\n\n // Required change\n if (base.required !== head.required) {\n const isBreaking = !base.required && head.required; // Optional -> Required is breaking\n diffs.push({\n type: isBreaking ? 'breaking' : 'changed',\n path: `${path}.required`,\n oldValue: base.required,\n newValue: head.required,\n description: isBreaking\n ? `Field '${base.name}' changed from optional to required`\n : `Field '${base.name}' changed from required to optional`,\n });\n }\n\n // Nullable change\n if (base.nullable !== head.nullable) {\n const isBreaking = base.nullable && !head.nullable; // Nullable -> Non-nullable is breaking\n diffs.push({\n type: isBreaking ? 'breaking' : 'changed',\n path: `${path}.nullable`,\n oldValue: base.nullable,\n newValue: head.nullable,\n description: isBreaking\n ? `Field '${base.name}' is no longer nullable`\n : `Field '${base.name}' is now nullable`,\n });\n }\n\n // Enum values change\n if (base.type === 'enum' && head.type === 'enum') {\n const baseValues = new Set(base.enumValues ?? []);\n const headValues = new Set(head.enumValues ?? []);\n\n // Removed enum values are breaking\n for (const value of baseValues) {\n if (!headValues.has(value)) {\n diffs.push({\n type: 'breaking',\n path: `${path}.enumValues`,\n oldValue: base.enumValues,\n newValue: head.enumValues,\n description: `Enum value '${value}' was removed`,\n });\n }\n }\n\n // Added enum values are non-breaking\n for (const value of headValues) {\n if (!baseValues.has(value)) {\n diffs.push({\n type: 'added',\n path: `${path}.enumValues`,\n oldValue: base.enumValues,\n newValue: head.enumValues,\n description: `Enum value '${value}' was added`,\n });\n }\n }\n }\n\n // Nested object fields\n if (\n base.type === 'object' &&\n head.type === 'object' &&\n base.properties &&\n head.properties\n ) {\n diffs.push(\n ...computeFieldsDiff(base.properties, head.properties, path, _options)\n );\n }\n\n // Array items\n if (\n base.type === 'array' &&\n head.type === 'array' &&\n base.items &&\n head.items\n ) {\n diffs.push(\n ...computeFieldDiff(base.items, head.items, `${path}.items`, _options)\n );\n }\n\n return diffs;\n}\n\n/**\n * Classify a diff as breaking based on context.\n */\nexport function isBreakingChange(\n diff: SemanticDiffItem,\n context: 'input' | 'output'\n): boolean {\n // In output context, removing/changing fields is always breaking\n if (context === 'output') {\n return diff.type === 'breaking' || diff.type === 'removed';\n }\n\n // In input context, adding required fields is breaking\n if (context === 'input') {\n if (diff.type === 'added' && diff.description?.includes('Required field')) {\n return true;\n }\n return diff.type === 'breaking';\n }\n\n return diff.type === 'breaking';\n}\n"],"mappings":"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"}
@@ -1,97 +0,0 @@
1
- import { scanSpecSource } from "../spec-scan.js";
2
-
3
- //#region src/analysis/diff/semantic.ts
4
- /**
5
- * Compute semantic differences between two spec sources.
6
- */
7
- function computeSemanticDiff(aCode, aPath, bCode, bPath, options = {}) {
8
- const a = scanSpecSource(aCode, aPath);
9
- const b = scanSpecSource(bCode, bPath);
10
- const diffs = [];
11
- compareScalar(diffs, "specType", a.specType, b.specType, {
12
- breaking: true,
13
- label: "Spec type"
14
- });
15
- compareScalar(diffs, "key", a.key, b.key, {
16
- breaking: true,
17
- label: "Key"
18
- });
19
- compareScalar(diffs, "version", a.version, b.version, {
20
- breaking: true,
21
- label: "Version"
22
- });
23
- compareScalar(diffs, "kind", a.kind, b.kind, {
24
- breaking: true,
25
- label: "Kind"
26
- });
27
- compareScalar(diffs, "stability", a.stability, b.stability, {
28
- breaking: isStabilityDowngrade(a, b),
29
- label: "Stability"
30
- });
31
- compareArray(diffs, "owners", a.owners ?? [], b.owners ?? [], { label: "Owners" });
32
- compareArray(diffs, "tags", a.tags ?? [], b.tags ?? [], { label: "Tags" });
33
- compareStructuralHints(diffs, a, b);
34
- return options.breakingOnly ? diffs.filter((d) => d.type === "breaking") : diffs;
35
- }
36
- function compareScalar(diffs, path, a, b, config) {
37
- if (a === b) return;
38
- diffs.push({
39
- type: config.breaking ? "breaking" : "changed",
40
- path,
41
- oldValue: a,
42
- newValue: b,
43
- description: `${config.label} changed`
44
- });
45
- }
46
- function compareArray(diffs, path, a, b, config) {
47
- const aSorted = [...a].sort();
48
- const bSorted = [...b].sort();
49
- if (JSON.stringify(aSorted) === JSON.stringify(bSorted)) return;
50
- diffs.push({
51
- type: "changed",
52
- path,
53
- oldValue: aSorted,
54
- newValue: bSorted,
55
- description: `${config.label} changed`
56
- });
57
- }
58
- function isStabilityDowngrade(a, b) {
59
- const order = {
60
- experimental: 0,
61
- beta: 1,
62
- stable: 2,
63
- deprecated: 3
64
- };
65
- const aValue = a.stability ? order[a.stability] ?? 0 : 0;
66
- return (b.stability ? order[b.stability] ?? 0 : 0) > aValue;
67
- }
68
- function compareStructuralHints(diffs, a, b) {
69
- compareScalar(diffs, "hasMeta", a.hasMeta, b.hasMeta, {
70
- breaking: a.specType === "operation" || b.specType === "operation",
71
- label: "meta section presence"
72
- });
73
- compareScalar(diffs, "hasIo", a.hasIo, b.hasIo, {
74
- breaking: a.specType === "operation" || b.specType === "operation",
75
- label: "io section presence"
76
- });
77
- compareScalar(diffs, "hasPolicy", a.hasPolicy, b.hasPolicy, {
78
- breaking: a.specType === "operation" || b.specType === "operation",
79
- label: "policy section presence"
80
- });
81
- compareScalar(diffs, "hasPayload", a.hasPayload, b.hasPayload, {
82
- breaking: a.specType === "event" || b.specType === "event",
83
- label: "payload section presence"
84
- });
85
- compareScalar(diffs, "hasContent", a.hasContent, b.hasContent, {
86
- breaking: a.specType === "presentation" || b.specType === "presentation",
87
- label: "content section presence"
88
- });
89
- compareScalar(diffs, "hasDefinition", a.hasDefinition, b.hasDefinition, {
90
- breaking: a.specType === "workflow" || b.specType === "workflow",
91
- label: "definition section presence"
92
- });
93
- }
94
-
95
- //#endregion
96
- export { computeSemanticDiff };
97
- //# sourceMappingURL=semantic.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"semantic.js","names":[],"sources":["../../../src/analysis/diff/semantic.ts"],"sourcesContent":["/**\n * Semantic diff computation for contract specs.\n * Extracted from cli-contractspec/src/commands/diff/semantic.ts\n */\n\nimport type {\n SemanticDiffItem,\n SemanticDiffOptions,\n SpecScanResult,\n} from '../../types/analysis-types';\nimport { scanSpecSource } from '../spec-scan';\n\n/**\n * Compute semantic differences between two spec sources.\n */\nexport function computeSemanticDiff(\n aCode: string,\n aPath: string,\n bCode: string,\n bPath: string,\n options: SemanticDiffOptions = {}\n): SemanticDiffItem[] {\n const a = scanSpecSource(aCode, aPath);\n const b = scanSpecSource(bCode, bPath);\n\n const diffs: SemanticDiffItem[] = [];\n\n compareScalar(diffs, 'specType', a.specType, b.specType, {\n breaking: true,\n label: 'Spec type',\n });\n\n compareScalar(diffs, 'key', a.key, b.key, {\n breaking: true,\n label: 'Key',\n });\n compareScalar(diffs, 'version', a.version, b.version, {\n breaking: true,\n label: 'Version',\n });\n compareScalar(diffs, 'kind', a.kind, b.kind, {\n breaking: true,\n label: 'Kind',\n });\n\n compareScalar(diffs, 'stability', a.stability, b.stability, {\n breaking: isStabilityDowngrade(a, b),\n label: 'Stability',\n });\n\n compareArray(diffs, 'owners', a.owners ?? [], b.owners ?? [], {\n label: 'Owners',\n });\n compareArray(diffs, 'tags', a.tags ?? [], b.tags ?? [], { label: 'Tags' });\n\n compareStructuralHints(diffs, a, b);\n\n const filtered = options.breakingOnly\n ? diffs.filter((d) => d.type === 'breaking')\n : diffs;\n\n return filtered;\n}\n\nfunction compareScalar(\n diffs: SemanticDiffItem[],\n path: string,\n a: unknown,\n b: unknown,\n config: { breaking: boolean; label: string }\n) {\n if (a === b) return;\n diffs.push({\n type: config.breaking ? 'breaking' : 'changed',\n path,\n oldValue: a,\n newValue: b,\n description: `${config.label} changed`,\n });\n}\n\nfunction compareArray(\n diffs: SemanticDiffItem[],\n path: string,\n a: string[],\n b: string[],\n config: { label: string }\n) {\n const aSorted = [...a].sort();\n const bSorted = [...b].sort();\n if (JSON.stringify(aSorted) === JSON.stringify(bSorted)) return;\n\n diffs.push({\n type: 'changed',\n path,\n oldValue: aSorted,\n newValue: bSorted,\n description: `${config.label} changed`,\n });\n}\n\nfunction isStabilityDowngrade(a: SpecScanResult, b: SpecScanResult): boolean {\n const order: Record<string, number> = {\n experimental: 0,\n beta: 1,\n stable: 2,\n deprecated: 3,\n };\n const aValue = a.stability ? (order[a.stability] ?? 0) : 0;\n const bValue = b.stability ? (order[b.stability] ?? 0) : 0;\n // Moving toward deprecated is effectively a breaking signal for consumers.\n return bValue > aValue;\n}\n\nfunction compareStructuralHints(\n diffs: SemanticDiffItem[],\n a: SpecScanResult,\n b: SpecScanResult\n) {\n // For operations these sections are usually required; missing them is breaking.\n compareScalar(diffs, 'hasMeta', a.hasMeta, b.hasMeta, {\n breaking: a.specType === 'operation' || b.specType === 'operation',\n label: 'meta section presence',\n });\n compareScalar(diffs, 'hasIo', a.hasIo, b.hasIo, {\n breaking: a.specType === 'operation' || b.specType === 'operation',\n label: 'io section presence',\n });\n compareScalar(diffs, 'hasPolicy', a.hasPolicy, b.hasPolicy, {\n breaking: a.specType === 'operation' || b.specType === 'operation',\n label: 'policy section presence',\n });\n compareScalar(diffs, 'hasPayload', a.hasPayload, b.hasPayload, {\n breaking: a.specType === 'event' || b.specType === 'event',\n label: 'payload section presence',\n });\n compareScalar(diffs, 'hasContent', a.hasContent, b.hasContent, {\n breaking: a.specType === 'presentation' || b.specType === 'presentation',\n label: 'content section presence',\n });\n compareScalar(diffs, 'hasDefinition', a.hasDefinition, b.hasDefinition, {\n breaking: a.specType === 'workflow' || b.specType === 'workflow',\n label: 'definition section presence',\n });\n}\n"],"mappings":";;;;;;AAeA,SAAgB,oBACd,OACA,OACA,OACA,OACA,UAA+B,EAAE,EACb;CACpB,MAAM,IAAI,eAAe,OAAO,MAAM;CACtC,MAAM,IAAI,eAAe,OAAO,MAAM;CAEtC,MAAM,QAA4B,EAAE;AAEpC,eAAc,OAAO,YAAY,EAAE,UAAU,EAAE,UAAU;EACvD,UAAU;EACV,OAAO;EACR,CAAC;AAEF,eAAc,OAAO,OAAO,EAAE,KAAK,EAAE,KAAK;EACxC,UAAU;EACV,OAAO;EACR,CAAC;AACF,eAAc,OAAO,WAAW,EAAE,SAAS,EAAE,SAAS;EACpD,UAAU;EACV,OAAO;EACR,CAAC;AACF,eAAc,OAAO,QAAQ,EAAE,MAAM,EAAE,MAAM;EAC3C,UAAU;EACV,OAAO;EACR,CAAC;AAEF,eAAc,OAAO,aAAa,EAAE,WAAW,EAAE,WAAW;EAC1D,UAAU,qBAAqB,GAAG,EAAE;EACpC,OAAO;EACR,CAAC;AAEF,cAAa,OAAO,UAAU,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAC5D,OAAO,UACR,CAAC;AACF,cAAa,OAAO,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,QAAQ,CAAC;AAE1E,wBAAuB,OAAO,GAAG,EAAE;AAMnC,QAJiB,QAAQ,eACrB,MAAM,QAAQ,MAAM,EAAE,SAAS,WAAW,GAC1C;;AAKN,SAAS,cACP,OACA,MACA,GACA,GACA,QACA;AACA,KAAI,MAAM,EAAG;AACb,OAAM,KAAK;EACT,MAAM,OAAO,WAAW,aAAa;EACrC;EACA,UAAU;EACV,UAAU;EACV,aAAa,GAAG,OAAO,MAAM;EAC9B,CAAC;;AAGJ,SAAS,aACP,OACA,MACA,GACA,GACA,QACA;CACA,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM;CAC7B,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM;AAC7B,KAAI,KAAK,UAAU,QAAQ,KAAK,KAAK,UAAU,QAAQ,CAAE;AAEzD,OAAM,KAAK;EACT,MAAM;EACN;EACA,UAAU;EACV,UAAU;EACV,aAAa,GAAG,OAAO,MAAM;EAC9B,CAAC;;AAGJ,SAAS,qBAAqB,GAAmB,GAA4B;CAC3E,MAAM,QAAgC;EACpC,cAAc;EACd,MAAM;EACN,QAAQ;EACR,YAAY;EACb;CACD,MAAM,SAAS,EAAE,YAAa,MAAM,EAAE,cAAc,IAAK;AAGzD,SAFe,EAAE,YAAa,MAAM,EAAE,cAAc,IAAK,KAEzC;;AAGlB,SAAS,uBACP,OACA,GACA,GACA;AAEA,eAAc,OAAO,WAAW,EAAE,SAAS,EAAE,SAAS;EACpD,UAAU,EAAE,aAAa,eAAe,EAAE,aAAa;EACvD,OAAO;EACR,CAAC;AACF,eAAc,OAAO,SAAS,EAAE,OAAO,EAAE,OAAO;EAC9C,UAAU,EAAE,aAAa,eAAe,EAAE,aAAa;EACvD,OAAO;EACR,CAAC;AACF,eAAc,OAAO,aAAa,EAAE,WAAW,EAAE,WAAW;EAC1D,UAAU,EAAE,aAAa,eAAe,EAAE,aAAa;EACvD,OAAO;EACR,CAAC;AACF,eAAc,OAAO,cAAc,EAAE,YAAY,EAAE,YAAY;EAC7D,UAAU,EAAE,aAAa,WAAW,EAAE,aAAa;EACnD,OAAO;EACR,CAAC;AACF,eAAc,OAAO,cAAc,EAAE,YAAY,EAAE,YAAY;EAC7D,UAAU,EAAE,aAAa,kBAAkB,EAAE,aAAa;EAC1D,OAAO;EACR,CAAC;AACF,eAAc,OAAO,iBAAiB,EAAE,eAAe,EAAE,eAAe;EACtE,UAAU,EAAE,aAAa,cAAc,EAAE,aAAa;EACtD,OAAO;EACR,CAAC"}
@@ -1,116 +0,0 @@
1
- import { isStability, matchStringArrayField, matchStringField, matchStringFieldIn } from "./utils/matchers.js";
2
-
3
- //#region src/analysis/example-scan.ts
4
- /**
5
- * Check if a file is an example file based on naming conventions.
6
- */
7
- function isExampleFile(filePath) {
8
- return filePath.includes("/example.") || filePath.endsWith(".example.ts");
9
- }
10
- /**
11
- * Scan an example source file to extract metadata.
12
- */
13
- function scanExampleSource(code, filePath) {
14
- const key = matchStringField(code, "key") ?? extractKeyFromFilePath(filePath);
15
- const version = matchStringField(code, "version") ?? void 0;
16
- const title = matchStringField(code, "title") ?? void 0;
17
- const description = matchStringField(code, "description") ?? void 0;
18
- const summary = matchStringField(code, "summary") ?? void 0;
19
- const kind = matchStringField(code, "kind") ?? void 0;
20
- const visibility = matchStringField(code, "visibility") ?? void 0;
21
- const domain = matchStringField(code, "domain") ?? void 0;
22
- const stabilityRaw = matchStringField(code, "stability");
23
- return {
24
- filePath,
25
- key,
26
- version,
27
- title,
28
- description,
29
- summary,
30
- kind,
31
- visibility,
32
- domain,
33
- stability: isStability(stabilityRaw) ? stabilityRaw : void 0,
34
- owners: matchStringArrayField(code, "owners"),
35
- tags: matchStringArrayField(code, "tags"),
36
- docs: extractDocs(code),
37
- surfaces: extractSurfaces(code),
38
- entrypoints: extractEntrypoints(code)
39
- };
40
- }
41
- /**
42
- * Extract docs section from source code.
43
- */
44
- function extractDocs(code) {
45
- const docsMatch = code.match(/docs\s*:\s*\{([\s\S]*?)\}/);
46
- if (!docsMatch?.[1]) return void 0;
47
- const docsContent = docsMatch[1];
48
- return {
49
- rootDocId: matchStringFieldIn(docsContent, "rootDocId") ?? void 0,
50
- goalDocId: matchStringFieldIn(docsContent, "goalDocId") ?? void 0,
51
- usageDocId: matchStringFieldIn(docsContent, "usageDocId") ?? void 0
52
- };
53
- }
54
- /**
55
- * Extract surfaces section from source code.
56
- */
57
- function extractSurfaces(code) {
58
- const surfaces = {
59
- templates: false,
60
- sandbox: {
61
- enabled: false,
62
- modes: []
63
- },
64
- studio: {
65
- enabled: false,
66
- installable: false
67
- },
68
- mcp: { enabled: false }
69
- };
70
- surfaces.templates = /surfaces\s*:\s*\{[\s\S]*?templates\s*:\s*true/.test(code);
71
- const sandboxMatch = code.match(/sandbox\s*:\s*\{\s*enabled\s*:\s*(true|false)\s*,\s*modes\s*:\s*\[([^\]]*)\]/);
72
- if (sandboxMatch) {
73
- surfaces.sandbox.enabled = sandboxMatch[1] === "true";
74
- if (sandboxMatch[2]) surfaces.sandbox.modes = Array.from(sandboxMatch[2].matchAll(/['"]([^'"]+)['"]/g)).map((m) => m[1]).filter((v) => typeof v === "string");
75
- }
76
- const studioMatch = code.match(/studio\s*:\s*\{\s*enabled\s*:\s*(true|false)\s*,\s*installable\s*:\s*(true|false)/);
77
- if (studioMatch) {
78
- surfaces.studio.enabled = studioMatch[1] === "true";
79
- surfaces.studio.installable = studioMatch[2] === "true";
80
- }
81
- const mcpMatch = code.match(/mcp\s*:\s*\{\s*enabled\s*:\s*(true|false)/);
82
- if (mcpMatch) surfaces.mcp.enabled = mcpMatch[1] === "true";
83
- return surfaces;
84
- }
85
- /**
86
- * Extract entrypoints section from source code.
87
- */
88
- function extractEntrypoints(code) {
89
- const entrypoints = { packageName: "" };
90
- const entrypointsMatch = code.match(/entrypoints\s*:\s*\{([\s\S]*?)\}(?=\s*[,}])/);
91
- if (!entrypointsMatch?.[1]) return entrypoints;
92
- const content = entrypointsMatch[1];
93
- entrypoints.packageName = matchStringFieldIn(content, "packageName") ?? "unknown";
94
- entrypoints.feature = matchStringFieldIn(content, "feature") ?? void 0;
95
- entrypoints.blueprint = matchStringFieldIn(content, "blueprint") ?? void 0;
96
- entrypoints.contracts = matchStringFieldIn(content, "contracts") ?? void 0;
97
- entrypoints.presentations = matchStringFieldIn(content, "presentations") ?? void 0;
98
- entrypoints.handlers = matchStringFieldIn(content, "handlers") ?? void 0;
99
- entrypoints.ui = matchStringFieldIn(content, "ui") ?? void 0;
100
- entrypoints.docs = matchStringFieldIn(content, "docs") ?? void 0;
101
- return entrypoints;
102
- }
103
- /**
104
- * Extract key from file path as fallback.
105
- */
106
- function extractKeyFromFilePath(filePath) {
107
- const parts = filePath.split("/");
108
- const examplesIndex = parts.findIndex((p) => p === "examples");
109
- const exampleName = parts[examplesIndex + 1];
110
- if (examplesIndex !== -1 && exampleName !== void 0) return exampleName;
111
- return (parts.pop() ?? filePath).replace(/\.example\.[jt]s$/, "").replace(/[^a-zA-Z0-9-]/g, "-");
112
- }
113
-
114
- //#endregion
115
- export { isExampleFile, scanExampleSource };
116
- //# sourceMappingURL=example-scan.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"example-scan.js","names":[],"sources":["../../src/analysis/example-scan.ts"],"sourcesContent":["import {\n isStability,\n matchStringArrayField,\n matchStringField,\n matchStringFieldIn,\n} from './utils/matchers';\nimport type { ExampleScanResult } from '../types/analysis-types';\n\n/**\n * Check if a file is an example file based on naming conventions.\n */\nexport function isExampleFile(filePath: string): boolean {\n return filePath.includes('/example.') || filePath.endsWith('.example.ts');\n}\n\n/**\n * Scan an example source file to extract metadata.\n */\nexport function scanExampleSource(\n code: string,\n filePath: string\n): ExampleScanResult {\n const key = matchStringField(code, 'key') ?? extractKeyFromFilePath(filePath);\n const versionRaw = matchStringField(code, 'version');\n const version = versionRaw ?? undefined;\n const title = matchStringField(code, 'title') ?? undefined;\n const description = matchStringField(code, 'description') ?? undefined;\n const summary = matchStringField(code, 'summary') ?? undefined;\n const kind = matchStringField(code, 'kind') ?? undefined;\n const visibility = matchStringField(code, 'visibility') ?? undefined;\n const domain = matchStringField(code, 'domain') ?? 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 // Extract docs\n const docs = extractDocs(code);\n\n // Extract surfaces\n const surfaces = extractSurfaces(code);\n\n // Extract entrypoints\n const entrypoints = extractEntrypoints(code);\n\n return {\n filePath,\n key,\n version,\n title,\n description,\n summary,\n kind,\n visibility,\n domain,\n stability,\n owners,\n tags,\n docs,\n surfaces,\n entrypoints,\n };\n}\n\n/**\n * Extract docs section from source code.\n */\nfunction extractDocs(code: string): ExampleScanResult['docs'] {\n const docsMatch = code.match(/docs\\s*:\\s*\\{([\\s\\S]*?)\\}/);\n if (!docsMatch?.[1]) return undefined;\n\n const docsContent = docsMatch[1];\n return {\n rootDocId: matchStringFieldIn(docsContent, 'rootDocId') ?? undefined,\n goalDocId: matchStringFieldIn(docsContent, 'goalDocId') ?? undefined,\n usageDocId: matchStringFieldIn(docsContent, 'usageDocId') ?? undefined,\n };\n}\n\n/**\n * Extract surfaces section from source code.\n */\nfunction extractSurfaces(code: string): ExampleScanResult['surfaces'] {\n const surfaces: ExampleScanResult['surfaces'] = {\n templates: false,\n sandbox: { enabled: false, modes: [] },\n studio: { enabled: false, installable: false },\n mcp: { enabled: false },\n };\n\n // Check templates directly in the surfaces section\n surfaces.templates = /surfaces\\s*:\\s*\\{[\\s\\S]*?templates\\s*:\\s*true/.test(\n code\n );\n\n // Check sandbox - look for the sandbox object and extract its content\n const sandboxMatch = code.match(\n /sandbox\\s*:\\s*\\{\\s*enabled\\s*:\\s*(true|false)\\s*,\\s*modes\\s*:\\s*\\[([^\\]]*)\\]/\n );\n if (sandboxMatch) {\n surfaces.sandbox.enabled = sandboxMatch[1] === 'true';\n if (sandboxMatch[2]) {\n surfaces.sandbox.modes = Array.from(\n sandboxMatch[2].matchAll(/['\"]([^'\"]+)['\"]/g)\n )\n .map((m) => m[1])\n .filter((v): v is string => typeof v === 'string');\n }\n }\n\n // Check studio - look for studio object\n const studioMatch = code.match(\n /studio\\s*:\\s*\\{\\s*enabled\\s*:\\s*(true|false)\\s*,\\s*installable\\s*:\\s*(true|false)/\n );\n if (studioMatch) {\n surfaces.studio.enabled = studioMatch[1] === 'true';\n surfaces.studio.installable = studioMatch[2] === 'true';\n }\n\n // Check mcp\n const mcpMatch = code.match(/mcp\\s*:\\s*\\{\\s*enabled\\s*:\\s*(true|false)/);\n if (mcpMatch) {\n surfaces.mcp.enabled = mcpMatch[1] === 'true';\n }\n\n return surfaces;\n}\n\n/**\n * Extract entrypoints section from source code.\n */\nfunction extractEntrypoints(code: string): ExampleScanResult['entrypoints'] {\n const entrypoints: ExampleScanResult['entrypoints'] = {\n packageName: '',\n };\n\n const entrypointsMatch = code.match(\n /entrypoints\\s*:\\s*\\{([\\s\\S]*?)\\}(?=\\s*[,}])/\n );\n if (!entrypointsMatch?.[1]) return entrypoints;\n\n const content = entrypointsMatch[1];\n\n entrypoints.packageName =\n matchStringFieldIn(content, 'packageName') ?? 'unknown';\n entrypoints.feature = matchStringFieldIn(content, 'feature') ?? undefined;\n entrypoints.blueprint = matchStringFieldIn(content, 'blueprint') ?? undefined;\n entrypoints.contracts = matchStringFieldIn(content, 'contracts') ?? undefined;\n entrypoints.presentations =\n matchStringFieldIn(content, 'presentations') ?? undefined;\n entrypoints.handlers = matchStringFieldIn(content, 'handlers') ?? undefined;\n entrypoints.ui = matchStringFieldIn(content, 'ui') ?? undefined;\n entrypoints.docs = matchStringFieldIn(content, 'docs') ?? undefined;\n\n return entrypoints;\n}\n\n/**\n * Extract key from file path as fallback.\n */\nfunction extractKeyFromFilePath(filePath: string): string {\n // Try to get package name from path\n const parts = filePath.split('/');\n const examplesIndex = parts.findIndex((p) => p === 'examples');\n const exampleName = parts[examplesIndex + 1];\n if (examplesIndex !== -1 && exampleName !== undefined) {\n return exampleName;\n }\n // Fallback to filename\n const fileName = parts.pop() ?? filePath;\n return fileName\n .replace(/\\.example\\.[jt]s$/, '')\n .replace(/[^a-zA-Z0-9-]/g, '-');\n}\n"],"mappings":"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"}
@@ -1,203 +0,0 @@
1
- import { Node, Project, SyntaxKind } from "ts-morph";
2
-
3
- //#region src/analysis/feature-extractor.ts
4
- /**
5
- * Extract specs referenced in a feature.
6
- * Uses ts-morph for robust parsing of object structures.
7
- */
8
- function extractFeatureRefs(code) {
9
- const result = {
10
- operations: [],
11
- events: [],
12
- presentations: [],
13
- experiments: [],
14
- capabilities: {
15
- provides: [],
16
- requires: []
17
- },
18
- opToPresentationLinks: [],
19
- presentationsTargets: []
20
- };
21
- const sourceFile = new Project({ useInMemoryFileSystem: true }).createSourceFile("feature.ts", code);
22
- const extractRefs = (obj, propName, allowKeyOnly = false) => {
23
- const refs = [];
24
- const prop = obj.getProperty(propName);
25
- if (prop && Node.isPropertyAssignment(prop)) {
26
- const init = prop.getInitializer();
27
- if (init && Node.isArrayLiteralExpression(init)) {
28
- for (const elem of init.getElements()) if (Node.isObjectLiteralExpression(elem)) {
29
- const keyText = getTextFromProp(elem, "key");
30
- const verText = getTextFromProp(elem, "version");
31
- if (keyText && verText) refs.push({
32
- key: keyText,
33
- version: verText
34
- });
35
- else if (keyText && allowKeyOnly) refs.push({
36
- key: keyText,
37
- version: "1.0.0"
38
- });
39
- }
40
- }
41
- }
42
- return refs;
43
- };
44
- const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);
45
- for (const call of callExpressions) if ([
46
- "defineFeature",
47
- "defineAppConfig",
48
- "defineAppBlueprint"
49
- ].includes(call.getExpression().getText())) {
50
- const args = call.getArguments();
51
- if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
52
- const obj = args[0];
53
- result.operations.push(...extractRefs(obj, "operations"));
54
- result.events.push(...extractRefs(obj, "events"));
55
- result.presentations.push(...extractRefs(obj, "presentations"));
56
- result.experiments.push(...extractRefs(obj, "experiments"));
57
- const capsProp = obj.getProperty("capabilities");
58
- if (capsProp && Node.isPropertyAssignment(capsProp)) {
59
- const capsObj = capsProp.getInitializer();
60
- if (capsObj && Node.isObjectLiteralExpression(capsObj)) {
61
- result.capabilities.provides.push(...extractRefs(capsObj, "provides"));
62
- result.capabilities.requires.push(...extractRefs(capsObj, "requires", true));
63
- }
64
- }
65
- const linksProp = obj.getProperty("opToPresentation");
66
- if (linksProp && Node.isPropertyAssignment(linksProp)) {
67
- const linksArr = linksProp.getInitializer();
68
- if (linksArr && Node.isArrayLiteralExpression(linksArr)) linksArr.getElements().forEach((link) => {
69
- if (Node.isObjectLiteralExpression(link)) {
70
- const opProp = link.getProperty("op");
71
- const presProp = link.getProperty("pres");
72
- let opRef;
73
- let presRef;
74
- if (opProp && Node.isPropertyAssignment(opProp)) {
75
- const val = opProp.getInitializer();
76
- if (val && Node.isObjectLiteralExpression(val)) {
77
- const key = getTextFromProp(val, "key");
78
- const version = getTextFromProp(val, "version");
79
- if (key && version) opRef = {
80
- key,
81
- version
82
- };
83
- }
84
- }
85
- if (presProp && Node.isPropertyAssignment(presProp)) {
86
- const val = presProp.getInitializer();
87
- if (val && Node.isObjectLiteralExpression(val)) {
88
- const key = getTextFromProp(val, "key");
89
- const version = getTextFromProp(val, "version");
90
- if (key && version) presRef = {
91
- key,
92
- version
93
- };
94
- }
95
- }
96
- if (opRef && presRef) result.opToPresentationLinks.push({
97
- op: opRef,
98
- pres: presRef
99
- });
100
- }
101
- });
102
- }
103
- extractLinks(obj, result.opToPresentationLinks);
104
- const targetsProp = obj.getProperty("presentationsTargets");
105
- if (targetsProp && Node.isPropertyAssignment(targetsProp)) {
106
- const targetsArr = targetsProp.getInitializer();
107
- if (targetsArr && Node.isArrayLiteralExpression(targetsArr)) targetsArr.getElements().forEach((targetBlock) => {
108
- if (Node.isObjectLiteralExpression(targetBlock)) {
109
- const key = getTextFromProp(targetBlock, "key");
110
- const version = getTextFromProp(targetBlock, "version");
111
- const targetsList = getTargetsList(targetBlock, "targets");
112
- if (key && version && targetsList) result.presentationsTargets.push({
113
- key,
114
- version,
115
- targets: targetsList
116
- });
117
- }
118
- });
119
- }
120
- extractPresentationTargets(obj, result.presentationsTargets);
121
- }
122
- }
123
- return result;
124
- }
125
- function extractLinks(obj, opToPresentationLinks) {
126
- const interactionsProp = obj.getProperty("interactions");
127
- if (interactionsProp && Node.isPropertyAssignment(interactionsProp)) {
128
- const interactionsArr = interactionsProp.getInitializer();
129
- if (interactionsArr && Node.isArrayLiteralExpression(interactionsArr)) interactionsArr.getElements().forEach((interaction) => {
130
- if (Node.isObjectLiteralExpression(interaction)) {
131
- const triggerProp = interaction.getProperty("trigger");
132
- const triggerObj = triggerProp && Node.isPropertyAssignment(triggerProp) && triggerProp.getInitializer();
133
- const actionProp = interaction.getProperty("action");
134
- const actionObj = actionProp && Node.isPropertyAssignment(actionProp) && actionProp.getInitializer();
135
- if (triggerObj && Node.isObjectLiteralExpression(triggerObj) && actionObj && Node.isObjectLiteralExpression(actionObj)) {
136
- const triggerType = getTextFromProp(triggerObj, "type");
137
- const actionType = getTextFromProp(actionObj, "type");
138
- if (triggerType === "presentation" && actionType === "operation") {
139
- const presRef = extractNestedRef(triggerObj, "presentation");
140
- const opRef = extractNestedRef(actionObj, "operation");
141
- if (presRef && opRef) opToPresentationLinks.push({
142
- op: opRef,
143
- pres: presRef
144
- });
145
- }
146
- }
147
- }
148
- });
149
- }
150
- }
151
- function extractNestedRef(obj, propName) {
152
- const prop = obj.getProperty(propName);
153
- if (prop && Node.isPropertyAssignment(prop)) {
154
- const val = prop.getInitializer();
155
- if (val && Node.isObjectLiteralExpression(val)) {
156
- const key = getTextFromProp(val, "key");
157
- const version = getTextFromProp(val, "version");
158
- if (key && version) return {
159
- key,
160
- version
161
- };
162
- }
163
- }
164
- }
165
- function extractPresentationTargets(obj, presentationsTargets) {
166
- const presentationsProp = obj.getProperty("presentations");
167
- if (presentationsProp && Node.isPropertyAssignment(presentationsProp)) {
168
- const presentationsArr = presentationsProp.getInitializer();
169
- if (presentationsArr && Node.isArrayLiteralExpression(presentationsArr)) {
170
- for (const elem of presentationsArr.getElements()) if (Node.isObjectLiteralExpression(elem)) {
171
- const keyText = getTextFromProp(elem, "key");
172
- const verText = getTextFromProp(elem, "version");
173
- const targetsList = getTargetsList(elem, "targets");
174
- if (keyText && verText && targetsList) presentationsTargets.push({
175
- key: keyText,
176
- version: verText,
177
- targets: targetsList
178
- });
179
- }
180
- }
181
- }
182
- }
183
- function getTextFromProp(obj, propName) {
184
- const prop = obj.getProperty(propName);
185
- if (prop && Node.isPropertyAssignment(prop)) {
186
- const init = prop.getInitializer();
187
- if (init && Node.isStringLiteral(init)) return init.getLiteralText();
188
- }
189
- }
190
- function getTargetsList(obj, propName) {
191
- const prop = obj.getProperty(propName);
192
- if (prop && Node.isPropertyAssignment(prop)) {
193
- const init = prop.getInitializer();
194
- if (init && Node.isArrayLiteralExpression(init)) return init.getElements().map((e) => {
195
- if (Node.isStringLiteral(e)) return e.getLiteralText();
196
- return { target: e.getText() };
197
- });
198
- }
199
- }
200
-
201
- //#endregion
202
- export { extractFeatureRefs };
203
- //# sourceMappingURL=feature-extractor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"feature-extractor.js","names":[],"sources":["../../src/analysis/feature-extractor.ts"],"sourcesContent":["import {\n Project,\n Node,\n SyntaxKind,\n type ObjectLiteralExpression,\n} from 'ts-morph';\nimport type { RefInfo } from '../types/analysis-types';\n\n/**\n * Extract specs referenced in a feature.\n * Uses ts-morph for robust parsing of object structures.\n */\nexport function extractFeatureRefs(code: string): {\n operations: RefInfo[];\n events: RefInfo[];\n presentations: RefInfo[];\n experiments: RefInfo[];\n capabilities: { provides: RefInfo[]; requires: RefInfo[] };\n opToPresentationLinks: { op: RefInfo; pres: RefInfo }[];\n presentationsTargets: {\n key: string;\n version: string;\n targets: Record<string, unknown>[];\n }[];\n} {\n const result = {\n operations: [] as RefInfo[],\n events: [] as RefInfo[],\n presentations: [] as RefInfo[],\n experiments: [] as RefInfo[],\n capabilities: {\n provides: [] as RefInfo[],\n requires: [] as RefInfo[],\n },\n opToPresentationLinks: [] as { op: RefInfo; pres: RefInfo }[],\n presentationsTargets: [] as {\n key: string;\n version: string;\n targets: Record<string, unknown>[];\n }[],\n };\n\n const project = new Project({ useInMemoryFileSystem: true });\n const sourceFile = project.createSourceFile('feature.ts', code);\n\n // Helper to extract ref array from an object property\n const extractRefs = (\n obj: ObjectLiteralExpression,\n propName: string,\n allowKeyOnly = false\n ): RefInfo[] => {\n const refs: RefInfo[] = [];\n const prop = obj.getProperty(propName);\n\n if (prop && Node.isPropertyAssignment(prop)) {\n const init = prop.getInitializer();\n if (init && Node.isArrayLiteralExpression(init)) {\n for (const elem of init.getElements()) {\n if (Node.isObjectLiteralExpression(elem)) {\n const keyText = getTextFromProp(elem, 'key');\n const verText = getTextFromProp(elem, 'version');\n\n if (keyText && verText) {\n refs.push({ key: keyText, version: verText });\n } else if (keyText && allowKeyOnly) {\n refs.push({ key: keyText, version: '1.0.0' });\n }\n }\n }\n }\n }\n return refs;\n };\n\n // Find defineFeature call\n const callExpressions = sourceFile.getDescendantsOfKind(\n SyntaxKind.CallExpression\n );\n\n for (const call of callExpressions) {\n if (\n ['defineFeature', 'defineAppConfig', 'defineAppBlueprint'].includes(\n call.getExpression().getText()\n )\n ) {\n const args = call.getArguments();\n if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {\n const obj = args[0];\n\n // Extract direct lists\n result.operations.push(...extractRefs(obj, 'operations'));\n result.events.push(...extractRefs(obj, 'events'));\n result.presentations.push(...extractRefs(obj, 'presentations'));\n result.experiments.push(...extractRefs(obj, 'experiments'));\n\n // Capabilities\n const capsProp = obj.getProperty('capabilities');\n if (capsProp && Node.isPropertyAssignment(capsProp)) {\n const capsObj = capsProp.getInitializer();\n if (capsObj && Node.isObjectLiteralExpression(capsObj)) {\n result.capabilities.provides.push(\n ...extractRefs(capsObj, 'provides')\n );\n result.capabilities.requires.push(\n ...extractRefs(capsObj, 'requires', true)\n );\n }\n }\n\n // Op to Presentation Links\n // explicit 'opToPresentation' field\n const linksProp = obj.getProperty('opToPresentation');\n if (linksProp && Node.isPropertyAssignment(linksProp)) {\n const linksArr = linksProp.getInitializer();\n if (linksArr && Node.isArrayLiteralExpression(linksArr)) {\n linksArr.getElements().forEach((link) => {\n if (Node.isObjectLiteralExpression(link)) {\n const opProp = link.getProperty('op');\n const presProp = link.getProperty('pres');\n\n let opRef: RefInfo | undefined;\n let presRef: RefInfo | undefined;\n\n if (opProp && Node.isPropertyAssignment(opProp)) {\n const val = opProp.getInitializer();\n if (val && Node.isObjectLiteralExpression(val)) {\n const key = getTextFromProp(val, 'key');\n const version = getTextFromProp(val, 'version');\n if (key && version) opRef = { key, version };\n }\n }\n if (presProp && Node.isPropertyAssignment(presProp)) {\n const val = presProp.getInitializer();\n if (val && Node.isObjectLiteralExpression(val)) {\n const key = getTextFromProp(val, 'key');\n const version = getTextFromProp(val, 'version');\n if (key && version) presRef = { key, version };\n }\n }\n\n if (opRef && presRef) {\n result.opToPresentationLinks.push({\n op: opRef,\n pres: presRef,\n });\n }\n }\n });\n }\n }\n\n // Also support 'interactions' style for forward compatibility\n extractLinks(obj, result.opToPresentationLinks);\n\n // Presentation Targets\n // explicit 'presentationsTargets' field\n const targetsProp = obj.getProperty('presentationsTargets');\n if (targetsProp && Node.isPropertyAssignment(targetsProp)) {\n const targetsArr = targetsProp.getInitializer();\n if (targetsArr && Node.isArrayLiteralExpression(targetsArr)) {\n targetsArr.getElements().forEach((targetBlock) => {\n if (Node.isObjectLiteralExpression(targetBlock)) {\n const key = getTextFromProp(targetBlock, 'key');\n const version = getTextFromProp(targetBlock, 'version');\n const targetsList = getTargetsList(targetBlock, 'targets');\n\n if (key && version && targetsList) {\n result.presentationsTargets.push({\n key,\n version,\n targets: targetsList as Record<string, unknown>[],\n });\n }\n }\n });\n }\n }\n\n // Also support inline targets in presentations list\n extractPresentationTargets(obj, result.presentationsTargets);\n }\n }\n }\n\n return result;\n}\n\nfunction extractLinks(\n obj: ObjectLiteralExpression,\n opToPresentationLinks: { op: RefInfo; pres: RefInfo }[]\n): void {\n const interactionsProp = obj.getProperty('interactions');\n if (interactionsProp && Node.isPropertyAssignment(interactionsProp)) {\n const interactionsArr = interactionsProp.getInitializer();\n if (interactionsArr && Node.isArrayLiteralExpression(interactionsArr)) {\n interactionsArr.getElements().forEach((interaction) => {\n if (Node.isObjectLiteralExpression(interaction)) {\n // Check: trigger: { type: 'presentation', presentation: { key, version } }\n // Check: action: { type: 'operation', operation: { key, version } }\n\n const triggerProp = interaction.getProperty('trigger');\n const triggerObj =\n triggerProp &&\n Node.isPropertyAssignment(triggerProp) &&\n triggerProp.getInitializer();\n\n const actionProp = interaction.getProperty('action');\n const actionObj =\n actionProp &&\n Node.isPropertyAssignment(actionProp) &&\n actionProp.getInitializer();\n\n if (\n triggerObj &&\n Node.isObjectLiteralExpression(triggerObj) &&\n actionObj &&\n Node.isObjectLiteralExpression(actionObj)\n ) {\n const triggerType = getTextFromProp(triggerObj, 'type');\n const actionType = getTextFromProp(actionObj, 'type');\n\n if (triggerType === 'presentation' && actionType === 'operation') {\n const presRef = extractNestedRef(triggerObj, 'presentation');\n const opRef = extractNestedRef(actionObj, 'operation');\n\n if (presRef && opRef) {\n opToPresentationLinks.push({ op: opRef, pres: presRef });\n }\n }\n }\n }\n });\n }\n }\n}\n\nfunction extractNestedRef(\n obj: ObjectLiteralExpression,\n propName: string\n): RefInfo | undefined {\n const prop = obj.getProperty(propName);\n if (prop && Node.isPropertyAssignment(prop)) {\n const val = prop.getInitializer();\n if (val && Node.isObjectLiteralExpression(val)) {\n const key = getTextFromProp(val, 'key');\n const version = getTextFromProp(val, 'version');\n if (key && version) return { key, version };\n }\n }\n return undefined;\n}\n\nfunction extractPresentationTargets(\n obj: ObjectLiteralExpression,\n presentationsTargets: {\n key: string;\n version: string;\n targets: Record<string, unknown>[];\n }[]\n): void {\n const presentationsProp = obj.getProperty('presentations');\n if (presentationsProp && Node.isPropertyAssignment(presentationsProp)) {\n const presentationsArr = presentationsProp.getInitializer();\n if (presentationsArr && Node.isArrayLiteralExpression(presentationsArr)) {\n for (const elem of presentationsArr.getElements()) {\n if (Node.isObjectLiteralExpression(elem)) {\n const keyText = getTextFromProp(elem, 'key');\n const verText = getTextFromProp(elem, 'version');\n\n // Use targets extraction from shared utility or local helper\n const targetsList = getTargetsList(elem, 'targets');\n\n if (keyText && verText && targetsList) {\n presentationsTargets.push({\n key: keyText,\n version: verText,\n targets: targetsList as Record<string, unknown>[],\n });\n }\n }\n }\n }\n }\n}\n\nfunction getTextFromProp(\n obj: ObjectLiteralExpression,\n propName: string\n): string | undefined {\n const prop = obj.getProperty(propName);\n if (prop && Node.isPropertyAssignment(prop)) {\n const init = prop.getInitializer();\n if (init && Node.isStringLiteral(init)) {\n return init.getLiteralText();\n }\n }\n return undefined;\n}\n\nfunction getTargetsList(\n obj: ObjectLiteralExpression,\n propName: string\n): unknown[] | undefined {\n const prop = obj.getProperty(propName);\n if (prop && Node.isPropertyAssignment(prop)) {\n const init = prop.getInitializer();\n if (init && Node.isArrayLiteralExpression(init)) {\n // Just extract strings for now, or raw text if they are identifiers/enums\n return init.getElements().map((e) => {\n if (Node.isStringLiteral(e)) return e.getLiteralText();\n // Fallback: create a dummy record to match the Expected type in the rest of the app\n return { target: e.getText() } as unknown;\n });\n }\n }\n return undefined;\n}\n"],"mappings":"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"}
@@ -1,56 +0,0 @@
1
- import { isStability, matchStringArrayField, matchStringField } from "./utils/matchers.js";
2
- import { extractFeatureRefs } from "./feature-extractor.js";
3
-
4
- //#region src/analysis/feature-scan.ts
5
- /**
6
- * Check if a file is a feature file based on naming conventions.
7
- */
8
- function isFeatureFile(filePath) {
9
- return filePath.includes(".feature.") && filePath.endsWith(".ts");
10
- }
11
- /**
12
- * Scan a feature source file to extract metadata.
13
- */
14
- function scanFeatureSource(code, filePath) {
15
- const key = matchStringField(code, "key") ?? extractKeyFromFilePath(filePath);
16
- const version = matchStringField(code, "version") ?? "1.0.0";
17
- const title = matchStringField(code, "title") ?? void 0;
18
- const description = matchStringField(code, "description") ?? void 0;
19
- const goal = matchStringField(code, "goal") ?? void 0;
20
- const context = matchStringField(code, "context") ?? void 0;
21
- const stabilityRaw = matchStringField(code, "stability");
22
- const stability = isStability(stabilityRaw) ? stabilityRaw : void 0;
23
- const owners = matchStringArrayField(code, "owners");
24
- const tags = matchStringArrayField(code, "tags");
25
- const refs = extractFeatureRefs(code);
26
- return {
27
- filePath,
28
- key,
29
- version,
30
- title,
31
- description,
32
- goal,
33
- context,
34
- stability,
35
- owners,
36
- tags,
37
- operations: refs.operations,
38
- events: refs.events,
39
- presentations: refs.presentations,
40
- experiments: refs.experiments,
41
- capabilities: refs.capabilities,
42
- opToPresentationLinks: refs.opToPresentationLinks,
43
- presentationsTargets: refs.presentationsTargets,
44
- sourceBlock: code
45
- };
46
- }
47
- /**
48
- * Extract key from file path as fallback.
49
- */
50
- function extractKeyFromFilePath(filePath) {
51
- return (filePath.split("/").pop() ?? filePath).replace(/\.feature\.[jt]s$/, "").replace(/[^a-zA-Z0-9-]/g, "-");
52
- }
53
-
54
- //#endregion
55
- export { isFeatureFile, scanFeatureSource };
56
- //# sourceMappingURL=feature-scan.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"feature-scan.js","names":[],"sources":["../../src/analysis/feature-scan.ts"],"sourcesContent":["import {\n isStability,\n matchStringArrayField,\n matchStringField,\n} from './utils/matchers';\nimport type { FeatureScanResult } from '../types/analysis-types';\nimport { extractFeatureRefs } from './feature-extractor';\n\n/**\n * Check if a file is a feature file based on naming conventions.\n */\nexport function isFeatureFile(filePath: string): boolean {\n return filePath.includes('.feature.') && filePath.endsWith('.ts');\n}\n\n/**\n * Scan a feature source file to extract metadata.\n */\nexport function scanFeatureSource(\n code: string,\n filePath: string\n): FeatureScanResult {\n const key = matchStringField(code, 'key') ?? extractKeyFromFilePath(filePath);\n const versionRaw = matchStringField(code, 'version');\n const version = versionRaw ?? '1.0.0'; // Default version\n const title = matchStringField(code, 'title') ?? undefined;\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 // Parse structure using ts-morph to extract nested refs\n const refs = extractFeatureRefs(code);\n\n return {\n filePath,\n key,\n version,\n title,\n description,\n goal,\n context,\n stability,\n owners,\n tags,\n operations: refs.operations,\n events: refs.events,\n presentations: refs.presentations,\n experiments: refs.experiments,\n capabilities: refs.capabilities,\n opToPresentationLinks: refs.opToPresentationLinks,\n presentationsTargets: refs.presentationsTargets,\n sourceBlock: code,\n };\n}\n\n/**\n * Extract key from file path as fallback.\n */\nfunction extractKeyFromFilePath(filePath: string): string {\n const fileName = filePath.split('/').pop() ?? filePath;\n return fileName\n .replace(/\\.feature\\.[jt]s$/, '')\n .replace(/[^a-zA-Z0-9-]/g, '-');\n}\n"],"mappings":";;;;;;;AAWA,SAAgB,cAAc,UAA2B;AACvD,QAAO,SAAS,SAAS,YAAY,IAAI,SAAS,SAAS,MAAM;;;;;AAMnE,SAAgB,kBACd,MACA,UACmB;CACnB,MAAM,MAAM,iBAAiB,MAAM,MAAM,IAAI,uBAAuB,SAAS;CAE7E,MAAM,UADa,iBAAiB,MAAM,UAAU,IACtB;CAC9B,MAAM,QAAQ,iBAAiB,MAAM,QAAQ,IAAI;CACjD,MAAM,cAAc,iBAAiB,MAAM,cAAc,IAAI;CAC7D,MAAM,OAAO,iBAAiB,MAAM,OAAO,IAAI;CAC/C,MAAM,UAAU,iBAAiB,MAAM,UAAU,IAAI;CACrD,MAAM,eAAe,iBAAiB,MAAM,YAAY;CACxD,MAAM,YAAY,YAAY,aAAa,GAAG,eAAe;CAC7D,MAAM,SAAS,sBAAsB,MAAM,SAAS;CACpD,MAAM,OAAO,sBAAsB,MAAM,OAAO;CAGhD,MAAM,OAAO,mBAAmB,KAAK;AAErC,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YAAY,KAAK;EACjB,QAAQ,KAAK;EACb,eAAe,KAAK;EACpB,aAAa,KAAK;EAClB,cAAc,KAAK;EACnB,uBAAuB,KAAK;EAC5B,sBAAsB,KAAK;EAC3B,aAAa;EACd;;;;;AAMH,SAAS,uBAAuB,UAA0B;AAExD,SADiB,SAAS,MAAM,IAAI,CAAC,KAAK,IAAI,UAE3C,QAAQ,qBAAqB,GAAG,CAChC,QAAQ,kBAAkB,IAAI"}