@atlaspack/inspector 0.0.19-canary.3998

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 (235) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +126 -0
  3. package/bin/atlaspack-inspector.js +2 -0
  4. package/lib/backend/cli.js +4 -0
  5. package/lib/backend/config/logger.js +16 -0
  6. package/lib/backend/config/middleware/cacheDataMiddleware.js +60 -0
  7. package/lib/backend/config/middleware/errorHandlingMiddleware.js +17 -0
  8. package/lib/backend/config/middleware/errorHandlingMiddleware.test.js +44 -0
  9. package/lib/backend/config/middleware/loggingMiddleware.js +22 -0
  10. package/lib/backend/controllers/BundleGraphController.js +42 -0
  11. package/lib/backend/controllers/CacheDataController.js +143 -0
  12. package/lib/backend/controllers/FrontendAssetsController.js +61 -0
  13. package/lib/backend/controllers/TreeMapController.js +108 -0
  14. package/lib/backend/controllers/mcp/InspectorMCP.js +231 -0
  15. package/lib/backend/controllers/mcp/InspectorMCPController.js +16 -0
  16. package/lib/backend/errors/HTTPError.js +16 -0
  17. package/lib/backend/errors/HTTPError.test.js +21 -0
  18. package/lib/backend/index.js +177 -0
  19. package/lib/backend/services/AnalyticsService.js +86 -0
  20. package/lib/backend/services/LazyValue.js +33 -0
  21. package/lib/backend/services/LazyValue.test.js +12 -0
  22. package/lib/backend/services/buildJsonGraph.js +86 -0
  23. package/lib/backend/services/buildTreemap.js +140 -0
  24. package/lib/backend/services/buildTreemapBundle.test.js +298 -0
  25. package/lib/backend/services/findSourceCodeUrl.js +107 -0
  26. package/lib/backend/services/findSourceCodeUrl.test.js +216 -0
  27. package/lib/backend/services/getCacheStats.js +36 -0
  28. package/lib/backend/services/getCacheStats.test.js +162 -0
  29. package/lib/backend/services/getDisplayName.js +18 -0
  30. package/lib/backend/services/getDisplayName.test.js +71 -0
  31. package/lib/backend/services/loadCacheData.js +209 -0
  32. package/lib/backend/services/loadCacheData.test.js +79 -0
  33. package/lib/backend/testing/TemporaryDirectory.js +46 -0
  34. package/lib/frontend/node_modules/@atlaspack/packager-js/lib/dev-prelude.js +145 -0
  35. package/lib/frontend/node_modules/@atlaspack/packager-js/src/dev-prelude.js +145 -0
  36. package/package.json +75 -0
  37. package/screenshots/bottom-up.png +0 -0
  38. package/screenshots/cache-inspector.png +0 -0
  39. package/screenshots/treemap.png +0 -0
  40. package/src/backend/README.md +14 -0
  41. package/src/backend/cli.ts +3 -0
  42. package/src/backend/config/logger.ts +14 -0
  43. package/src/backend/config/middleware/cacheDataMiddleware.ts +94 -0
  44. package/src/backend/config/middleware/errorHandlingMiddleware.test.ts +52 -0
  45. package/src/backend/config/middleware/errorHandlingMiddleware.ts +20 -0
  46. package/src/backend/config/middleware/loggingMiddleware.ts +24 -0
  47. package/src/backend/controllers/BundleGraphController.ts +73 -0
  48. package/src/backend/controllers/CacheDataController.ts +187 -0
  49. package/src/backend/controllers/FrontendAssetsController.ts +28 -0
  50. package/src/backend/controllers/TreeMapController.ts +143 -0
  51. package/src/backend/controllers/mcp/InspectorMCP.ts +311 -0
  52. package/src/backend/controllers/mcp/InspectorMCPController.ts +17 -0
  53. package/src/backend/errors/HTTPError.test.ts +19 -0
  54. package/src/backend/errors/HTTPError.ts +14 -0
  55. package/src/backend/globals.d.ts +9 -0
  56. package/src/backend/index.ts +271 -0
  57. package/src/backend/services/AnalyticsService.ts +118 -0
  58. package/src/backend/services/LazyValue.test.ts +13 -0
  59. package/src/backend/services/LazyValue.ts +29 -0
  60. package/src/backend/services/buildJsonGraph.ts +124 -0
  61. package/src/backend/services/buildTreemap.ts +273 -0
  62. package/src/backend/services/buildTreemapBundle.test.ts +348 -0
  63. package/src/backend/services/findSourceCodeUrl.test.ts +228 -0
  64. package/src/backend/services/findSourceCodeUrl.ts +146 -0
  65. package/src/backend/services/getCacheStats.test.ts +169 -0
  66. package/src/backend/services/getCacheStats.ts +46 -0
  67. package/src/backend/services/getDisplayName.test.ts +84 -0
  68. package/src/backend/services/getDisplayName.ts +20 -0
  69. package/src/backend/services/loadCacheData.test.ts +101 -0
  70. package/src/backend/services/loadCacheData.ts +294 -0
  71. package/src/backend/testing/TemporaryDirectory.ts +50 -0
  72. package/src/frontend/.atlaspackrc +4 -0
  73. package/src/frontend/.eslintrc.json +19 -0
  74. package/src/frontend/dist/atlassian-dark-brand-refresh.91b786da.js +2 -0
  75. package/src/frontend/dist/atlassian-dark-brand-refresh.91b786da.js.map +1 -0
  76. package/src/frontend/dist/atlassian-dark-future.59ebadca.js +2 -0
  77. package/src/frontend/dist/atlassian-dark-future.59ebadca.js.map +1 -0
  78. package/src/frontend/dist/atlassian-dark-increased-contrast.ff6775f2.js +2 -0
  79. package/src/frontend/dist/atlassian-dark-increased-contrast.ff6775f2.js.map +1 -0
  80. package/src/frontend/dist/atlassian-dark.ad679134.js +2 -0
  81. package/src/frontend/dist/atlassian-dark.ad679134.js.map +1 -0
  82. package/src/frontend/dist/atlassian-legacy-dark.8aa27f7f.js +2 -0
  83. package/src/frontend/dist/atlassian-legacy-dark.8aa27f7f.js.map +1 -0
  84. package/src/frontend/dist/atlassian-legacy-light.2eb372ce.js +2 -0
  85. package/src/frontend/dist/atlassian-legacy-light.2eb372ce.js.map +1 -0
  86. package/src/frontend/dist/atlassian-light-brand-refresh.fadcab0a.js +2 -0
  87. package/src/frontend/dist/atlassian-light-brand-refresh.fadcab0a.js.map +1 -0
  88. package/src/frontend/dist/atlassian-light-future.612afe8a.js +2 -0
  89. package/src/frontend/dist/atlassian-light-future.612afe8a.js.map +1 -0
  90. package/src/frontend/dist/atlassian-light-increased-contrast.7161cd79.js +2 -0
  91. package/src/frontend/dist/atlassian-light-increased-contrast.7161cd79.js.map +1 -0
  92. package/src/frontend/dist/atlassian-light.bc343d4c.js +2 -0
  93. package/src/frontend/dist/atlassian-light.bc343d4c.js.map +1 -0
  94. package/src/frontend/dist/atlassian-shape.b92d69c0.js +2 -0
  95. package/src/frontend/dist/atlassian-shape.b92d69c0.js.map +1 -0
  96. package/src/frontend/dist/atlassian-spacing.60ddd8e7.js +2 -0
  97. package/src/frontend/dist/atlassian-spacing.60ddd8e7.js.map +1 -0
  98. package/src/frontend/dist/atlassian-typography-adg3.f88947f6.js +2 -0
  99. package/src/frontend/dist/atlassian-typography-adg3.f88947f6.js.map +1 -0
  100. package/src/frontend/dist/atlassian-typography-modernized.42016c51.js +2 -0
  101. package/src/frontend/dist/atlassian-typography-modernized.42016c51.js.map +1 -0
  102. package/src/frontend/dist/atlassian-typography-refreshed.ec0d111b.js +2 -0
  103. package/src/frontend/dist/atlassian-typography-refreshed.ec0d111b.js.map +1 -0
  104. package/src/frontend/dist/atlassian-typography.66d7e8f4.js +2 -0
  105. package/src/frontend/dist/atlassian-typography.66d7e8f4.js.map +1 -0
  106. package/src/frontend/dist/badge-light.7e55986a.png +0 -0
  107. package/src/frontend/dist/custom-theme.4680282a.js +2 -0
  108. package/src/frontend/dist/custom-theme.4680282a.js.map +1 -0
  109. package/src/frontend/dist/drag-handle.136830d3.js +2 -0
  110. package/src/frontend/dist/drag-handle.136830d3.js.map +1 -0
  111. package/src/frontend/dist/drag-handle.63bdb345.css +2 -0
  112. package/src/frontend/dist/drag-handle.63bdb345.css.map +1 -0
  113. package/src/frontend/dist/index.a41fafce.css +2 -0
  114. package/src/frontend/dist/index.a41fafce.css.map +1 -0
  115. package/src/frontend/dist/index.a4ce2b12.js +28 -0
  116. package/src/frontend/dist/index.a4ce2b12.js.map +1 -0
  117. package/src/frontend/dist/index.html +1 -0
  118. package/src/frontend/dist/index.runtime.a729d997.js +2 -0
  119. package/src/frontend/dist/index.runtime.a729d997.js.map +1 -0
  120. package/src/frontend/dist/refractor.2c1fd9a1.js +2 -0
  121. package/src/frontend/dist/refractor.2c1fd9a1.js.map +1 -0
  122. package/src/frontend/index.html +11 -0
  123. package/src/frontend/jest.config.js +16 -0
  124. package/src/frontend/package.json +64 -0
  125. package/src/frontend/src/APIError.test.ts +72 -0
  126. package/src/frontend/src/APIError.tsx +29 -0
  127. package/src/frontend/src/AppRoutes.tsx +56 -0
  128. package/src/frontend/src/hack-feature-flags.ts +6 -0
  129. package/src/frontend/src/main.tsx +50 -0
  130. package/src/frontend/src/test/stubCssModule.js +1 -0
  131. package/src/frontend/src/ui/App.module.css +122 -0
  132. package/src/frontend/src/ui/App.module.css.d.ts +8 -0
  133. package/src/frontend/src/ui/AppLayout/AppLayout.tsx +26 -0
  134. package/src/frontend/src/ui/AppLayout/SidebarNavigation/LinkItem.tsx +26 -0
  135. package/src/frontend/src/ui/AppLayout/SidebarNavigation/SidebarNavigation.tsx +45 -0
  136. package/src/frontend/src/ui/AppLayout/TopNavigation/Logo.module.css +12 -0
  137. package/src/frontend/src/ui/AppLayout/TopNavigation/Logo.module.css.d.ts +4 -0
  138. package/src/frontend/src/ui/AppLayout/TopNavigation/Logo.tsx +11 -0
  139. package/src/frontend/src/ui/AppLayout/TopNavigation/TopNavigation.module.css +14 -0
  140. package/src/frontend/src/ui/AppLayout/TopNavigation/TopNavigation.module.css.d.ts +3 -0
  141. package/src/frontend/src/ui/AppLayout/TopNavigation/TopNavigation.tsx +45 -0
  142. package/src/frontend/src/ui/AppLayout/TopNavigation/badge-light.png +0 -0
  143. package/src/frontend/src/ui/AppLayout/TopNavigation/logo-light.png +0 -0
  144. package/src/frontend/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.module.css +9 -0
  145. package/src/frontend/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.module.css.d.ts +3 -0
  146. package/src/frontend/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.test.tsx +15 -0
  147. package/src/frontend/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.tsx +14 -0
  148. package/src/frontend/src/ui/app/StatsPage.tsx +77 -0
  149. package/src/frontend/src/ui/app/cache/CacheKeysIndexPage.tsx +13 -0
  150. package/src/frontend/src/ui/app/cache/CacheKeysPage.module.css +11 -0
  151. package/src/frontend/src/ui/app/cache/CacheKeysPage.module.css.d.ts +4 -0
  152. package/src/frontend/src/ui/app/cache/CacheKeysPage.tsx +23 -0
  153. package/src/frontend/src/ui/app/cache/[key]/CacheValuePage.tsx +40 -0
  154. package/src/frontend/src/ui/app/cache/ui/CacheKeyList.module.css +40 -0
  155. package/src/frontend/src/ui/app/cache/ui/CacheKeyList.module.css.d.ts +7 -0
  156. package/src/frontend/src/ui/app/cache/ui/CacheKeyList.tsx +187 -0
  157. package/src/frontend/src/ui/app/cache-invalidation/CacheInvalidationPage.tsx +22 -0
  158. package/src/frontend/src/ui/app/cache-invalidation/[fileId]/CacheInvalidationFilePage.tsx +22 -0
  159. package/src/frontend/src/ui/app/cache-invalidation/ui/CacheFileList.module.css +40 -0
  160. package/src/frontend/src/ui/app/cache-invalidation/ui/CacheFileList.module.css.d.ts +7 -0
  161. package/src/frontend/src/ui/app/cache-invalidation/ui/CacheFileList.tsx +185 -0
  162. package/src/frontend/src/ui/app/treemap/BottomPanelResizeState.test.ts +25 -0
  163. package/src/frontend/src/ui/app/treemap/BottomPanelResizeState.tsx +48 -0
  164. package/src/frontend/src/ui/app/treemap/FoamTreemapPage.module.css +24 -0
  165. package/src/frontend/src/ui/app/treemap/FoamTreemapPage.module.css.d.ts +6 -0
  166. package/src/frontend/src/ui/app/treemap/FoamTreemapPage.tsx +47 -0
  167. package/src/frontend/src/ui/app/treemap/controllers/RelatedBundlesController.tsx +41 -0
  168. package/src/frontend/src/ui/app/treemap/controllers/UrlFocusController.tsx +33 -0
  169. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/BottomPanel.module.css +24 -0
  170. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/BottomPanel.module.css.d.ts +5 -0
  171. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/BottomPanel.tsx +24 -0
  172. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.module.css +13 -0
  173. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.module.css.d.ts +5 -0
  174. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.tsx +53 -0
  175. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/AssetTable.tsx +135 -0
  176. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.module.css +7 -0
  177. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.module.css.d.ts +3 -0
  178. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.tsx +123 -0
  179. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableModel.tsx +18 -0
  180. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.module.css +20 -0
  181. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.module.css.d.ts +6 -0
  182. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.tsx +79 -0
  183. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/getFileURL.test.ts +19 -0
  184. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/getFileURL.ts +24 -0
  185. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.module.css +20 -0
  186. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.module.css.d.ts +5 -0
  187. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.tsx +42 -0
  188. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.module.css +29 -0
  189. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.module.css.d.ts +6 -0
  190. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.tsx +107 -0
  191. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.module.css +7 -0
  192. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.module.css.d.ts +3 -0
  193. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.tsx +20 -0
  194. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/SourceCodeURL.tsx +5 -0
  195. package/src/frontend/src/ui/app/treemap/ui/BundleGraphRenderer.module.css +13 -0
  196. package/src/frontend/src/ui/app/treemap/ui/BundleGraphRenderer.module.css.d.ts +4 -0
  197. package/src/frontend/src/ui/app/treemap/ui/BundleGraphRenderer.tsx +95 -0
  198. package/src/frontend/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.module.css +6 -0
  199. package/src/frontend/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.module.css.d.ts +3 -0
  200. package/src/frontend/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.tsx +49 -0
  201. package/src/frontend/src/ui/app/treemap/ui/SigmaGraph.module.css +5 -0
  202. package/src/frontend/src/ui/app/treemap/ui/SigmaGraph.module.css.d.ts +3 -0
  203. package/src/frontend/src/ui/app/treemap/ui/SigmaGraph.tsx +80 -0
  204. package/src/frontend/src/ui/app/treemap/ui/Treemap.tsx +14 -0
  205. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.module.css +32 -0
  206. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.module.css.d.ts +5 -0
  207. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.tsx +24 -0
  208. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.module.css +14 -0
  209. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.module.css.d.ts +4 -0
  210. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.tsx +271 -0
  211. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.module.css +15 -0
  212. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.module.css.d.ts +4 -0
  213. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.tsx +111 -0
  214. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/controllers/useStableCallback.test.ts +27 -0
  215. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/controllers/useStableCallback.ts +21 -0
  216. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/useMouseMoveController.ts +20 -0
  217. package/src/frontend/src/ui/globals.css +26 -0
  218. package/src/frontend/src/ui/globals.css.d.ts +1 -0
  219. package/src/frontend/src/ui/globals.d.ts +9 -0
  220. package/src/frontend/src/ui/model/ViewModel.test.ts +31 -0
  221. package/src/frontend/src/ui/model/ViewModel.ts +62 -0
  222. package/src/frontend/src/ui/not-found/NotFoundPage.module.css +7 -0
  223. package/src/frontend/src/ui/not-found/NotFoundPage.module.css.d.ts +3 -0
  224. package/src/frontend/src/ui/not-found/NotFoundPage.tsx +9 -0
  225. package/src/frontend/src/ui/types/Graph.tsx +12 -0
  226. package/src/frontend/src/ui/util/ErrorBoundary.module.css +3 -0
  227. package/src/frontend/src/ui/util/ErrorBoundary.module.css.d.ts +3 -0
  228. package/src/frontend/src/ui/util/ErrorBoundary.test.tsx +65 -0
  229. package/src/frontend/src/ui/util/ErrorBoundary.tsx +75 -0
  230. package/src/frontend/src/ui/util/colorPalette.tsx +122 -0
  231. package/src/frontend/src/ui/util/formatBytes.test.ts +13 -0
  232. package/src/frontend/src/ui/util/formatBytes.tsx +9 -0
  233. package/src/frontend/src/ui/util/getRandomDarkerColor.tsx +31 -0
  234. package/src/frontend/tsconfig.json +12 -0
  235. package/src/frontend/yarn.lock +0 -0
@@ -0,0 +1,298 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const assert_1 = __importDefault(require("assert"));
40
+ const sinon = __importStar(require("sinon"));
41
+ const fs_1 = __importDefault(require("fs"));
42
+ const path_1 = __importDefault(require("path"));
43
+ const buildTreemap_1 = require("./buildTreemap");
44
+ jest.mock('../config/logger');
45
+ describe('buildTreemapBundle', function () {
46
+ let sandbox;
47
+ let mockBundleGraph;
48
+ let mockNode;
49
+ let mockWriteBundleRequestsByBundleId;
50
+ beforeEach(() => {
51
+ sandbox = sinon.createSandbox();
52
+ // Mock fs.statSync
53
+ sandbox.stub(fs_1.default, 'statSync').returns({ size: 1024 });
54
+ // Mock path.join
55
+ sandbox
56
+ .stub(path_1.default, 'join')
57
+ .callsFake((...paths) => paths.join('/'));
58
+ // Mock bundle node
59
+ mockNode = {
60
+ id: 'bundle123',
61
+ type: 'bundle',
62
+ value: {
63
+ displayName: 'main.js',
64
+ },
65
+ };
66
+ // Mock bundle graph with traverseAssets method
67
+ mockBundleGraph = {
68
+ traverseAssets: sandbox.stub(),
69
+ };
70
+ // Mock write bundle requests map
71
+ mockWriteBundleRequestsByBundleId = new Map([
72
+ [
73
+ 'bundle123',
74
+ {
75
+ result: {
76
+ bundleId: 'bundle123',
77
+ filePath: 'dist/main.js',
78
+ },
79
+ },
80
+ ],
81
+ ]);
82
+ });
83
+ afterEach(() => {
84
+ sandbox.restore();
85
+ });
86
+ it('should build treemap bundle with correct basic properties', function () {
87
+ // Setup mock assets
88
+ const mockAssets = [
89
+ {
90
+ filePath: '/src/index.js',
91
+ stats: { size: 100 },
92
+ },
93
+ {
94
+ filePath: '/src/utils.js',
95
+ stats: { size: 50 },
96
+ },
97
+ ];
98
+ // Mock traverseAssets to call callback with each asset
99
+ mockBundleGraph.traverseAssets.callsFake((bundleValue, callback) => {
100
+ mockAssets.forEach(callback);
101
+ });
102
+ const result = (0, buildTreemap_1.buildTreemapBundle)({
103
+ writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
104
+ node: mockNode,
105
+ projectRoot: '/project',
106
+ repositoryRoot: '/project',
107
+ bundleGraph: mockBundleGraph,
108
+ });
109
+ assert_1.default.equal(result.id, 'bundle123');
110
+ assert_1.default.equal(result.displayName, 'main.js');
111
+ assert_1.default.equal(result.bundle, mockNode);
112
+ assert_1.default.equal(result.size, 1024); // from mocked fs.statSync
113
+ assert_1.default.equal(result.filePath, 'dist/main.js');
114
+ (0, assert_1.default)(result.assetTree);
115
+ });
116
+ it('should handle missing write bundle request', function () {
117
+ const emptyMap = new Map();
118
+ mockBundleGraph.traverseAssets.callsFake((_bundleValue, _callback) => {
119
+ // No assets
120
+ });
121
+ const result = (0, buildTreemap_1.buildTreemapBundle)({
122
+ writeBundleRequestsByBundleId: emptyMap,
123
+ node: mockNode,
124
+ projectRoot: '/project',
125
+ repositoryRoot: '/project',
126
+ bundleGraph: mockBundleGraph,
127
+ });
128
+ assert_1.default.equal(result.size, 0);
129
+ assert_1.default.equal(result.filePath, '');
130
+ });
131
+ it('should build correct asset tree structure', function () {
132
+ const mockAssets = [
133
+ {
134
+ filePath: 'src/components/Button.js',
135
+ stats: { size: 100 },
136
+ },
137
+ {
138
+ filePath: 'src/utils/helpers.js',
139
+ stats: { size: 50 },
140
+ },
141
+ ];
142
+ mockBundleGraph.traverseAssets.callsFake((bundleValue, callback) => {
143
+ mockAssets.forEach(callback);
144
+ });
145
+ const result = (0, buildTreemap_1.buildTreemapBundle)({
146
+ writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
147
+ node: mockNode,
148
+ projectRoot: '/project',
149
+ repositoryRoot: '/project',
150
+ bundleGraph: mockBundleGraph,
151
+ });
152
+ // Check that tree structure exists
153
+ (0, assert_1.default)(result.assetTree.children.src);
154
+ assert_1.default.equal(result.assetTree.path, '');
155
+ assert_1.default.equal(result.assetTree.children.src.path, '/src');
156
+ // Check components subdirectory exists
157
+ (0, assert_1.default)(result.assetTree.children.src.children.components);
158
+ assert_1.default.equal(result.assetTree.children.src.children.components.path, '/src/components');
159
+ // Check utils subdirectory exists
160
+ (0, assert_1.default)(result.assetTree.children.src.children.utils);
161
+ assert_1.default.equal(result.assetTree.children.src.children.utils.path, '/src/utils');
162
+ assert_1.default.equal(result.assetTree.size, 150);
163
+ assert_1.default.equal(result.assetTree.children.src.size, 150);
164
+ assert_1.default.equal(result.assetTree.children.src.children.components.size, 100);
165
+ assert_1.default.equal(result.assetTree.children.src.children.utils.size, 50);
166
+ });
167
+ it('should handle assets with same directory correctly', function () {
168
+ const mockAssets = [
169
+ {
170
+ filePath: 'lib/module1.js',
171
+ stats: { size: 100 },
172
+ },
173
+ {
174
+ filePath: 'lib/module2.js',
175
+ stats: { size: 200 },
176
+ },
177
+ ];
178
+ mockBundleGraph.traverseAssets.callsFake((bundleValue, callback) => {
179
+ mockAssets.forEach(callback);
180
+ });
181
+ const result = (0, buildTreemap_1.buildTreemapBundle)({
182
+ writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
183
+ node: mockNode,
184
+ projectRoot: '/project',
185
+ repositoryRoot: '/project',
186
+ bundleGraph: mockBundleGraph,
187
+ });
188
+ // lib directory should contain total of all files under it
189
+ assert_1.default.equal(result.assetTree.children.lib.size, 300); // 100 + 200
190
+ assert_1.default.equal(result.assetTree.children.lib.children['module1.js'].size, 100);
191
+ assert_1.default.equal(result.assetTree.children.lib.children['module2.js'].size, 200);
192
+ });
193
+ it('should handle empty assets array', function () {
194
+ mockBundleGraph.traverseAssets.callsFake((_bundleValue, _callback) => {
195
+ // No assets
196
+ });
197
+ const result = (0, buildTreemap_1.buildTreemapBundle)({
198
+ writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
199
+ node: mockNode,
200
+ projectRoot: '/project',
201
+ repositoryRoot: '/project',
202
+ bundleGraph: mockBundleGraph,
203
+ });
204
+ assert_1.default.equal(result.assetTree.size, 0);
205
+ assert_1.default.deepEqual(result.assetTree.children, {});
206
+ });
207
+ it('should handle file path without extension', function () {
208
+ const mockAssets = [
209
+ {
210
+ filePath: 'src/config',
211
+ stats: { size: 25 },
212
+ },
213
+ ];
214
+ mockBundleGraph.traverseAssets.callsFake((_bundleValue, callback) => {
215
+ mockAssets.forEach(callback);
216
+ });
217
+ const result = (0, buildTreemap_1.buildTreemapBundle)({
218
+ writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
219
+ node: mockNode,
220
+ projectRoot: '/project',
221
+ repositoryRoot: '/project',
222
+ bundleGraph: mockBundleGraph,
223
+ });
224
+ assert_1.default.equal(result.assetTree.children.src.children.config.size, 25);
225
+ });
226
+ it('should call traverseAssets with correct bundle value', function () {
227
+ mockBundleGraph.traverseAssets.callsFake((_bundleValue, _callback) => {
228
+ // Just verify it was called
229
+ });
230
+ (0, buildTreemap_1.buildTreemapBundle)({
231
+ writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
232
+ node: mockNode,
233
+ projectRoot: '/project',
234
+ repositoryRoot: '/project',
235
+ bundleGraph: mockBundleGraph,
236
+ });
237
+ (0, assert_1.default)(mockBundleGraph.traverseAssets.calledOnce);
238
+ (0, assert_1.default)(mockBundleGraph.traverseAssets.calledWith(mockNode.value));
239
+ });
240
+ it('should calculate directory sizes correctly', function () {
241
+ // Test case matching user's example:
242
+ // lib/child/a.js - 10
243
+ // lib/other/b.js - 10
244
+ // lib/other/c.js - 10
245
+ const mockAssets = [
246
+ {
247
+ filePath: 'lib/child/a.js',
248
+ stats: { size: 10 },
249
+ },
250
+ {
251
+ filePath: 'lib/other/b.js',
252
+ stats: { size: 10 },
253
+ },
254
+ {
255
+ filePath: 'lib/other/c.js',
256
+ stats: { size: 10 },
257
+ },
258
+ ];
259
+ mockBundleGraph.traverseAssets.callsFake((bundleValue, callback) => {
260
+ mockAssets.forEach(callback);
261
+ });
262
+ const result = (0, buildTreemap_1.buildTreemapBundle)({
263
+ writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
264
+ node: mockNode,
265
+ projectRoot: '/project',
266
+ repositoryRoot: '/project',
267
+ bundleGraph: mockBundleGraph,
268
+ });
269
+ // Root should contain total of all files
270
+ // assert.equal(result.assetTree.size, 30); // 10+10+10
271
+ // lib directory should contain total of all files under lib
272
+ assert_1.default.equal(result.assetTree.children.lib.size, 30); // 10+10+10
273
+ // lib/child should contain only a.js
274
+ assert_1.default.equal(result.assetTree.children.lib.children.child.size, 10); // 10
275
+ // lib/other should contain b.js + c.js
276
+ assert_1.default.equal(result.assetTree.children.lib.children.other.size, 20); // 10+10
277
+ // Individual files should have their own sizes
278
+ assert_1.default.equal(result.assetTree.children.lib.children.child.children['a.js'].size, 10);
279
+ assert_1.default.equal(result.assetTree.children.lib.children.other.children['b.js'].size, 10);
280
+ assert_1.default.equal(result.assetTree.children.lib.children.other.children['c.js'].size, 10);
281
+ });
282
+ it('should handle fs.statSync errors gracefully', function () {
283
+ // Make fs.statSync throw an error
284
+ fs_1.default.statSync.throws(new Error('File not found'));
285
+ mockBundleGraph.traverseAssets.callsFake((_bundleValue, _callback) => {
286
+ // No assets
287
+ });
288
+ assert_1.default.doesNotThrow(() => {
289
+ (0, buildTreemap_1.buildTreemapBundle)({
290
+ writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
291
+ node: mockNode,
292
+ projectRoot: '/project',
293
+ repositoryRoot: '/project',
294
+ bundleGraph: mockBundleGraph,
295
+ });
296
+ }, Error);
297
+ });
298
+ });
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.findRoot = findRoot;
7
+ exports.findRepositoryRoot = findRepositoryRoot;
8
+ exports.findProjectRoot = findProjectRoot;
9
+ exports.findSourceCodeURL = findSourceCodeURL;
10
+ const path_1 = __importDefault(require("path"));
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const child_process_1 = __importDefault(require("child_process"));
13
+ const PROJECT_ROOT_DIRS = [
14
+ '.parcelrc',
15
+ '.atlaspackrc',
16
+ 'yarn.lock',
17
+ 'package-lock.json',
18
+ 'pnpm-lock.yaml',
19
+ ];
20
+ /**
21
+ * Finds a root directory that contains a marker directory.
22
+ *
23
+ * @param target - The target directory to search from.
24
+ * @param candidate - The marker directory to search for.
25
+ */
26
+ function findRoot(target, candidate) {
27
+ let projectRoot = path_1.default.resolve(process.cwd(), target);
28
+ let exists = false;
29
+ while (projectRoot !== '/' && projectRoot !== '.') {
30
+ if (fs_1.default.existsSync(path_1.default.join(projectRoot, candidate))) {
31
+ exists = true;
32
+ break;
33
+ }
34
+ projectRoot = path_1.default.dirname(projectRoot);
35
+ }
36
+ if (!exists) {
37
+ return null;
38
+ }
39
+ return projectRoot;
40
+ }
41
+ /**
42
+ * Finds a root directory that contains a `.git` directory.
43
+ * This is not quite matching `@atlaspack/core`'s logic.
44
+ *
45
+ * @param target - The target directory to search from.
46
+ */
47
+ function findRepositoryRoot(target) {
48
+ return findRoot(target, '.git');
49
+ }
50
+ /**
51
+ * Finds a root directory that contains a project root directory.
52
+ *
53
+ * @param target - The target directory to search from.
54
+ */
55
+ function findProjectRoot(target) {
56
+ for (const candidate of PROJECT_ROOT_DIRS) {
57
+ const root = findRoot(target, candidate);
58
+ if (root) {
59
+ return root;
60
+ }
61
+ }
62
+ return null;
63
+ }
64
+ /**
65
+ * Based on the directory path, find a source code URL for this project.
66
+ *
67
+ * This is based on parsing `git remote` URLs.
68
+ *
69
+ * Both SSH and HTTP URLs should be supported for both GitHub and BitBucket
70
+ * Cloud.
71
+ *
72
+ * If a repository has multiple remotes, the first GitHub/BitBucket remote
73
+ * will be used.
74
+ *
75
+ * This might not work for repositories using BitBucket Server, or mirror
76
+ * URLs as remotes.
77
+ */
78
+ function findSourceCodeURL(target) {
79
+ const repositoryRoot = findRepositoryRoot(target);
80
+ const projectRoot = findProjectRoot(target);
81
+ if (!repositoryRoot || !projectRoot) {
82
+ return null;
83
+ }
84
+ const remotes = child_process_1.default
85
+ .execSync('git remote -v', {
86
+ cwd: repositoryRoot,
87
+ })
88
+ .toString()
89
+ .split('\n')
90
+ .filter(Boolean)
91
+ .map((line) => line.split('\t'))
92
+ .map(([name, url]) => ({ name, url }));
93
+ const remote = remotes.find(({ url }) => url.includes('bitbucket.org') || url.includes('github.com'))?.url;
94
+ if (!remote) {
95
+ return null;
96
+ }
97
+ const remoteUrl = remote.split(' ')[0];
98
+ const type = remoteUrl.includes('bitbucket.org') ? 'bitbucket' : 'github';
99
+ // get owner and repo from HTTP or SSH urls
100
+ const regex = /^(?:https?:\/\/|git@)(github|bitbucket)\.(com|org)[:/]([^/\s.]+)\/([^/\s.]+)(\.git)?/;
101
+ const match = remoteUrl.match(regex);
102
+ if (!match) {
103
+ return null;
104
+ }
105
+ const [, , , owner, repo] = match;
106
+ return { type, owner, repo };
107
+ }
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const assert_1 = __importDefault(require("assert"));
40
+ const sinon = __importStar(require("sinon"));
41
+ const path_1 = __importDefault(require("path"));
42
+ const fs_1 = __importDefault(require("fs"));
43
+ const child_process_1 = __importDefault(require("child_process"));
44
+ const findSourceCodeUrl_1 = require("./findSourceCodeUrl");
45
+ describe('findSourceCodeUrl', function () {
46
+ let sandbox;
47
+ beforeEach(() => {
48
+ sandbox = sinon.createSandbox();
49
+ });
50
+ afterEach(() => {
51
+ sandbox.restore();
52
+ });
53
+ describe('findProjectRoot', function () {
54
+ it('should find project root when .git directory exists', function () {
55
+ const mockTarget = '/path/to/project/subdir';
56
+ const mockResolvedPath = '/resolved/path/to/project/subdir';
57
+ const mockProjectRoot = '/resolved/path/to/project';
58
+ sandbox.stub(path_1.default, 'resolve').returns(mockResolvedPath);
59
+ sandbox.stub(path_1.default, 'dirname').returns(mockProjectRoot);
60
+ sandbox.stub(path_1.default, 'join').returns('/resolved/path/to/project/.git');
61
+ sandbox.stub(fs_1.default, 'existsSync').returns(true);
62
+ const result = (0, findSourceCodeUrl_1.findProjectRoot)(mockTarget);
63
+ assert_1.default.equal(result, mockResolvedPath);
64
+ (0, assert_1.default)(path_1.default.resolve.calledWith(process.cwd(), mockTarget));
65
+ (0, assert_1.default)(fs_1.default.existsSync.calledWith('/resolved/path/to/project/.git'));
66
+ });
67
+ it('should return null when no .git directory is found', function () {
68
+ const mockTarget = '/path/to/project';
69
+ const mockResolvedPath = '/resolved/path/to/project';
70
+ sandbox.stub(path_1.default, 'resolve').returns(mockResolvedPath);
71
+ sandbox.stub(path_1.default, 'dirname').callsFake((p) => {
72
+ if (p === mockResolvedPath)
73
+ return '/resolved/path/to';
74
+ if (p === '/resolved/path/to')
75
+ return '/resolved/path';
76
+ if (p === '/resolved/path')
77
+ return '/resolved';
78
+ if (p === '/resolved')
79
+ return '/';
80
+ return '/';
81
+ });
82
+ sandbox
83
+ .stub(path_1.default, 'join')
84
+ .callsFake((p1, p2) => `${p1}/${p2}`);
85
+ sandbox.stub(fs_1.default, 'existsSync').returns(false);
86
+ const result = (0, findSourceCodeUrl_1.findProjectRoot)(mockTarget);
87
+ assert_1.default.equal(result, null);
88
+ });
89
+ it('should traverse up directories until finding .git', function () {
90
+ const mockTarget = '/path/to/project/deep/subdir';
91
+ const mockResolvedPath = '/resolved/path/to/project/deep/subdir';
92
+ sandbox.stub(path_1.default, 'resolve').returns(mockResolvedPath);
93
+ sandbox.stub(path_1.default, 'dirname').callsFake((p) => {
94
+ if (p === mockResolvedPath)
95
+ return '/resolved/path/to/project/deep';
96
+ if (p === '/resolved/path/to/project/deep')
97
+ return '/resolved/path/to/project';
98
+ if (p === '/resolved/path/to/project')
99
+ return '/resolved/path/to';
100
+ return '/';
101
+ });
102
+ sandbox
103
+ .stub(path_1.default, 'join')
104
+ .callsFake((p1, _p2) => `${p1}/.git`);
105
+ const existsStub = sandbox.stub(fs_1.default, 'existsSync');
106
+ existsStub
107
+ .withArgs('/resolved/path/to/project/deep/subdir/.git')
108
+ .returns(false);
109
+ existsStub.withArgs('/resolved/path/to/project/deep/.git').returns(false);
110
+ existsStub.withArgs('/resolved/path/to/project/.git').returns(true);
111
+ const result = (0, findSourceCodeUrl_1.findProjectRoot)(mockTarget);
112
+ assert_1.default.equal(result, '/resolved/path/to/project');
113
+ });
114
+ });
115
+ describe('findSourceCodeURL', function () {
116
+ it('should return null when no project root is found', function () {
117
+ const mockTarget = '/path/to/project';
118
+ sandbox.stub(path_1.default, 'resolve').returns('/resolved/path');
119
+ sandbox.stub(path_1.default, 'dirname').returns('/');
120
+ sandbox.stub(path_1.default, 'join').returns('/.git');
121
+ sandbox.stub(fs_1.default, 'existsSync').returns(false);
122
+ const result = (0, findSourceCodeUrl_1.findSourceCodeURL)(mockTarget);
123
+ assert_1.default.equal(result, null);
124
+ });
125
+ it('should parse GitHub SSH URL correctly', function () {
126
+ const mockTarget = '/path/to/project';
127
+ sandbox.stub(path_1.default, 'resolve').returns('/resolved/path');
128
+ sandbox.stub(path_1.default, 'dirname').returns('/');
129
+ sandbox.stub(path_1.default, 'join').returns('/resolved/path/.git');
130
+ sandbox.stub(fs_1.default, 'existsSync').returns(true);
131
+ const mockGitOutput = 'origin\tgit@github.com:owner/repo.git (fetch)\norigin\tgit@github.com:owner/repo.git (push)';
132
+ sandbox
133
+ .stub(child_process_1.default, 'execSync')
134
+ .returns(Buffer.from(mockGitOutput));
135
+ const result = (0, findSourceCodeUrl_1.findSourceCodeURL)(mockTarget);
136
+ assert_1.default.deepEqual(result, {
137
+ type: 'github',
138
+ owner: 'owner',
139
+ repo: 'repo',
140
+ });
141
+ });
142
+ it('should parse GitHub HTTPS URL correctly', function () {
143
+ const mockTarget = '/path/to/project';
144
+ sandbox.stub(path_1.default, 'resolve').returns('/resolved/path');
145
+ sandbox.stub(path_1.default, 'dirname').returns('/');
146
+ sandbox.stub(path_1.default, 'join').returns('/resolved/path/.git');
147
+ sandbox.stub(fs_1.default, 'existsSync').returns(true);
148
+ const mockGitOutput = 'origin\thttps://github.com/owner/repo.git (fetch)';
149
+ sandbox
150
+ .stub(child_process_1.default, 'execSync')
151
+ .returns(Buffer.from(mockGitOutput));
152
+ const result = (0, findSourceCodeUrl_1.findSourceCodeURL)(mockTarget);
153
+ assert_1.default.deepEqual(result, {
154
+ type: 'github',
155
+ owner: 'owner',
156
+ repo: 'repo',
157
+ });
158
+ });
159
+ it('should parse Bitbucket SSH URL correctly', function () {
160
+ const mockTarget = '/path/to/project';
161
+ sandbox.stub(path_1.default, 'resolve').returns('/resolved/path');
162
+ sandbox.stub(path_1.default, 'dirname').returns('/');
163
+ sandbox.stub(path_1.default, 'join').returns('/resolved/path/.git');
164
+ sandbox.stub(fs_1.default, 'existsSync').returns(true);
165
+ const mockGitOutput = 'origin\tgit@bitbucket.org:owner/repo.git (fetch)';
166
+ sandbox
167
+ .stub(child_process_1.default, 'execSync')
168
+ .returns(Buffer.from(mockGitOutput));
169
+ const result = (0, findSourceCodeUrl_1.findSourceCodeURL)(mockTarget);
170
+ assert_1.default.deepEqual(result, {
171
+ type: 'bitbucket',
172
+ owner: 'owner',
173
+ repo: 'repo',
174
+ });
175
+ });
176
+ it('should return null when no valid remote is found', function () {
177
+ const mockTarget = '/path/to/project';
178
+ sandbox.stub(path_1.default, 'resolve').returns('/resolved/path');
179
+ sandbox.stub(path_1.default, 'dirname').returns('/');
180
+ sandbox.stub(path_1.default, 'join').returns('/resolved/path/.git');
181
+ sandbox.stub(fs_1.default, 'existsSync').returns(true);
182
+ const mockGitOutput = 'origin\tgit@example.com:owner/repo.git (fetch)';
183
+ sandbox
184
+ .stub(child_process_1.default, 'execSync')
185
+ .returns(Buffer.from(mockGitOutput));
186
+ const result = (0, findSourceCodeUrl_1.findSourceCodeURL)(mockTarget);
187
+ assert_1.default.equal(result, null);
188
+ });
189
+ it('should return null when git command fails', function () {
190
+ const mockTarget = '/path/to/project';
191
+ sandbox.stub(path_1.default, 'resolve').returns('/resolved/path');
192
+ sandbox.stub(path_1.default, 'dirname').returns('/');
193
+ sandbox.stub(path_1.default, 'join').returns('/resolved/path/.git');
194
+ sandbox.stub(fs_1.default, 'existsSync').returns(true);
195
+ sandbox
196
+ .stub(child_process_1.default, 'execSync')
197
+ .throws(new Error('Git command failed'));
198
+ assert_1.default.throws(() => {
199
+ (0, findSourceCodeUrl_1.findSourceCodeURL)(mockTarget);
200
+ }, Error);
201
+ });
202
+ it('should return null when URL format is invalid', function () {
203
+ const mockTarget = '/path/to/project';
204
+ sandbox.stub(path_1.default, 'resolve').returns('/resolved/path');
205
+ sandbox.stub(path_1.default, 'dirname').returns('/');
206
+ sandbox.stub(path_1.default, 'join').returns('/resolved/path/.git');
207
+ sandbox.stub(fs_1.default, 'existsSync').returns(true);
208
+ const mockGitOutput = 'origin\tinvalid-url-format (fetch)';
209
+ sandbox
210
+ .stub(child_process_1.default, 'execSync')
211
+ .returns(Buffer.from(mockGitOutput));
212
+ const result = (0, findSourceCodeUrl_1.findSourceCodeURL)(mockTarget);
213
+ assert_1.default.equal(result, null);
214
+ });
215
+ });
216
+ });
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCacheStats = getCacheStats;
4
+ /**
5
+ * Aggregate data based on general cache usage, by reading all entries
6
+ * in the cache.
7
+ *
8
+ * This can take a non-neglible amount of time on large caches, but
9
+ * will still be a lot faster than the graph deserialization steps.
10
+ */
11
+ function getCacheStats(cache) {
12
+ const stats = {
13
+ size: 0,
14
+ count: 0,
15
+ keySize: 0,
16
+ assetContentCount: 0,
17
+ assetContentSize: 0,
18
+ assetMapCount: 0,
19
+ assetMapSize: 0,
20
+ };
21
+ for (const key of cache.keys()) {
22
+ const value = cache.getBlobSync(key);
23
+ stats.size += value.length;
24
+ stats.keySize += Buffer.from(key).length;
25
+ stats.count++;
26
+ if (key.endsWith(':content')) {
27
+ stats.assetContentCount++;
28
+ stats.assetContentSize += value.length;
29
+ }
30
+ else if (key.endsWith(':map')) {
31
+ stats.assetMapCount++;
32
+ stats.assetMapSize += value.length;
33
+ }
34
+ }
35
+ return stats;
36
+ }