@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.
- package/LICENSE +201 -0
- package/README.md +126 -0
- package/bin/atlaspack-inspector.js +2 -0
- package/lib/backend/cli.js +4 -0
- package/lib/backend/config/logger.js +16 -0
- package/lib/backend/config/middleware/cacheDataMiddleware.js +60 -0
- package/lib/backend/config/middleware/errorHandlingMiddleware.js +17 -0
- package/lib/backend/config/middleware/errorHandlingMiddleware.test.js +44 -0
- package/lib/backend/config/middleware/loggingMiddleware.js +22 -0
- package/lib/backend/controllers/BundleGraphController.js +42 -0
- package/lib/backend/controllers/CacheDataController.js +143 -0
- package/lib/backend/controllers/FrontendAssetsController.js +61 -0
- package/lib/backend/controllers/TreeMapController.js +108 -0
- package/lib/backend/controllers/mcp/InspectorMCP.js +231 -0
- package/lib/backend/controllers/mcp/InspectorMCPController.js +16 -0
- package/lib/backend/errors/HTTPError.js +16 -0
- package/lib/backend/errors/HTTPError.test.js +21 -0
- package/lib/backend/index.js +177 -0
- package/lib/backend/services/AnalyticsService.js +86 -0
- package/lib/backend/services/LazyValue.js +33 -0
- package/lib/backend/services/LazyValue.test.js +12 -0
- package/lib/backend/services/buildJsonGraph.js +86 -0
- package/lib/backend/services/buildTreemap.js +140 -0
- package/lib/backend/services/buildTreemapBundle.test.js +298 -0
- package/lib/backend/services/findSourceCodeUrl.js +107 -0
- package/lib/backend/services/findSourceCodeUrl.test.js +216 -0
- package/lib/backend/services/getCacheStats.js +36 -0
- package/lib/backend/services/getCacheStats.test.js +162 -0
- package/lib/backend/services/getDisplayName.js +18 -0
- package/lib/backend/services/getDisplayName.test.js +71 -0
- package/lib/backend/services/loadCacheData.js +209 -0
- package/lib/backend/services/loadCacheData.test.js +79 -0
- package/lib/backend/testing/TemporaryDirectory.js +46 -0
- package/lib/frontend/node_modules/@atlaspack/packager-js/lib/dev-prelude.js +145 -0
- package/lib/frontend/node_modules/@atlaspack/packager-js/src/dev-prelude.js +145 -0
- package/package.json +75 -0
- package/screenshots/bottom-up.png +0 -0
- package/screenshots/cache-inspector.png +0 -0
- package/screenshots/treemap.png +0 -0
- package/src/backend/README.md +14 -0
- package/src/backend/cli.ts +3 -0
- package/src/backend/config/logger.ts +14 -0
- package/src/backend/config/middleware/cacheDataMiddleware.ts +94 -0
- package/src/backend/config/middleware/errorHandlingMiddleware.test.ts +52 -0
- package/src/backend/config/middleware/errorHandlingMiddleware.ts +20 -0
- package/src/backend/config/middleware/loggingMiddleware.ts +24 -0
- package/src/backend/controllers/BundleGraphController.ts +73 -0
- package/src/backend/controllers/CacheDataController.ts +187 -0
- package/src/backend/controllers/FrontendAssetsController.ts +28 -0
- package/src/backend/controllers/TreeMapController.ts +143 -0
- package/src/backend/controllers/mcp/InspectorMCP.ts +311 -0
- package/src/backend/controllers/mcp/InspectorMCPController.ts +17 -0
- package/src/backend/errors/HTTPError.test.ts +19 -0
- package/src/backend/errors/HTTPError.ts +14 -0
- package/src/backend/globals.d.ts +9 -0
- package/src/backend/index.ts +271 -0
- package/src/backend/services/AnalyticsService.ts +118 -0
- package/src/backend/services/LazyValue.test.ts +13 -0
- package/src/backend/services/LazyValue.ts +29 -0
- package/src/backend/services/buildJsonGraph.ts +124 -0
- package/src/backend/services/buildTreemap.ts +273 -0
- package/src/backend/services/buildTreemapBundle.test.ts +348 -0
- package/src/backend/services/findSourceCodeUrl.test.ts +228 -0
- package/src/backend/services/findSourceCodeUrl.ts +146 -0
- package/src/backend/services/getCacheStats.test.ts +169 -0
- package/src/backend/services/getCacheStats.ts +46 -0
- package/src/backend/services/getDisplayName.test.ts +84 -0
- package/src/backend/services/getDisplayName.ts +20 -0
- package/src/backend/services/loadCacheData.test.ts +101 -0
- package/src/backend/services/loadCacheData.ts +294 -0
- package/src/backend/testing/TemporaryDirectory.ts +50 -0
- package/src/frontend/.atlaspackrc +4 -0
- package/src/frontend/.eslintrc.json +19 -0
- package/src/frontend/dist/atlassian-dark-brand-refresh.91b786da.js +2 -0
- package/src/frontend/dist/atlassian-dark-brand-refresh.91b786da.js.map +1 -0
- package/src/frontend/dist/atlassian-dark-future.59ebadca.js +2 -0
- package/src/frontend/dist/atlassian-dark-future.59ebadca.js.map +1 -0
- package/src/frontend/dist/atlassian-dark-increased-contrast.ff6775f2.js +2 -0
- package/src/frontend/dist/atlassian-dark-increased-contrast.ff6775f2.js.map +1 -0
- package/src/frontend/dist/atlassian-dark.ad679134.js +2 -0
- package/src/frontend/dist/atlassian-dark.ad679134.js.map +1 -0
- package/src/frontend/dist/atlassian-legacy-dark.8aa27f7f.js +2 -0
- package/src/frontend/dist/atlassian-legacy-dark.8aa27f7f.js.map +1 -0
- package/src/frontend/dist/atlassian-legacy-light.2eb372ce.js +2 -0
- package/src/frontend/dist/atlassian-legacy-light.2eb372ce.js.map +1 -0
- package/src/frontend/dist/atlassian-light-brand-refresh.fadcab0a.js +2 -0
- package/src/frontend/dist/atlassian-light-brand-refresh.fadcab0a.js.map +1 -0
- package/src/frontend/dist/atlassian-light-future.612afe8a.js +2 -0
- package/src/frontend/dist/atlassian-light-future.612afe8a.js.map +1 -0
- package/src/frontend/dist/atlassian-light-increased-contrast.7161cd79.js +2 -0
- package/src/frontend/dist/atlassian-light-increased-contrast.7161cd79.js.map +1 -0
- package/src/frontend/dist/atlassian-light.bc343d4c.js +2 -0
- package/src/frontend/dist/atlassian-light.bc343d4c.js.map +1 -0
- package/src/frontend/dist/atlassian-shape.b92d69c0.js +2 -0
- package/src/frontend/dist/atlassian-shape.b92d69c0.js.map +1 -0
- package/src/frontend/dist/atlassian-spacing.60ddd8e7.js +2 -0
- package/src/frontend/dist/atlassian-spacing.60ddd8e7.js.map +1 -0
- package/src/frontend/dist/atlassian-typography-adg3.f88947f6.js +2 -0
- package/src/frontend/dist/atlassian-typography-adg3.f88947f6.js.map +1 -0
- package/src/frontend/dist/atlassian-typography-modernized.42016c51.js +2 -0
- package/src/frontend/dist/atlassian-typography-modernized.42016c51.js.map +1 -0
- package/src/frontend/dist/atlassian-typography-refreshed.ec0d111b.js +2 -0
- package/src/frontend/dist/atlassian-typography-refreshed.ec0d111b.js.map +1 -0
- package/src/frontend/dist/atlassian-typography.66d7e8f4.js +2 -0
- package/src/frontend/dist/atlassian-typography.66d7e8f4.js.map +1 -0
- package/src/frontend/dist/badge-light.7e55986a.png +0 -0
- package/src/frontend/dist/custom-theme.4680282a.js +2 -0
- package/src/frontend/dist/custom-theme.4680282a.js.map +1 -0
- package/src/frontend/dist/drag-handle.136830d3.js +2 -0
- package/src/frontend/dist/drag-handle.136830d3.js.map +1 -0
- package/src/frontend/dist/drag-handle.63bdb345.css +2 -0
- package/src/frontend/dist/drag-handle.63bdb345.css.map +1 -0
- package/src/frontend/dist/index.a41fafce.css +2 -0
- package/src/frontend/dist/index.a41fafce.css.map +1 -0
- package/src/frontend/dist/index.a4ce2b12.js +28 -0
- package/src/frontend/dist/index.a4ce2b12.js.map +1 -0
- package/src/frontend/dist/index.html +1 -0
- package/src/frontend/dist/index.runtime.a729d997.js +2 -0
- package/src/frontend/dist/index.runtime.a729d997.js.map +1 -0
- package/src/frontend/dist/refractor.2c1fd9a1.js +2 -0
- package/src/frontend/dist/refractor.2c1fd9a1.js.map +1 -0
- package/src/frontend/index.html +11 -0
- package/src/frontend/jest.config.js +16 -0
- package/src/frontend/package.json +64 -0
- package/src/frontend/src/APIError.test.ts +72 -0
- package/src/frontend/src/APIError.tsx +29 -0
- package/src/frontend/src/AppRoutes.tsx +56 -0
- package/src/frontend/src/hack-feature-flags.ts +6 -0
- package/src/frontend/src/main.tsx +50 -0
- package/src/frontend/src/test/stubCssModule.js +1 -0
- package/src/frontend/src/ui/App.module.css +122 -0
- package/src/frontend/src/ui/App.module.css.d.ts +8 -0
- package/src/frontend/src/ui/AppLayout/AppLayout.tsx +26 -0
- package/src/frontend/src/ui/AppLayout/SidebarNavigation/LinkItem.tsx +26 -0
- package/src/frontend/src/ui/AppLayout/SidebarNavigation/SidebarNavigation.tsx +45 -0
- package/src/frontend/src/ui/AppLayout/TopNavigation/Logo.module.css +12 -0
- package/src/frontend/src/ui/AppLayout/TopNavigation/Logo.module.css.d.ts +4 -0
- package/src/frontend/src/ui/AppLayout/TopNavigation/Logo.tsx +11 -0
- package/src/frontend/src/ui/AppLayout/TopNavigation/TopNavigation.module.css +14 -0
- package/src/frontend/src/ui/AppLayout/TopNavigation/TopNavigation.module.css.d.ts +3 -0
- package/src/frontend/src/ui/AppLayout/TopNavigation/TopNavigation.tsx +45 -0
- package/src/frontend/src/ui/AppLayout/TopNavigation/badge-light.png +0 -0
- package/src/frontend/src/ui/AppLayout/TopNavigation/logo-light.png +0 -0
- package/src/frontend/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.module.css +9 -0
- package/src/frontend/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.module.css.d.ts +3 -0
- package/src/frontend/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.test.tsx +15 -0
- package/src/frontend/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.tsx +14 -0
- package/src/frontend/src/ui/app/StatsPage.tsx +77 -0
- package/src/frontend/src/ui/app/cache/CacheKeysIndexPage.tsx +13 -0
- package/src/frontend/src/ui/app/cache/CacheKeysPage.module.css +11 -0
- package/src/frontend/src/ui/app/cache/CacheKeysPage.module.css.d.ts +4 -0
- package/src/frontend/src/ui/app/cache/CacheKeysPage.tsx +23 -0
- package/src/frontend/src/ui/app/cache/[key]/CacheValuePage.tsx +40 -0
- package/src/frontend/src/ui/app/cache/ui/CacheKeyList.module.css +40 -0
- package/src/frontend/src/ui/app/cache/ui/CacheKeyList.module.css.d.ts +7 -0
- package/src/frontend/src/ui/app/cache/ui/CacheKeyList.tsx +187 -0
- package/src/frontend/src/ui/app/cache-invalidation/CacheInvalidationPage.tsx +22 -0
- package/src/frontend/src/ui/app/cache-invalidation/[fileId]/CacheInvalidationFilePage.tsx +22 -0
- package/src/frontend/src/ui/app/cache-invalidation/ui/CacheFileList.module.css +40 -0
- package/src/frontend/src/ui/app/cache-invalidation/ui/CacheFileList.module.css.d.ts +7 -0
- package/src/frontend/src/ui/app/cache-invalidation/ui/CacheFileList.tsx +185 -0
- package/src/frontend/src/ui/app/treemap/BottomPanelResizeState.test.ts +25 -0
- package/src/frontend/src/ui/app/treemap/BottomPanelResizeState.tsx +48 -0
- package/src/frontend/src/ui/app/treemap/FoamTreemapPage.module.css +24 -0
- package/src/frontend/src/ui/app/treemap/FoamTreemapPage.module.css.d.ts +6 -0
- package/src/frontend/src/ui/app/treemap/FoamTreemapPage.tsx +47 -0
- package/src/frontend/src/ui/app/treemap/controllers/RelatedBundlesController.tsx +41 -0
- package/src/frontend/src/ui/app/treemap/controllers/UrlFocusController.tsx +33 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/BottomPanel.module.css +24 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/BottomPanel.module.css.d.ts +5 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/BottomPanel.tsx +24 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.module.css +13 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.module.css.d.ts +5 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.tsx +53 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/AssetTable.tsx +135 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.module.css +7 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.module.css.d.ts +3 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.tsx +123 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableModel.tsx +18 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.module.css +20 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.module.css.d.ts +6 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.tsx +79 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/getFileURL.test.ts +19 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/getFileURL.ts +24 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.module.css +20 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.module.css.d.ts +5 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.tsx +42 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.module.css +29 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.module.css.d.ts +6 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.tsx +107 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.module.css +7 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.module.css.d.ts +3 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.tsx +20 -0
- package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/SourceCodeURL.tsx +5 -0
- package/src/frontend/src/ui/app/treemap/ui/BundleGraphRenderer.module.css +13 -0
- package/src/frontend/src/ui/app/treemap/ui/BundleGraphRenderer.module.css.d.ts +4 -0
- package/src/frontend/src/ui/app/treemap/ui/BundleGraphRenderer.tsx +95 -0
- package/src/frontend/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.module.css +6 -0
- package/src/frontend/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.module.css.d.ts +3 -0
- package/src/frontend/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.tsx +49 -0
- package/src/frontend/src/ui/app/treemap/ui/SigmaGraph.module.css +5 -0
- package/src/frontend/src/ui/app/treemap/ui/SigmaGraph.module.css.d.ts +3 -0
- package/src/frontend/src/ui/app/treemap/ui/SigmaGraph.tsx +80 -0
- package/src/frontend/src/ui/app/treemap/ui/Treemap.tsx +14 -0
- package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.module.css +32 -0
- package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.module.css.d.ts +5 -0
- package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.tsx +24 -0
- package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.module.css +14 -0
- package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.module.css.d.ts +4 -0
- package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.tsx +271 -0
- package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.module.css +15 -0
- package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.module.css.d.ts +4 -0
- package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.tsx +111 -0
- package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/controllers/useStableCallback.test.ts +27 -0
- package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/controllers/useStableCallback.ts +21 -0
- package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/useMouseMoveController.ts +20 -0
- package/src/frontend/src/ui/globals.css +26 -0
- package/src/frontend/src/ui/globals.css.d.ts +1 -0
- package/src/frontend/src/ui/globals.d.ts +9 -0
- package/src/frontend/src/ui/model/ViewModel.test.ts +31 -0
- package/src/frontend/src/ui/model/ViewModel.ts +62 -0
- package/src/frontend/src/ui/not-found/NotFoundPage.module.css +7 -0
- package/src/frontend/src/ui/not-found/NotFoundPage.module.css.d.ts +3 -0
- package/src/frontend/src/ui/not-found/NotFoundPage.tsx +9 -0
- package/src/frontend/src/ui/types/Graph.tsx +12 -0
- package/src/frontend/src/ui/util/ErrorBoundary.module.css +3 -0
- package/src/frontend/src/ui/util/ErrorBoundary.module.css.d.ts +3 -0
- package/src/frontend/src/ui/util/ErrorBoundary.test.tsx +65 -0
- package/src/frontend/src/ui/util/ErrorBoundary.tsx +75 -0
- package/src/frontend/src/ui/util/colorPalette.tsx +122 -0
- package/src/frontend/src/ui/util/formatBytes.test.ts +13 -0
- package/src/frontend/src/ui/util/formatBytes.tsx +9 -0
- package/src/frontend/src/ui/util/getRandomDarkerColor.tsx +31 -0
- package/src/frontend/tsconfig.json +12 -0
- package/src/frontend/yarn.lock +0 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/* eslint-disable monorepo/no-internal-import */
|
|
2
|
+
// @ts-expect-error TS2749
|
|
3
|
+
import type BundleGraph from '@atlaspack/core/lib/BundleGraph.js';
|
|
4
|
+
// @ts-expect-error TS2749
|
|
5
|
+
import {requestTypes} from '@atlaspack/core/lib/RequestTracker.js';
|
|
6
|
+
// @ts-expect-error TS2749
|
|
7
|
+
import type RequestTracker from '@atlaspack/core/lib/RequestTracker.js';
|
|
8
|
+
// @ts-expect-error TS2749
|
|
9
|
+
import type {RequestGraphNode} from '@atlaspack/core/lib/RequestTracker.js';
|
|
10
|
+
// @ts-expect-error TS2749
|
|
11
|
+
import type {Node} from '@atlaspack/core/lib/types.js';
|
|
12
|
+
import fs from 'fs';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import {logger} from '../config/logger';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* An asset tree node.
|
|
18
|
+
*
|
|
19
|
+
* This is the file-tree structure of the bundle. Each file and directory is a node in the
|
|
20
|
+
* tree.
|
|
21
|
+
*
|
|
22
|
+
* Directories' sizes are the sum of their children's sizes.
|
|
23
|
+
*
|
|
24
|
+
* Sizes are read from disk, not from the bundle itself.
|
|
25
|
+
*/
|
|
26
|
+
export type AssetTreeNode = {
|
|
27
|
+
/**
|
|
28
|
+
* ID of this file.
|
|
29
|
+
*/
|
|
30
|
+
id: string;
|
|
31
|
+
/**
|
|
32
|
+
* Children of this node (empty is this is a file).
|
|
33
|
+
*
|
|
34
|
+
* This is the next path component in the file-path leading to each child.
|
|
35
|
+
*/
|
|
36
|
+
children: Record<string, AssetTreeNode>;
|
|
37
|
+
/**
|
|
38
|
+
* Size of this node in bytes.
|
|
39
|
+
*/
|
|
40
|
+
size: number;
|
|
41
|
+
/**
|
|
42
|
+
* The full file-path of this node.
|
|
43
|
+
*/
|
|
44
|
+
path: string;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* A bundle in the tree-map.
|
|
49
|
+
*/
|
|
50
|
+
export interface TreemapBundle {
|
|
51
|
+
/**
|
|
52
|
+
* The bundle `id` for tree-map purposes.
|
|
53
|
+
*/
|
|
54
|
+
id: string;
|
|
55
|
+
/**
|
|
56
|
+
* A display name for the UI
|
|
57
|
+
*/
|
|
58
|
+
displayName: string;
|
|
59
|
+
/**
|
|
60
|
+
* Raw bundle node from the bundle graph.
|
|
61
|
+
*/
|
|
62
|
+
bundle: any;
|
|
63
|
+
/**
|
|
64
|
+
* Size of the bundle in bytes, as read from disk.
|
|
65
|
+
*/
|
|
66
|
+
size: number;
|
|
67
|
+
/**
|
|
68
|
+
* The file path of the bundle on disk.
|
|
69
|
+
*/
|
|
70
|
+
filePath: string;
|
|
71
|
+
/**
|
|
72
|
+
* The file-tree for the bundle.
|
|
73
|
+
*/
|
|
74
|
+
assetTree: AssetTreeNode;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The tree-map model.
|
|
79
|
+
*/
|
|
80
|
+
export interface Treemap {
|
|
81
|
+
/**
|
|
82
|
+
* Each bundle in the application build.
|
|
83
|
+
*/
|
|
84
|
+
bundles: Array<TreemapBundle>;
|
|
85
|
+
/**
|
|
86
|
+
* Total size of all bundles in bytes.
|
|
87
|
+
*/
|
|
88
|
+
totalSize: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* In order to find the sizes of bundles, we look-up write bundle requests for each bundle
|
|
93
|
+
* in this build, then read the sizes of each file from disk.
|
|
94
|
+
*/
|
|
95
|
+
export function getWriteBundleRequestsByBundleId(
|
|
96
|
+
requestTracker: RequestTracker,
|
|
97
|
+
): Map<string, RequestGraphNode> {
|
|
98
|
+
const writeBundleRequests = requestTracker.graph.nodes.filter(
|
|
99
|
+
(requestNode: RequestGraphNode) =>
|
|
100
|
+
requestNode &&
|
|
101
|
+
requestNode.type === 1 &&
|
|
102
|
+
requestNode.requestType === requestTypes.write_bundle_request,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
return new Map(
|
|
106
|
+
writeBundleRequests.map((request: RequestGraphNode) => [
|
|
107
|
+
request.result?.bundleId ?? '',
|
|
108
|
+
request,
|
|
109
|
+
]),
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Builds a tree-map model for a bundle graph.
|
|
115
|
+
*
|
|
116
|
+
* The tree-map is a tree structure starting at the bundle and having layers for
|
|
117
|
+
* each asset sub-directory in its asset tree.
|
|
118
|
+
*
|
|
119
|
+
* Asset sizes are calculated from the asset size stats, which should represent
|
|
120
|
+
* sizes post-transformation, but before minification.
|
|
121
|
+
*
|
|
122
|
+
* Bundle sizes are read from the bundle files on disk.
|
|
123
|
+
*
|
|
124
|
+
* The sub-directories are sized to the size of their children.
|
|
125
|
+
*/
|
|
126
|
+
export function buildTreemapBundle({
|
|
127
|
+
writeBundleRequestsByBundleId,
|
|
128
|
+
node,
|
|
129
|
+
projectRoot,
|
|
130
|
+
repositoryRoot,
|
|
131
|
+
bundleGraph,
|
|
132
|
+
}: {
|
|
133
|
+
writeBundleRequestsByBundleId: Map<string, RequestGraphNode>;
|
|
134
|
+
node: Node;
|
|
135
|
+
projectRoot: string;
|
|
136
|
+
repositoryRoot: string;
|
|
137
|
+
bundleGraph: BundleGraph;
|
|
138
|
+
}): TreemapBundle {
|
|
139
|
+
const writeBundleRequest = writeBundleRequestsByBundleId.get(node.id);
|
|
140
|
+
const {size, filePath} = findBundleInfo({
|
|
141
|
+
writeBundleRequest,
|
|
142
|
+
projectRoot,
|
|
143
|
+
repositoryRoot,
|
|
144
|
+
node,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// this is the directory structure
|
|
148
|
+
const assetTree: AssetTreeNode = {
|
|
149
|
+
id: `${node.id}::/`,
|
|
150
|
+
path: '',
|
|
151
|
+
children: {},
|
|
152
|
+
size: 0,
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const assets: any[] = [];
|
|
156
|
+
bundleGraph.traverseAssets(node.value, (asset: any) => {
|
|
157
|
+
assets.push(asset);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
for (const asset of assets) {
|
|
161
|
+
const filePath = path.isAbsolute(asset.filePath)
|
|
162
|
+
? path.relative(repositoryRoot, asset.filePath)
|
|
163
|
+
: asset.filePath;
|
|
164
|
+
const parts = filePath.split('/');
|
|
165
|
+
const assetSize = asset.stats.size;
|
|
166
|
+
let current = assetTree;
|
|
167
|
+
|
|
168
|
+
let currentSubpath = '';
|
|
169
|
+
for (let part of parts) {
|
|
170
|
+
currentSubpath += '/' + part;
|
|
171
|
+
current.size += assetSize;
|
|
172
|
+
current.children[part] = current.children[part] ?? {
|
|
173
|
+
id: `${node.id}::${currentSubpath}`,
|
|
174
|
+
path: currentSubpath,
|
|
175
|
+
children: {},
|
|
176
|
+
size: 0,
|
|
177
|
+
};
|
|
178
|
+
current = current.children[part];
|
|
179
|
+
}
|
|
180
|
+
current.size += assetSize;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const treemapBundle = {
|
|
184
|
+
id: node.id,
|
|
185
|
+
displayName: node.value.displayName,
|
|
186
|
+
bundle: node,
|
|
187
|
+
size,
|
|
188
|
+
filePath: filePath ?? '',
|
|
189
|
+
assetTree,
|
|
190
|
+
};
|
|
191
|
+
return treemapBundle;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Finds the size and file path of a bundle.
|
|
196
|
+
*
|
|
197
|
+
* If the file path is not absolute, it is made absolute by joining it with the project root.
|
|
198
|
+
*
|
|
199
|
+
* If the file path is not found, the size is 0.
|
|
200
|
+
*
|
|
201
|
+
* If the file path is found but the file cannot be read, an error is logged and the size is 0.
|
|
202
|
+
*/
|
|
203
|
+
export function findBundleInfo({
|
|
204
|
+
writeBundleRequest,
|
|
205
|
+
projectRoot,
|
|
206
|
+
repositoryRoot,
|
|
207
|
+
node,
|
|
208
|
+
}: {
|
|
209
|
+
writeBundleRequest: RequestGraphNode | undefined;
|
|
210
|
+
projectRoot: string;
|
|
211
|
+
repositoryRoot: string;
|
|
212
|
+
node: Node;
|
|
213
|
+
}): {size: number; filePath: string | null} {
|
|
214
|
+
let filePath = writeBundleRequest?.result?.filePath
|
|
215
|
+
? path.isAbsolute(writeBundleRequest?.result?.filePath)
|
|
216
|
+
? writeBundleRequest.result.filePath
|
|
217
|
+
: path.join(projectRoot, writeBundleRequest.result.filePath)
|
|
218
|
+
: null;
|
|
219
|
+
let size = 0;
|
|
220
|
+
try {
|
|
221
|
+
size = filePath ? fs.statSync(filePath).size : 0;
|
|
222
|
+
} catch (e) {
|
|
223
|
+
logger.error(
|
|
224
|
+
{filePath, nodeId: node.id, error: e},
|
|
225
|
+
`Error getting size of bundle at ${filePath}`,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
filePath = filePath
|
|
230
|
+
? path.isAbsolute(filePath)
|
|
231
|
+
? path.relative(repositoryRoot, filePath)
|
|
232
|
+
: filePath
|
|
233
|
+
: null;
|
|
234
|
+
|
|
235
|
+
return {size, filePath};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export function buildTreemap({
|
|
239
|
+
projectRoot,
|
|
240
|
+
repositoryRoot,
|
|
241
|
+
bundleGraph,
|
|
242
|
+
requestTracker,
|
|
243
|
+
}: {
|
|
244
|
+
projectRoot: string;
|
|
245
|
+
repositoryRoot: string;
|
|
246
|
+
bundleGraph: BundleGraph;
|
|
247
|
+
requestTracker: RequestTracker;
|
|
248
|
+
}): Treemap {
|
|
249
|
+
const treemap: Treemap = {
|
|
250
|
+
bundles: [],
|
|
251
|
+
totalSize: 0,
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const writeBundleRequestsByBundleId =
|
|
255
|
+
getWriteBundleRequestsByBundleId(requestTracker);
|
|
256
|
+
|
|
257
|
+
bundleGraph._graph.nodes.forEach((node: Node) => {
|
|
258
|
+
if (node.type === 'bundle') {
|
|
259
|
+
const treemapBundle = buildTreemapBundle({
|
|
260
|
+
writeBundleRequestsByBundleId,
|
|
261
|
+
node,
|
|
262
|
+
projectRoot,
|
|
263
|
+
repositoryRoot,
|
|
264
|
+
bundleGraph,
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
treemap.bundles.push(treemapBundle);
|
|
268
|
+
treemap.totalSize += treemapBundle.size;
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
return treemap;
|
|
273
|
+
}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import assert from 'assert';
|
|
2
|
+
import * as sinon from 'sinon';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import {buildTreemapBundle} from './buildTreemap';
|
|
6
|
+
|
|
7
|
+
jest.mock('../config/logger');
|
|
8
|
+
|
|
9
|
+
describe('buildTreemapBundle', function () {
|
|
10
|
+
let sandbox: sinon.SinonSandbox;
|
|
11
|
+
let mockBundleGraph: any;
|
|
12
|
+
let mockNode: any;
|
|
13
|
+
let mockWriteBundleRequestsByBundleId: Map<string, any>;
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
sandbox = sinon.createSandbox();
|
|
17
|
+
|
|
18
|
+
// Mock fs.statSync
|
|
19
|
+
sandbox.stub(fs, 'statSync').returns({size: 1024} as any);
|
|
20
|
+
|
|
21
|
+
// Mock path.join
|
|
22
|
+
sandbox
|
|
23
|
+
.stub(path, 'join')
|
|
24
|
+
.callsFake((...paths: string[]) => paths.join('/'));
|
|
25
|
+
|
|
26
|
+
// Mock bundle node
|
|
27
|
+
mockNode = {
|
|
28
|
+
id: 'bundle123',
|
|
29
|
+
type: 'bundle',
|
|
30
|
+
value: {
|
|
31
|
+
displayName: 'main.js',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Mock bundle graph with traverseAssets method
|
|
36
|
+
mockBundleGraph = {
|
|
37
|
+
traverseAssets: sandbox.stub(),
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Mock write bundle requests map
|
|
41
|
+
mockWriteBundleRequestsByBundleId = new Map([
|
|
42
|
+
[
|
|
43
|
+
'bundle123',
|
|
44
|
+
{
|
|
45
|
+
result: {
|
|
46
|
+
bundleId: 'bundle123',
|
|
47
|
+
filePath: 'dist/main.js',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
]);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
afterEach(() => {
|
|
55
|
+
sandbox.restore();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should build treemap bundle with correct basic properties', function () {
|
|
59
|
+
// Setup mock assets
|
|
60
|
+
const mockAssets = [
|
|
61
|
+
{
|
|
62
|
+
filePath: '/src/index.js',
|
|
63
|
+
stats: {size: 100},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
filePath: '/src/utils.js',
|
|
67
|
+
stats: {size: 50},
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
// Mock traverseAssets to call callback with each asset
|
|
72
|
+
mockBundleGraph.traverseAssets.callsFake(
|
|
73
|
+
(bundleValue: any, callback: (asset: any) => void) => {
|
|
74
|
+
mockAssets.forEach(callback);
|
|
75
|
+
},
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const result = buildTreemapBundle({
|
|
79
|
+
writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
|
|
80
|
+
node: mockNode,
|
|
81
|
+
projectRoot: '/project',
|
|
82
|
+
repositoryRoot: '/project',
|
|
83
|
+
bundleGraph: mockBundleGraph,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
assert.equal(result.id, 'bundle123');
|
|
87
|
+
assert.equal(result.displayName, 'main.js');
|
|
88
|
+
assert.equal(result.bundle, mockNode);
|
|
89
|
+
assert.equal(result.size, 1024); // from mocked fs.statSync
|
|
90
|
+
assert.equal(result.filePath, 'dist/main.js');
|
|
91
|
+
assert(result.assetTree);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should handle missing write bundle request', function () {
|
|
95
|
+
const emptyMap = new Map();
|
|
96
|
+
|
|
97
|
+
mockBundleGraph.traverseAssets.callsFake(
|
|
98
|
+
(_bundleValue: any, _callback: (asset: any) => void) => {
|
|
99
|
+
// No assets
|
|
100
|
+
},
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const result = buildTreemapBundle({
|
|
104
|
+
writeBundleRequestsByBundleId: emptyMap,
|
|
105
|
+
node: mockNode,
|
|
106
|
+
projectRoot: '/project',
|
|
107
|
+
repositoryRoot: '/project',
|
|
108
|
+
bundleGraph: mockBundleGraph,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
assert.equal(result.size, 0);
|
|
112
|
+
assert.equal(result.filePath, '');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should build correct asset tree structure', function () {
|
|
116
|
+
const mockAssets = [
|
|
117
|
+
{
|
|
118
|
+
filePath: 'src/components/Button.js',
|
|
119
|
+
stats: {size: 100},
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
filePath: 'src/utils/helpers.js',
|
|
123
|
+
stats: {size: 50},
|
|
124
|
+
},
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
mockBundleGraph.traverseAssets.callsFake(
|
|
128
|
+
(bundleValue: any, callback: (asset: any) => void) => {
|
|
129
|
+
mockAssets.forEach(callback);
|
|
130
|
+
},
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const result = buildTreemapBundle({
|
|
134
|
+
writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
|
|
135
|
+
node: mockNode,
|
|
136
|
+
projectRoot: '/project',
|
|
137
|
+
repositoryRoot: '/project',
|
|
138
|
+
bundleGraph: mockBundleGraph,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Check that tree structure exists
|
|
142
|
+
assert(result.assetTree.children.src);
|
|
143
|
+
assert.equal(result.assetTree.path, '');
|
|
144
|
+
assert.equal(result.assetTree.children.src.path, '/src');
|
|
145
|
+
|
|
146
|
+
// Check components subdirectory exists
|
|
147
|
+
assert(result.assetTree.children.src.children.components);
|
|
148
|
+
assert.equal(
|
|
149
|
+
result.assetTree.children.src.children.components.path,
|
|
150
|
+
'/src/components',
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
// Check utils subdirectory exists
|
|
154
|
+
assert(result.assetTree.children.src.children.utils);
|
|
155
|
+
assert.equal(
|
|
156
|
+
result.assetTree.children.src.children.utils.path,
|
|
157
|
+
'/src/utils',
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
assert.equal(result.assetTree.size, 150);
|
|
161
|
+
assert.equal(result.assetTree.children.src.size, 150);
|
|
162
|
+
assert.equal(result.assetTree.children.src.children.components.size, 100);
|
|
163
|
+
assert.equal(result.assetTree.children.src.children.utils.size, 50);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should handle assets with same directory correctly', function () {
|
|
167
|
+
const mockAssets = [
|
|
168
|
+
{
|
|
169
|
+
filePath: 'lib/module1.js',
|
|
170
|
+
stats: {size: 100},
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
filePath: 'lib/module2.js',
|
|
174
|
+
stats: {size: 200},
|
|
175
|
+
},
|
|
176
|
+
];
|
|
177
|
+
|
|
178
|
+
mockBundleGraph.traverseAssets.callsFake(
|
|
179
|
+
(bundleValue: any, callback: (asset: any) => void) => {
|
|
180
|
+
mockAssets.forEach(callback);
|
|
181
|
+
},
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
const result = buildTreemapBundle({
|
|
185
|
+
writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
|
|
186
|
+
node: mockNode,
|
|
187
|
+
projectRoot: '/project',
|
|
188
|
+
repositoryRoot: '/project',
|
|
189
|
+
bundleGraph: mockBundleGraph,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// lib directory should contain total of all files under it
|
|
193
|
+
assert.equal(result.assetTree.children.lib.size, 300); // 100 + 200
|
|
194
|
+
assert.equal(
|
|
195
|
+
result.assetTree.children.lib.children['module1.js'].size,
|
|
196
|
+
100,
|
|
197
|
+
);
|
|
198
|
+
assert.equal(
|
|
199
|
+
result.assetTree.children.lib.children['module2.js'].size,
|
|
200
|
+
200,
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should handle empty assets array', function () {
|
|
205
|
+
mockBundleGraph.traverseAssets.callsFake(
|
|
206
|
+
(_bundleValue: any, _callback: (asset: any) => void) => {
|
|
207
|
+
// No assets
|
|
208
|
+
},
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
const result = buildTreemapBundle({
|
|
212
|
+
writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
|
|
213
|
+
node: mockNode,
|
|
214
|
+
projectRoot: '/project',
|
|
215
|
+
repositoryRoot: '/project',
|
|
216
|
+
bundleGraph: mockBundleGraph,
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
assert.equal(result.assetTree.size, 0);
|
|
220
|
+
assert.deepEqual(result.assetTree.children, {});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should handle file path without extension', function () {
|
|
224
|
+
const mockAssets = [
|
|
225
|
+
{
|
|
226
|
+
filePath: 'src/config',
|
|
227
|
+
stats: {size: 25},
|
|
228
|
+
},
|
|
229
|
+
];
|
|
230
|
+
|
|
231
|
+
mockBundleGraph.traverseAssets.callsFake(
|
|
232
|
+
(_bundleValue: any, callback: (asset: any) => void) => {
|
|
233
|
+
mockAssets.forEach(callback);
|
|
234
|
+
},
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
const result = buildTreemapBundle({
|
|
238
|
+
writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
|
|
239
|
+
node: mockNode,
|
|
240
|
+
projectRoot: '/project',
|
|
241
|
+
repositoryRoot: '/project',
|
|
242
|
+
bundleGraph: mockBundleGraph,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
assert.equal(result.assetTree.children.src.children.config.size, 25);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should call traverseAssets with correct bundle value', function () {
|
|
249
|
+
mockBundleGraph.traverseAssets.callsFake(
|
|
250
|
+
(_bundleValue: any, _callback: (asset: any) => void) => {
|
|
251
|
+
// Just verify it was called
|
|
252
|
+
},
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
buildTreemapBundle({
|
|
256
|
+
writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
|
|
257
|
+
node: mockNode,
|
|
258
|
+
projectRoot: '/project',
|
|
259
|
+
repositoryRoot: '/project',
|
|
260
|
+
bundleGraph: mockBundleGraph,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
assert(mockBundleGraph.traverseAssets.calledOnce);
|
|
264
|
+
assert(mockBundleGraph.traverseAssets.calledWith(mockNode.value));
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should calculate directory sizes correctly', function () {
|
|
268
|
+
// Test case matching user's example:
|
|
269
|
+
// lib/child/a.js - 10
|
|
270
|
+
// lib/other/b.js - 10
|
|
271
|
+
// lib/other/c.js - 10
|
|
272
|
+
const mockAssets = [
|
|
273
|
+
{
|
|
274
|
+
filePath: 'lib/child/a.js',
|
|
275
|
+
stats: {size: 10},
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
filePath: 'lib/other/b.js',
|
|
279
|
+
stats: {size: 10},
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
filePath: 'lib/other/c.js',
|
|
283
|
+
stats: {size: 10},
|
|
284
|
+
},
|
|
285
|
+
];
|
|
286
|
+
|
|
287
|
+
mockBundleGraph.traverseAssets.callsFake(
|
|
288
|
+
(bundleValue: any, callback: (asset: any) => void) => {
|
|
289
|
+
mockAssets.forEach(callback);
|
|
290
|
+
},
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
const result = buildTreemapBundle({
|
|
294
|
+
writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
|
|
295
|
+
node: mockNode,
|
|
296
|
+
projectRoot: '/project',
|
|
297
|
+
repositoryRoot: '/project',
|
|
298
|
+
bundleGraph: mockBundleGraph,
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// Root should contain total of all files
|
|
302
|
+
// assert.equal(result.assetTree.size, 30); // 10+10+10
|
|
303
|
+
|
|
304
|
+
// lib directory should contain total of all files under lib
|
|
305
|
+
assert.equal(result.assetTree.children.lib.size, 30); // 10+10+10
|
|
306
|
+
|
|
307
|
+
// lib/child should contain only a.js
|
|
308
|
+
assert.equal(result.assetTree.children.lib.children.child.size, 10); // 10
|
|
309
|
+
|
|
310
|
+
// lib/other should contain b.js + c.js
|
|
311
|
+
assert.equal(result.assetTree.children.lib.children.other.size, 20); // 10+10
|
|
312
|
+
|
|
313
|
+
// Individual files should have their own sizes
|
|
314
|
+
assert.equal(
|
|
315
|
+
result.assetTree.children.lib.children.child.children['a.js'].size,
|
|
316
|
+
10,
|
|
317
|
+
);
|
|
318
|
+
assert.equal(
|
|
319
|
+
result.assetTree.children.lib.children.other.children['b.js'].size,
|
|
320
|
+
10,
|
|
321
|
+
);
|
|
322
|
+
assert.equal(
|
|
323
|
+
result.assetTree.children.lib.children.other.children['c.js'].size,
|
|
324
|
+
10,
|
|
325
|
+
);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('should handle fs.statSync errors gracefully', function () {
|
|
329
|
+
// Make fs.statSync throw an error
|
|
330
|
+
(fs.statSync as sinon.SinonStub).throws(new Error('File not found'));
|
|
331
|
+
|
|
332
|
+
mockBundleGraph.traverseAssets.callsFake(
|
|
333
|
+
(_bundleValue: any, _callback: (asset: any) => void) => {
|
|
334
|
+
// No assets
|
|
335
|
+
},
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
assert.doesNotThrow(() => {
|
|
339
|
+
buildTreemapBundle({
|
|
340
|
+
writeBundleRequestsByBundleId: mockWriteBundleRequestsByBundleId,
|
|
341
|
+
node: mockNode,
|
|
342
|
+
projectRoot: '/project',
|
|
343
|
+
repositoryRoot: '/project',
|
|
344
|
+
bundleGraph: mockBundleGraph,
|
|
345
|
+
});
|
|
346
|
+
}, Error);
|
|
347
|
+
});
|
|
348
|
+
});
|