@skyramp/mcp 0.3.2-rc.pom-3 → 0.3.2

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 (289) hide show
  1. package/build/commands/commandLibrary.d.ts +1 -0
  2. package/build/commands/commandLibrary.js +19 -13
  3. package/build/commands/localDevTestChangesCommand.d.ts +15 -0
  4. package/build/commands/localDevTestChangesCommand.js +201 -0
  5. package/build/index.js +80 -6
  6. package/build/prompts/code-reuse.js +3 -0
  7. package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +1 -0
  8. package/build/prompts/enhance-assertions/sharedAssertionRules.js +17 -0
  9. package/build/prompts/initialize-workspace/initializeWorkspacePrompt.js +11 -9
  10. package/build/prompts/local-dev/local-dev-plan.d.ts +35 -0
  11. package/build/prompts/local-dev/local-dev-plan.js +429 -0
  12. package/build/prompts/local-dev/local-dev-prompts.d.ts +4 -0
  13. package/build/prompts/local-dev/local-dev-prompts.js +190 -0
  14. package/build/prompts/pom-aware-code-reuse.js +12 -0
  15. package/build/prompts/prompt-utils.d.ts +8 -0
  16. package/build/prompts/prompt-utils.js +33 -0
  17. package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +37 -14
  18. package/build/prompts/sut-setup/shared.js +16 -12
  19. package/build/prompts/test-recommendation/analysisOutputPrompt.js +21 -29
  20. package/build/prompts/test-recommendation/scopeAssessment.d.ts +24 -7
  21. package/build/prompts/test-recommendation/scopeAssessment.js +111 -12
  22. package/build/prompts/test-recommendation/test-recommendation-prompt.js +41 -4
  23. package/build/prompts/testbot/testbot-prompts.d.ts +0 -5
  24. package/build/prompts/testbot/testbot-prompts.js +32 -52
  25. package/build/recommendation/planRanker.d.ts +15 -2
  26. package/build/recommendation/planRanker.js +76 -5
  27. package/build/resources/testbotResource.js +2 -1
  28. package/build/services/AnalyticsService.d.ts +1 -1
  29. package/build/services/TestExecutionService.d.ts +2 -1
  30. package/build/services/TestExecutionService.js +8 -3
  31. package/build/services/TestGenerationService.d.ts +2 -2
  32. package/build/services/TestGenerationService.js +39 -21
  33. package/build/services/containerEnv.js +3 -1
  34. package/build/tool-phases.js +6 -0
  35. package/build/tools/code-refactor/codeReuseTool.js +43 -4
  36. package/build/tools/code-refactor/enhanceAssertionsTool.js +68 -18
  37. package/build/tools/code-refactor/reuse-outcome.d.ts +109 -0
  38. package/build/tools/code-refactor/reuse-outcome.js +158 -0
  39. package/build/tools/code-refactor/reuse-state.d.ts +45 -0
  40. package/build/tools/code-refactor/reuse-state.js +140 -0
  41. package/build/tools/enrichTestWithMocksTool.d.ts +28 -0
  42. package/build/tools/enrichTestWithMocksTool.js +726 -0
  43. package/build/tools/executeSkyrampTestTool.d.ts +11 -0
  44. package/build/tools/executeSkyrampTestTool.js +62 -21
  45. package/build/tools/generate-tests/batchMockGenerationTool.d.ts +106 -0
  46. package/build/tools/generate-tests/batchMockGenerationTool.js +545 -0
  47. package/build/tools/generate-tests/generateBatchScenarioRestTool.js +25 -23
  48. package/build/tools/generate-tests/generateContractRestTool.js +2 -2
  49. package/build/tools/generate-tests/generateE2ERestTool.d.ts +1 -1
  50. package/build/tools/generate-tests/generateE2ERestTool.js +1 -1
  51. package/build/tools/generate-tests/generateLoadRestTool.d.ts +1 -1
  52. package/build/tools/generate-tests/generateLoadRestTool.js +1 -1
  53. package/build/tools/generate-tests/generateMockRestTool.d.ts +179 -6
  54. package/build/tools/generate-tests/generateMockRestTool.js +391 -22
  55. package/build/tools/generate-tests/loadTestSchema.d.ts +1 -1
  56. package/build/tools/generate-tests/planGuard.js +2 -22
  57. package/build/tools/generateEnrichedIntegrationTestTool.d.ts +25 -0
  58. package/build/tools/generateEnrichedIntegrationTestTool.js +235 -0
  59. package/build/tools/localDevWorkerComposeTool.d.ts +24 -0
  60. package/build/tools/localDevWorkerComposeTool.js +264 -0
  61. package/build/tools/one-click/oneClickTool.d.ts +13 -0
  62. package/build/tools/one-click/oneClickTool.js +195 -24
  63. package/build/tools/preflightMockCheckTool.d.ts +2 -0
  64. package/build/tools/preflightMockCheckTool.js +96 -0
  65. package/build/tools/queryProxyMocksTool.d.ts +70 -0
  66. package/build/tools/queryProxyMocksTool.js +522 -0
  67. package/build/tools/runExistingTestsTool.d.ts +31 -0
  68. package/build/tools/runExistingTestsTool.js +214 -13
  69. package/build/tools/submitReportTool.js +38 -3
  70. package/build/tools/test-management/analyzeChangesTool.d.ts +2 -1
  71. package/build/tools/test-management/analyzeChangesTool.js +63 -40
  72. package/build/tools/test-management/registerTestPlanTool.js +55 -7
  73. package/build/tools/trace/startTraceCollectionTool.js +3 -3
  74. package/build/types/FrontendIntegration.d.ts +3 -0
  75. package/build/types/FrontendIntegration.js +3 -0
  76. package/build/types/OneClickCommands.d.ts +1 -1
  77. package/build/types/Recommendation.d.ts +20 -0
  78. package/build/types/Recommendation.js +32 -6
  79. package/build/types/RepositoryAnalysis.d.ts +131 -14
  80. package/build/types/RepositoryAnalysis.js +16 -2
  81. package/build/types/ReuseOutcome.d.ts +63 -0
  82. package/build/types/ReuseOutcome.js +33 -0
  83. package/build/types/TestExecution.d.ts +1 -0
  84. package/build/types/TestTypes.d.ts +25 -7
  85. package/build/types/TestTypes.js +22 -6
  86. package/build/types/TestbotReport.d.ts +7 -0
  87. package/build/types/index.d.ts +2 -0
  88. package/build/types/index.js +1 -0
  89. package/build/utils/AnalysisStateManager.d.ts +26 -0
  90. package/build/utils/AnalysisStateManager.js +31 -1
  91. package/build/utils/analyze-openapi.js +18 -1
  92. package/build/utils/branchDiff.d.ts +17 -1
  93. package/build/utils/branchDiff.js +99 -14
  94. package/build/utils/featureFlags.d.ts +31 -0
  95. package/build/utils/featureFlags.js +37 -0
  96. package/build/utils/frontendIntegration.js +8 -1
  97. package/build/utils/grpcMockValidation.d.ts +1 -0
  98. package/build/utils/grpcMockValidation.js +49 -0
  99. package/build/utils/httpMethodValidation.d.ts +4 -0
  100. package/build/utils/httpMethodValidation.js +15 -0
  101. package/build/utils/logger.js +1 -1
  102. package/build/utils/mockCompatibility.d.ts +49 -0
  103. package/build/utils/mockCompatibility.js +82 -0
  104. package/build/utils/pom-scope/pom-files.js +7 -0
  105. package/build/utils/pom-verify/bindings.js +11 -1
  106. package/build/utils/pom-verify/re-exports.d.ts +10 -0
  107. package/build/utils/pom-verify/re-exports.js +61 -0
  108. package/build/utils/pom-verify/resolve.d.ts +4 -1
  109. package/build/utils/pom-verify/resolve.js +7 -4
  110. package/build/utils/pom-verify/verify.d.ts +5 -0
  111. package/build/utils/pom-verify/verify.js +25 -3
  112. package/build/utils/progress.js +10 -5
  113. package/build/utils/proxy-terminal.js +3 -3
  114. package/build/utils/routeParsers.d.ts +3 -9
  115. package/build/utils/routeParsers.js +79 -4
  116. package/build/utils/utils.js +2 -2
  117. package/build/utils/versions.d.ts +4 -3
  118. package/build/utils/versions.js +3 -1
  119. package/build/utils/workspaceAuth.d.ts +46 -0
  120. package/build/utils/workspaceAuth.js +156 -1
  121. package/build/workspace/testSuites.d.ts +2 -1
  122. package/build/workspace/testSuites.js +1 -1
  123. package/build/workspace/workspace.d.ts +108 -32
  124. package/build/workspace/workspace.js +32 -4
  125. package/package.json +5 -2
  126. package/build/adapters/jestAdapter.test.d.ts +0 -1
  127. package/build/adapters/jestAdapter.test.js +0 -93
  128. package/build/adapters/mochaAdapter.test.d.ts +0 -1
  129. package/build/adapters/mochaAdapter.test.js +0 -63
  130. package/build/adapters/playwrightAdapter.test.d.ts +0 -1
  131. package/build/adapters/playwrightAdapter.test.js +0 -169
  132. package/build/adapters/pytestAdapter.test.d.ts +0 -1
  133. package/build/adapters/pytestAdapter.test.js +0 -90
  134. package/build/prompts/code-reuse.test.d.ts +0 -1
  135. package/build/prompts/code-reuse.test.js +0 -62
  136. package/build/prompts/pom-aware-code-reuse.test.d.ts +0 -1
  137. package/build/prompts/pom-aware-code-reuse.test.js +0 -11
  138. package/build/prompts/test-maintenance/drift-analysis-prompt.test.d.ts +0 -1
  139. package/build/prompts/test-maintenance/drift-analysis-prompt.test.js +0 -51
  140. package/build/prompts/test-recommendation/analysisOutputPrompt.test.d.ts +0 -1
  141. package/build/prompts/test-recommendation/analysisOutputPrompt.test.js +0 -264
  142. package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.d.ts +0 -1
  143. package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.js +0 -126
  144. package/build/prompts/test-recommendation/promptPlan.test.d.ts +0 -1
  145. package/build/prompts/test-recommendation/promptPlan.test.js +0 -336
  146. package/build/prompts/test-recommendation/scopeAssessment.test.d.ts +0 -1
  147. package/build/prompts/test-recommendation/scopeAssessment.test.js +0 -371
  148. package/build/prompts/test-recommendation/test-recommendation-prompt.test.d.ts +0 -1
  149. package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +0 -1925
  150. package/build/prompts/testbot/testbot-prompts.test.d.ts +0 -1
  151. package/build/prompts/testbot/testbot-prompts.test.js +0 -451
  152. package/build/recommendation/budgeters/diversityBalancedBudgeter.test.d.ts +0 -1
  153. package/build/recommendation/budgeters/diversityBalancedBudgeter.test.js +0 -138
  154. package/build/recommendation/budgeters/fixedNBudgeter.test.d.ts +0 -1
  155. package/build/recommendation/budgeters/fixedNBudgeter.test.js +0 -66
  156. package/build/recommendation/discriminators.test.d.ts +0 -1
  157. package/build/recommendation/discriminators.test.js +0 -324
  158. package/build/recommendation/diversity.test.d.ts +0 -1
  159. package/build/recommendation/diversity.test.js +0 -77
  160. package/build/recommendation/planRanker.test.d.ts +0 -1
  161. package/build/recommendation/planRanker.test.js +0 -110
  162. package/build/resources/testbotResource.test.d.ts +0 -1
  163. package/build/resources/testbotResource.test.js +0 -44
  164. package/build/services/AnalyticsService.test.d.ts +0 -1
  165. package/build/services/AnalyticsService.test.js +0 -86
  166. package/build/services/ScenarioGenerationService.integration.test.d.ts +0 -1
  167. package/build/services/ScenarioGenerationService.integration.test.js +0 -162
  168. package/build/services/ScenarioGenerationService.test.d.ts +0 -1
  169. package/build/services/ScenarioGenerationService.test.js +0 -414
  170. package/build/services/TestDiscoveryService.test.d.ts +0 -1
  171. package/build/services/TestDiscoveryService.test.js +0 -983
  172. package/build/services/TestExecutionService.test.d.ts +0 -1
  173. package/build/services/TestExecutionService.test.js +0 -1032
  174. package/build/services/TestGenerationService.test.d.ts +0 -1
  175. package/build/services/TestGenerationService.test.js +0 -578
  176. package/build/tool-phase-coverage.test.d.ts +0 -1
  177. package/build/tool-phase-coverage.test.js +0 -49
  178. package/build/tools/code-refactor/codeReuseTool.test.d.ts +0 -1
  179. package/build/tools/code-refactor/codeReuseTool.test.js +0 -572
  180. package/build/tools/generate-tests/generateBatchScenarioRestTool.test.d.ts +0 -1
  181. package/build/tools/generate-tests/generateBatchScenarioRestTool.test.js +0 -433
  182. package/build/tools/generate-tests/generateContractRestTool.test.d.ts +0 -1
  183. package/build/tools/generate-tests/generateContractRestTool.test.js +0 -142
  184. package/build/tools/generate-tests/generateIntegrationRestTool.test.d.ts +0 -1
  185. package/build/tools/generate-tests/generateIntegrationRestTool.test.js +0 -159
  186. package/build/tools/generate-tests/generateLoadRestTool.test.d.ts +0 -1
  187. package/build/tools/generate-tests/generateLoadRestTool.test.js +0 -169
  188. package/build/tools/generate-tests/generateUIRestTool.test.d.ts +0 -1
  189. package/build/tools/generate-tests/generateUIRestTool.test.js +0 -32
  190. package/build/tools/generate-tests/planGuard.test.d.ts +0 -1
  191. package/build/tools/generate-tests/planGuard.test.js +0 -185
  192. package/build/tools/generate-tests/scenarioLint.test.d.ts +0 -1
  193. package/build/tools/generate-tests/scenarioLint.test.js +0 -100
  194. package/build/tools/runExistingTestsTool.test.d.ts +0 -1
  195. package/build/tools/runExistingTestsTool.test.js +0 -379
  196. package/build/tools/submitReportTool.test.d.ts +0 -1
  197. package/build/tools/submitReportTool.test.js +0 -1428
  198. package/build/tools/test-management/actionsTool.test.d.ts +0 -1
  199. package/build/tools/test-management/actionsTool.test.js +0 -436
  200. package/build/tools/test-management/analyzeChangesTool.test.d.ts +0 -1
  201. package/build/tools/test-management/analyzeChangesTool.test.js +0 -522
  202. package/build/tools/test-management/analyzeTestHealthTool.test.d.ts +0 -1
  203. package/build/tools/test-management/analyzeTestHealthTool.test.js +0 -385
  204. package/build/tools/test-management/registerTestPlanTool.test.d.ts +0 -1
  205. package/build/tools/test-management/registerTestPlanTool.test.js +0 -296
  206. package/build/tools/trace/resolveSaveStoragePath.test.d.ts +0 -1
  207. package/build/tools/trace/resolveSaveStoragePath.test.js +0 -17
  208. package/build/tools/trace/resolveSessionPaths.test.d.ts +0 -1
  209. package/build/tools/trace/resolveSessionPaths.test.js +0 -104
  210. package/build/tools/trace/sessionState.test.d.ts +0 -1
  211. package/build/tools/trace/sessionState.test.js +0 -17
  212. package/build/tools/workspace/initializeWorkspaceTool.test.d.ts +0 -1
  213. package/build/tools/workspace/initializeWorkspaceTool.test.js +0 -139
  214. package/build/tools/workspace/serviceUpsert.test.d.ts +0 -1
  215. package/build/tools/workspace/serviceUpsert.test.js +0 -50
  216. package/build/utils/AnalysisStateManager.test.d.ts +0 -1
  217. package/build/utils/AnalysisStateManager.test.js +0 -134
  218. package/build/utils/dartRouteExtractor.test.d.ts +0 -1
  219. package/build/utils/dartRouteExtractor.test.js +0 -307
  220. package/build/utils/docker.test.d.ts +0 -1
  221. package/build/utils/docker.test.js +0 -114
  222. package/build/utils/featureFlags.test.d.ts +0 -1
  223. package/build/utils/featureFlags.test.js +0 -81
  224. package/build/utils/fileWalk.test.d.ts +0 -1
  225. package/build/utils/fileWalk.test.js +0 -252
  226. package/build/utils/frontendIntegration.test.d.ts +0 -1
  227. package/build/utils/frontendIntegration.test.js +0 -229
  228. package/build/utils/frontendSelectors.test.d.ts +0 -1
  229. package/build/utils/frontendSelectors.test.js +0 -118
  230. package/build/utils/gitStaging.test.d.ts +0 -1
  231. package/build/utils/gitStaging.test.js +0 -111
  232. package/build/utils/httpDefaults.test.d.ts +0 -1
  233. package/build/utils/httpDefaults.test.js +0 -21
  234. package/build/utils/importerHop.test.d.ts +0 -1
  235. package/build/utils/importerHop.test.js +0 -469
  236. package/build/utils/pathAffinityClassification.test.d.ts +0 -1
  237. package/build/utils/pathAffinityClassification.test.js +0 -208
  238. package/build/utils/planMatchKeys.test.d.ts +0 -1
  239. package/build/utils/planMatchKeys.test.js +0 -123
  240. package/build/utils/pom-scope/index.test.d.ts +0 -1
  241. package/build/utils/pom-scope/index.test.js +0 -278
  242. package/build/utils/pom-scope/pom-files.test.d.ts +0 -1
  243. package/build/utils/pom-scope/pom-files.test.js +0 -29
  244. package/build/utils/pom-scope/scoring.test.d.ts +0 -1
  245. package/build/utils/pom-scope/scoring.test.js +0 -39
  246. package/build/utils/pom-scope/selector-extractor.test.d.ts +0 -1
  247. package/build/utils/pom-scope/selector-extractor.test.js +0 -67
  248. package/build/utils/pom-verify/bindings.test.d.ts +0 -1
  249. package/build/utils/pom-verify/bindings.test.js +0 -164
  250. package/build/utils/pom-verify/calls.test.d.ts +0 -1
  251. package/build/utils/pom-verify/calls.test.js +0 -61
  252. package/build/utils/pom-verify/resolve.test.d.ts +0 -1
  253. package/build/utils/pom-verify/resolve.test.js +0 -114
  254. package/build/utils/pom-verify/verify.test.d.ts +0 -1
  255. package/build/utils/pom-verify/verify.test.js +0 -374
  256. package/build/utils/pr-comment-parser.test.d.ts +0 -1
  257. package/build/utils/pr-comment-parser.test.js +0 -428
  258. package/build/utils/progress.test.d.ts +0 -1
  259. package/build/utils/progress.test.js +0 -37
  260. package/build/utils/projectMetadata.test.d.ts +0 -1
  261. package/build/utils/projectMetadata.test.js +0 -172
  262. package/build/utils/pythonMountPrefixes.test.d.ts +0 -1
  263. package/build/utils/pythonMountPrefixes.test.js +0 -113
  264. package/build/utils/repoScanner.test.d.ts +0 -1
  265. package/build/utils/repoScanner.test.js +0 -190
  266. package/build/utils/reportVerification.test.d.ts +0 -1
  267. package/build/utils/reportVerification.test.js +0 -185
  268. package/build/utils/routeParsers.test.d.ts +0 -1
  269. package/build/utils/routeParsers.test.js +0 -1011
  270. package/build/utils/scenarioDrafting.test.d.ts +0 -1
  271. package/build/utils/scenarioDrafting.test.js +0 -876
  272. package/build/utils/sourceRouteExtractor.test.d.ts +0 -1
  273. package/build/utils/sourceRouteExtractor.test.js +0 -738
  274. package/build/utils/telemetry.test.d.ts +0 -1
  275. package/build/utils/telemetry.test.js +0 -70
  276. package/build/utils/trace-parser.test.d.ts +0 -6
  277. package/build/utils/trace-parser.test.js +0 -140
  278. package/build/utils/uiPageEnumerator.test.d.ts +0 -1
  279. package/build/utils/uiPageEnumerator.test.js +0 -824
  280. package/build/utils/utils.test.d.ts +0 -1
  281. package/build/utils/utils.test.js +0 -103
  282. package/build/utils/walkerCharacterization.test.d.ts +0 -1
  283. package/build/utils/walkerCharacterization.test.js +0 -233
  284. package/build/utils/workspaceAuth.test.d.ts +0 -1
  285. package/build/utils/workspaceAuth.test.js +0 -260
  286. package/build/workspace/testSuites.test.d.ts +0 -1
  287. package/build/workspace/testSuites.test.js +0 -23
  288. package/build/workspace/workspace.test.d.ts +0 -1
  289. package/build/workspace/workspace.test.js +0 -264
@@ -1,738 +0,0 @@
1
- // No external mocks needed — the extractor is pure fs + TS Compiler API.
2
- import * as fs from "fs";
3
- import * as os from "os";
4
- import * as path from "path";
5
- import { extractSourceRoutes } from "./sourceRouteExtractor.js";
6
- function makeTmpRepo(files) {
7
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), "skyramp-route-test-"));
8
- for (const f of files) {
9
- const fullPath = path.join(dir, f.path);
10
- fs.mkdirSync(path.dirname(fullPath), { recursive: true });
11
- fs.writeFileSync(fullPath, f.content);
12
- }
13
- return dir;
14
- }
15
- function cleanup(dir) {
16
- fs.rmSync(dir, { recursive: true, force: true });
17
- }
18
- // ── Tests ──────────────────────────────────────────────────────────────────
19
- describe("extractSourceRoutes", () => {
20
- it("returns empty when no router files found", () => {
21
- const repo = makeTmpRepo([
22
- {
23
- path: "src/components/Button.tsx",
24
- content: "export default function Button() { return <button/>; }",
25
- },
26
- ]);
27
- expect(extractSourceRoutes(repo)).toEqual([]);
28
- cleanup(repo);
29
- });
30
- it("extracts a single React Router Route with element prop", () => {
31
- const repo = makeTmpRepo([
32
- {
33
- path: "src/App.tsx",
34
- content: `
35
- import { Routes, Route } from 'react-router-dom';
36
- import Cart from './pages/Cart';
37
-
38
- export default function App() {
39
- return (
40
- <Routes>
41
- <Route path="/cart" element={<Cart />} />
42
- </Routes>
43
- );
44
- }
45
- `,
46
- },
47
- {
48
- path: "src/pages/Cart.tsx",
49
- content: "export default function Cart() { return <div/>; }",
50
- },
51
- ]);
52
- const routes = extractSourceRoutes(repo);
53
- expect(routes).toHaveLength(1);
54
- expect(routes[0]).toMatchObject({
55
- path: "/cart",
56
- componentName: "Cart",
57
- });
58
- expect(routes[0].componentFile).toMatch(/src\/pages\/Cart\.tsx$/);
59
- cleanup(repo);
60
- });
61
- it("extracts multiple Routes from one file", () => {
62
- const repo = makeTmpRepo([
63
- {
64
- path: "src/App.tsx",
65
- content: `
66
- import { Routes, Route } from 'react-router-dom';
67
- import Cart from './pages/Cart';
68
- import Orders from './pages/Orders';
69
- import ProductDetail from './pages/ProductDetail';
70
-
71
- export default function App() {
72
- return (
73
- <Routes>
74
- <Route path="/cart" element={<Cart />} />
75
- <Route path="/orders" element={<Orders />} />
76
- <Route path="/products/:id" element={<ProductDetail />} />
77
- </Routes>
78
- );
79
- }
80
- `,
81
- },
82
- ]);
83
- const routes = extractSourceRoutes(repo);
84
- expect(routes).toHaveLength(3);
85
- expect(routes.map((r) => r.path).sort()).toEqual([
86
- "/cart",
87
- "/orders",
88
- "/products/:id",
89
- ]);
90
- cleanup(repo);
91
- });
92
- it("extracts Route with component prop (alternate syntax)", () => {
93
- const repo = makeTmpRepo([
94
- {
95
- path: "src/App.tsx",
96
- content: `
97
- import { Route } from 'react-router-dom';
98
- import Cart from './pages/Cart';
99
-
100
- export default function App() {
101
- return <Route path="/cart" component={Cart} />;
102
- }
103
- `,
104
- },
105
- ]);
106
- const routes = extractSourceRoutes(repo);
107
- expect(routes).toHaveLength(1);
108
- expect(routes[0].path).toBe("/cart");
109
- expect(routes[0].componentName).toBe("Cart");
110
- });
111
- it("recognizes SentryRoute and other configured wrapper components", () => {
112
- const repo = makeTmpRepo([
113
- {
114
- path: "src/AppRouter.tsx",
115
- content: `
116
- import { Switch } from 'react-router-dom';
117
- import { SentryRoute } from './components/SentryRoute';
118
- import Workspaces from './pages/Workspaces';
119
-
120
- export default function AppRouter() {
121
- return (
122
- <Switch>
123
- <SentryRoute path="/workspaces" component={Workspaces} />
124
- </Switch>
125
- );
126
- }
127
- `,
128
- },
129
- ]);
130
- const routes = extractSourceRoutes(repo);
131
- expect(routes).toHaveLength(1);
132
- expect(routes[0].path).toBe("/workspaces");
133
- expect(routes[0].componentName).toBe("Workspaces");
134
- });
135
- it("resolves identifier-valued path attribute via local const (basic case)", () => {
136
- const repo = makeTmpRepo([
137
- {
138
- path: "src/App.tsx",
139
- content: `
140
- import { Route } from 'react-router-dom';
141
- import Workspaces from './pages/Workspaces';
142
-
143
- const WORKSPACE_URL = "/workspace";
144
-
145
- export default function App() {
146
- return <Route path={WORKSPACE_URL} element={<Workspaces />} />;
147
- }
148
- `,
149
- },
150
- ]);
151
- const routes = extractSourceRoutes(repo);
152
- expect(routes).toHaveLength(1);
153
- expect(routes[0].path).toBe("/workspace");
154
- });
155
- it("skips Route with template literal path whose parts are not module-scoped", () => {
156
- // Const declarations inside a function aren't visible to the resolver
157
- // (we only walk module-scope consts). The route is correctly skipped.
158
- const repo = makeTmpRepo([
159
- {
160
- path: "src/App.tsx",
161
- content: `
162
- import { Route } from 'react-router-dom';
163
- import Foo from './pages/Foo';
164
-
165
- export default function App() {
166
- const prefix = '/admin';
167
- return <Route path={\`\${prefix}/foo\`} element={<Foo />} />;
168
- }
169
- `,
170
- },
171
- ]);
172
- const routes = extractSourceRoutes(repo);
173
- expect(routes).toEqual([]);
174
- });
175
- it("skips Route without a path attribute", () => {
176
- const repo = makeTmpRepo([
177
- {
178
- path: "src/App.tsx",
179
- content: `
180
- import { Route } from 'react-router-dom';
181
- import Foo from './pages/Foo';
182
-
183
- export default function App() {
184
- return <Route element={<Foo />} />;
185
- }
186
- `,
187
- },
188
- ]);
189
- const routes = extractSourceRoutes(repo);
190
- expect(routes).toEqual([]);
191
- });
192
- it("resolves component file path via relative import", () => {
193
- const repo = makeTmpRepo([
194
- {
195
- path: "src/App.tsx",
196
- content: `
197
- import { Route } from 'react-router-dom';
198
- import Cart from './pages/Cart';
199
-
200
- export default function App() {
201
- return <Route path="/cart" element={<Cart />} />;
202
- }
203
- `,
204
- },
205
- {
206
- path: "src/pages/Cart.tsx",
207
- content: "export default function Cart() { return <div/>; }",
208
- },
209
- ]);
210
- const routes = extractSourceRoutes(repo);
211
- expect(routes[0].componentFile).toMatch(/src\/pages\/Cart\.tsx$/);
212
- cleanup(repo);
213
- });
214
- it("leaves componentFile undefined when import not found", () => {
215
- const repo = makeTmpRepo([
216
- {
217
- path: "src/App.tsx",
218
- content: `
219
- import { Route } from 'react-router-dom';
220
- // Cart referenced but not imported in this file
221
- export default function App() {
222
- return <Route path="/cart" element={<Cart />} />;
223
- }
224
- `,
225
- },
226
- ]);
227
- const routes = extractSourceRoutes(repo);
228
- expect(routes).toHaveLength(1);
229
- expect(routes[0].componentName).toBe("Cart");
230
- expect(routes[0].componentFile).toBeUndefined();
231
- cleanup(repo);
232
- });
233
- it("ignores non-Route JSX elements", () => {
234
- const repo = makeTmpRepo([
235
- {
236
- path: "src/App.tsx",
237
- content: `
238
- import { Routes, Route, Link } from 'react-router-dom';
239
- import Cart from './pages/Cart';
240
-
241
- export default function App() {
242
- return (
243
- <Routes>
244
- <Link to="/somewhere">Click</Link>
245
- <Route path="/cart" element={<Cart />} />
246
- </Routes>
247
- );
248
- }
249
- `,
250
- },
251
- ]);
252
- const routes = extractSourceRoutes(repo);
253
- expect(routes).toHaveLength(1);
254
- expect(routes[0].path).toBe("/cart");
255
- cleanup(repo);
256
- });
257
- it("discovers routes across multiple candidate router files", () => {
258
- const repo = makeTmpRepo([
259
- {
260
- path: "src/App.tsx",
261
- content: `
262
- import { Route } from 'react-router-dom';
263
- import Foo from './pages/Foo';
264
- export default function App() {
265
- return <Route path="/foo" element={<Foo />} />;
266
- }
267
- `,
268
- },
269
- {
270
- path: "src/router.tsx",
271
- content: `
272
- import { Route } from 'react-router-dom';
273
- import Bar from './pages/Bar';
274
- export const Bar2 = <Route path="/bar" element={<Bar />} />;
275
- `,
276
- },
277
- ]);
278
- const routes = extractSourceRoutes(repo);
279
- expect(routes.map((r) => r.path).sort()).toEqual(["/bar", "/foo"]);
280
- cleanup(repo);
281
- });
282
- it("resolves import with explicit .tsx extension", () => {
283
- const repo = makeTmpRepo([
284
- {
285
- path: "src/App.tsx",
286
- content: `
287
- import { Route } from 'react-router-dom';
288
- import Cart from './pages/Cart.tsx';
289
- export default function App() {
290
- return <Route path="/cart" element={<Cart />} />;
291
- }
292
- `,
293
- },
294
- {
295
- path: "src/pages/Cart.tsx",
296
- content: "export default function Cart() { return <div/>; }",
297
- },
298
- ]);
299
- const routes = extractSourceRoutes(repo);
300
- expect(routes[0].componentFile).toMatch(/src\/pages\/Cart\.tsx$/);
301
- cleanup(repo);
302
- });
303
- // ── Slice 3b: constant resolution ─────────────────────────────────────────
304
- it("resolves identifier-valued path via cross-file import (named)", () => {
305
- const repo = makeTmpRepo([
306
- {
307
- path: "src/constants/routes.ts",
308
- content: `
309
- export const APPLICATIONS_URL = "/applications";
310
- export const WORKSPACE_URL = "/workspace";
311
- `,
312
- },
313
- {
314
- path: "src/AppRouter.tsx",
315
- content: `
316
- import { Route } from 'react-router-dom';
317
- import { APPLICATIONS_URL } from './constants/routes';
318
- import Apps from './pages/Apps';
319
-
320
- export default function AppRouter() {
321
- return <Route path={APPLICATIONS_URL} element={<Apps />} />;
322
- }
323
- `,
324
- },
325
- ]);
326
- const routes = extractSourceRoutes(repo);
327
- expect(routes).toHaveLength(1);
328
- expect(routes[0].path).toBe("/applications");
329
- cleanup(repo);
330
- });
331
- it("resolves identifier-valued path via DEFAULT import (export default)", () => {
332
- // Regression: default imports were recorded with exportedName=null and
333
- // resolved with `name` (the local identifier) — but the resolver only
334
- // looks up named exports, so default-exported path constants never resolved.
335
- // Fix: mark default imports as exportedName="default" and handle
336
- // `export default <expr>` in the resolver.
337
- const repo = makeTmpRepo([
338
- {
339
- path: "src/constants/orders.ts",
340
- content: `export default "/orders";`,
341
- },
342
- {
343
- path: "src/AppRouter.tsx",
344
- content: `
345
- import { Route } from 'react-router-dom';
346
- import ORDERS_URL from './constants/orders';
347
- import Orders from './pages/Orders';
348
-
349
- export default function AppRouter() {
350
- return <Route path={ORDERS_URL} element={<Orders />} />;
351
- }
352
- `,
353
- },
354
- ]);
355
- const routes = extractSourceRoutes(repo);
356
- expect(routes).toHaveLength(1);
357
- expect(routes[0].path).toBe("/orders");
358
- cleanup(repo);
359
- });
360
- it("resolves identifier-valued path via DEFAULT import (export { X as default })", () => {
361
- const repo = makeTmpRepo([
362
- {
363
- path: "src/constants/cart.ts",
364
- content: `
365
- const CART_URL = "/cart";
366
- export { CART_URL as default };
367
- `,
368
- },
369
- {
370
- path: "src/AppRouter.tsx",
371
- content: `
372
- import { Route } from 'react-router-dom';
373
- import CART_URL from './constants/cart';
374
- import Cart from './pages/Cart';
375
-
376
- export default function AppRouter() {
377
- return <Route path={CART_URL} element={<Cart />} />;
378
- }
379
- `,
380
- },
381
- ]);
382
- const routes = extractSourceRoutes(repo);
383
- expect(routes).toHaveLength(1);
384
- expect(routes[0].path).toBe("/cart");
385
- cleanup(repo);
386
- });
387
- it("rejects absolute import specs (path-traversal hardening)", () => {
388
- // A hostile repo could write `import X from "/etc/passwd"` and trigger
389
- // arbitrary host-path file reads during route extraction. The collector
390
- // skips absolute import specs entirely. Verify by writing an import that
391
- // *would* otherwise resolve to outside repositoryPath if absolute paths
392
- // were honored.
393
- const repo = makeTmpRepo([
394
- {
395
- path: "src/constants/bad.ts",
396
- content: `export const BAD = "/should-not-resolve";`,
397
- },
398
- {
399
- path: "src/AppRouter.tsx",
400
- content: `
401
- import { Route } from 'react-router-dom';
402
- import { BAD } from "/etc/passwd";
403
- import Page from './pages/Page';
404
-
405
- export default function AppRouter() {
406
- return <Route path={BAD} element={<Page />} />;
407
- }
408
- `,
409
- },
410
- ]);
411
- const routes = extractSourceRoutes(repo);
412
- // The path constant doesn't resolve (absolute import rejected), so the
413
- // identifier remains unresolved and the route is skipped. Zero routes.
414
- expect(routes).toHaveLength(0);
415
- cleanup(repo);
416
- });
417
- it("resolves template literal that references another resolvable constant", () => {
418
- const repo = makeTmpRepo([
419
- {
420
- path: "src/constants/routes.ts",
421
- content: `
422
- export const USER_AUTH_URL = "/user";
423
- export const AUTH_LOGIN_URL = \`\${USER_AUTH_URL}/login\`;
424
- `,
425
- },
426
- {
427
- path: "src/AppRouter.tsx",
428
- content: `
429
- import { Route } from 'react-router-dom';
430
- import { AUTH_LOGIN_URL } from './constants/routes';
431
- import Login from './pages/Login';
432
-
433
- export default function AppRouter() {
434
- return <Route path={AUTH_LOGIN_URL} element={<Login />} />;
435
- }
436
- `,
437
- },
438
- ]);
439
- const routes = extractSourceRoutes(repo);
440
- expect(routes).toHaveLength(1);
441
- expect(routes[0].path).toBe("/user/login");
442
- cleanup(repo);
443
- });
444
- it("skips identifier path when constant cannot be resolved", () => {
445
- const repo = makeTmpRepo([
446
- {
447
- path: "src/AppRouter.tsx",
448
- content: `
449
- import { Route } from 'react-router-dom';
450
- import { UNKNOWN_URL } from 'some-package';
451
- import Foo from './pages/Foo';
452
-
453
- export default function AppRouter() {
454
- return <Route path={UNKNOWN_URL} element={<Foo />} />;
455
- }
456
- `,
457
- },
458
- ]);
459
- const routes = extractSourceRoutes(repo);
460
- expect(routes).toEqual([]);
461
- cleanup(repo);
462
- });
463
- // ── Slice 3b: Vue Router object literals ──────────────────────────────────
464
- it("extracts Vue Router routes from object-literal array", () => {
465
- const repo = makeTmpRepo([
466
- {
467
- path: "src/router.ts",
468
- content: `
469
- import { createRouter } from 'vue-router';
470
- import Login from '@/routes/login.vue';
471
- import Dashboard from '@/routes/dashboard.vue';
472
-
473
- export const defaultRoutes = [
474
- { name: 'login', path: '/login', component: Login },
475
- { name: 'dashboard', path: '/dashboard', component: Dashboard },
476
- ];
477
- `,
478
- },
479
- ]);
480
- const routes = extractSourceRoutes(repo);
481
- expect(routes.map((r) => r.path).sort()).toEqual(["/dashboard", "/login"]);
482
- cleanup(repo);
483
- });
484
- it("ignores object literals that aren't route declarations", () => {
485
- const repo = makeTmpRepo([
486
- {
487
- path: "src/router.ts",
488
- content: `
489
- const config = { path: '/somewhere', enabled: true };
490
- const settings = { timeout: 30 };
491
- `,
492
- },
493
- ]);
494
- const routes = extractSourceRoutes(repo);
495
- expect(routes).toEqual([]);
496
- cleanup(repo);
497
- });
498
- // ── Slice 3b: defineModule aggregation ────────────────────────────────────
499
- it("aggregates defineModule routes with module id as URL prefix", () => {
500
- const repo = makeTmpRepo([
501
- {
502
- path: "src/modules/notifications/index.ts",
503
- content: `
504
- import { defineModule } from '@directus/extensions';
505
- import NotificationsCollection from './routes/collection.vue';
506
-
507
- export default defineModule({
508
- id: 'notifications',
509
- name: 'Notifications',
510
- routes: [
511
- { name: 'notifications-collection', path: '', component: NotificationsCollection },
512
- ],
513
- });
514
- `,
515
- },
516
- ]);
517
- const routes = extractSourceRoutes(repo);
518
- expect(routes).toHaveLength(1);
519
- expect(routes[0].path).toBe("/notifications");
520
- cleanup(repo);
521
- });
522
- it("aggregates defineModule routes with nested path", () => {
523
- const repo = makeTmpRepo([
524
- {
525
- path: "src/modules/users/index.ts",
526
- content: `
527
- import { defineModule } from '@directus/extensions';
528
- import UserDetail from './routes/detail.vue';
529
-
530
- export default defineModule({
531
- id: 'users',
532
- routes: [
533
- { name: 'user-detail', path: ':id', component: UserDetail },
534
- ],
535
- });
536
- `,
537
- },
538
- ]);
539
- const routes = extractSourceRoutes(repo);
540
- expect(routes).toHaveLength(1);
541
- expect(routes[0].path).toBe("/users/:id");
542
- cleanup(repo);
543
- });
544
- it("resolves import that is a directory with index.tsx", () => {
545
- const repo = makeTmpRepo([
546
- {
547
- path: "src/App.tsx",
548
- content: `
549
- import { Route } from 'react-router-dom';
550
- import Cart from './pages/Cart';
551
- export default function App() {
552
- return <Route path="/cart" element={<Cart />} />;
553
- }
554
- `,
555
- },
556
- {
557
- path: "src/pages/Cart/index.tsx",
558
- content: "export default function Cart() { return <div/>; }",
559
- },
560
- ]);
561
- const routes = extractSourceRoutes(repo);
562
- expect(routes[0].componentFile).toMatch(/src\/pages\/Cart\/index\.tsx$/);
563
- cleanup(repo);
564
- });
565
- // ── Nested React Router routes ────────────────────────────────────────────
566
- it("composes nested JSX <Route> child paths with their parent", () => {
567
- // React Router v6 child paths are relative to the parent route. Without
568
- // composition the extractor emits bare segments ("settings") that aren't
569
- // navigable URLs.
570
- const repo = makeTmpRepo([
571
- {
572
- path: "src/App.tsx",
573
- content: `
574
- import { Routes, Route } from 'react-router-dom';
575
- import Dashboard from './pages/Dashboard';
576
- import Settings from './pages/Settings';
577
- import Users from './pages/Users';
578
-
579
- export default function App() {
580
- return (
581
- <Routes>
582
- <Route path="/dashboard" element={<Dashboard />}>
583
- <Route path="settings" element={<Settings />} />
584
- <Route path="users" element={<Users />} />
585
- </Route>
586
- </Routes>
587
- );
588
- }
589
- `,
590
- },
591
- ]);
592
- const routes = extractSourceRoutes(repo);
593
- expect(routes.map((r) => r.path).sort()).toEqual([
594
- "/dashboard",
595
- "/dashboard/settings",
596
- "/dashboard/users",
597
- ]);
598
- cleanup(repo);
599
- });
600
- it("composes relative child paths under a root layout route", () => {
601
- // Canonical RR v6 shape: a path-bearing parent that itself has children,
602
- // with relative child paths. The parent must not count its own path twice.
603
- const repo = makeTmpRepo([
604
- {
605
- path: "src/App.tsx",
606
- content: `
607
- import { Routes, Route } from 'react-router-dom';
608
- import Layout from './Layout';
609
- import Dashboard from './pages/Dashboard';
610
- import Settings from './pages/Settings';
611
-
612
- export default function App() {
613
- return (
614
- <Routes>
615
- <Route path="/" element={<Layout />}>
616
- <Route path="dashboard" element={<Dashboard />}>
617
- <Route path="settings" element={<Settings />} />
618
- </Route>
619
- </Route>
620
- </Routes>
621
- );
622
- }
623
- `,
624
- },
625
- ]);
626
- const routes = extractSourceRoutes(repo);
627
- expect(routes.find((r) => r.componentName === "Dashboard").path).toBe("/dashboard");
628
- expect(routes.find((r) => r.componentName === "Settings").path).toBe("/dashboard/settings");
629
- cleanup(repo);
630
- });
631
- it("resolves a JSX index route to its parent's path", () => {
632
- // <Route index> has no path attribute; it renders at the parent's path.
633
- const repo = makeTmpRepo([
634
- {
635
- path: "src/App.tsx",
636
- content: `
637
- import { Routes, Route } from 'react-router-dom';
638
- import Dashboard from './pages/Dashboard';
639
- import DashboardHome from './pages/DashboardHome';
640
-
641
- export default function App() {
642
- return (
643
- <Routes>
644
- <Route path="/dashboard" element={<Dashboard />}>
645
- <Route index element={<DashboardHome />} />
646
- </Route>
647
- </Routes>
648
- );
649
- }
650
- `,
651
- },
652
- ]);
653
- const routes = extractSourceRoutes(repo);
654
- const home = routes.find((r) => r.componentName === "DashboardHome");
655
- expect(home).toBeDefined();
656
- expect(home.path).toBe("/dashboard");
657
- cleanup(repo);
658
- });
659
- it("extracts createBrowserRouter data-router routes with composed nested paths", () => {
660
- // The data-router API uses object literals with `element:` (JSX) and nests
661
- // via `children:` — neither the JSX-element path nor the Vue object path
662
- // handled these, so the whole tree was missed (root-only fallback).
663
- const repo = makeTmpRepo([
664
- {
665
- path: "src/router.tsx",
666
- content: `
667
- import { createBrowserRouter } from 'react-router-dom';
668
- import Root from './Root';
669
- import Dashboard from './pages/Dashboard';
670
- import Settings from './pages/Settings';
671
- import Profile from './pages/Profile';
672
-
673
- export const router = createBrowserRouter([
674
- {
675
- path: '/',
676
- element: <Root />,
677
- children: [
678
- { path: 'dashboard', element: <Dashboard /> },
679
- {
680
- path: 'settings',
681
- element: <Settings />,
682
- children: [
683
- { path: 'profile', element: <Profile /> },
684
- ],
685
- },
686
- ],
687
- },
688
- ]);
689
- `,
690
- },
691
- ]);
692
- const routes = extractSourceRoutes(repo);
693
- expect(routes.map((r) => r.path).sort()).toEqual([
694
- "/",
695
- "/dashboard",
696
- "/settings",
697
- "/settings/profile",
698
- ]);
699
- expect(routes.find((r) => r.path === "/settings/profile").componentName).toBe("Profile");
700
- cleanup(repo);
701
- });
702
- it("extracts createStaticRouter (SSR) routes with composed nested paths", () => {
703
- // SSR apps build routes with createStaticRouter — same route-array shape as
704
- // createBrowserRouter, so nested composition must work identically.
705
- const repo = makeTmpRepo([
706
- {
707
- path: "src/router.tsx",
708
- content: `
709
- import { createStaticRouter } from 'react-router-dom/server';
710
- import Root from './Root';
711
- import Reports from './pages/Reports';
712
- import Detail from './pages/Detail';
713
-
714
- export const router = createStaticRouter([
715
- {
716
- path: '/',
717
- element: <Root />,
718
- children: [
719
- { path: 'reports', element: <Reports />,
720
- children: [
721
- { path: ':id', element: <Detail /> },
722
- ],
723
- },
724
- ],
725
- },
726
- ]);
727
- `,
728
- },
729
- ]);
730
- const routes = extractSourceRoutes(repo);
731
- expect(routes.map((r) => r.path).sort()).toEqual([
732
- "/",
733
- "/reports",
734
- "/reports/:id",
735
- ]);
736
- cleanup(repo);
737
- });
738
- });