rn-bundle-analyzer 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -0
- package/dist/builders/treeBuilder.d.ts +2 -0
- package/dist/builders/treeBuilder.js +47 -0
- package/dist/collectors/fileCollector.d.ts +2 -0
- package/dist/collectors/fileCollector.js +27 -0
- package/dist/collectors/inverseDependencyCollector.d.ts +2 -0
- package/dist/collectors/inverseDependencyCollector.js +29 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.js +15 -0
- package/dist/fileInfoCollector.d.ts +4 -0
- package/dist/fileInfoCollector.js +44 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +48 -0
- package/dist/templates/analyse.html +1082 -0
- package/dist/templates/analyse.pug +321 -0
- package/dist/templates/analyseTemplate.d.ts +3 -0
- package/dist/templates/analyseTemplate.js +41 -0
- package/dist/templates/icons-inline.js +27 -0
- package/dist/templates/lucideIcons.d.ts +2 -0
- package/dist/templates/lucideIcons.js +28 -0
- package/dist/templates/tailwindcss.js +83 -0
- package/dist/types.d.ts +41 -0
- package/dist/types.js +2 -0
- package/dist/utils/envSetup.d.ts +1 -0
- package/dist/utils/envSetup.js +21 -0
- package/dist/utils/fileUtils.d.ts +3 -0
- package/dist/utils/fileUtils.js +27 -0
- package/dist/writers/fileInfoWriter.d.ts +12 -0
- package/dist/writers/fileInfoWriter.js +42 -0
- package/dist/writers/inverseDependencyWriter.d.ts +2 -0
- package/dist/writers/inverseDependencyWriter.js +48 -0
- package/dist/writers/treeWriter.d.ts +2 -0
- package/dist/writers/treeWriter.js +26 -0
- package/index.js +1 -0
- package/package.json +24 -0
- package/scripts/compile-pug.js +17 -0
- package/src/builders/treeBuilder.ts +57 -0
- package/src/collectors/fileCollector.ts +24 -0
- package/src/collectors/inverseDependencyCollector.ts +32 -0
- package/src/config.ts +14 -0
- package/src/fileInfoCollector.ts +50 -0
- package/src/index.ts +15 -0
- package/src/templates/analyse-app.js +988 -0
- package/src/templates/analyse.pug +321 -0
- package/src/templates/analyseTemplate.ts +45 -0
- package/src/templates/icons-inline.js +27 -0
- package/src/templates/tailwindcss.js +83 -0
- package/src/types.ts +43 -0
- package/src/utils/envSetup.ts +18 -0
- package/src/utils/fileUtils.ts +21 -0
- package/src/writers/fileInfoWriter.ts +44 -0
- package/src/writers/inverseDependencyWriter.ts +50 -0
- package/src/writers/treeWriter.ts +24 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
//- 报告页唯一手写模板;由运行时直接渲染
|
|
2
|
+
doctype html
|
|
3
|
+
html(lang='zh-CN')
|
|
4
|
+
head
|
|
5
|
+
meta(charset='UTF-8')
|
|
6
|
+
meta(name='viewport' content='width=device-width, initial-scale=1.0')
|
|
7
|
+
title(data-i18n='pageTitle') RN 包分析结果展示
|
|
8
|
+
script(src='./tailwindcss.js')
|
|
9
|
+
script(src='./icons-inline.js')
|
|
10
|
+
script(src='./rn-bundle-files-data.js')
|
|
11
|
+
script(src='./rn-bundle-tree-data.js')
|
|
12
|
+
script(src='./rn-bundle-inverse-deps-data.js')
|
|
13
|
+
script.
|
|
14
|
+
tailwind.config = {
|
|
15
|
+
theme: {
|
|
16
|
+
extend: {
|
|
17
|
+
colors: {
|
|
18
|
+
border: "hsl(214.3 31.8% 91.4%)",
|
|
19
|
+
input: "hsl(214.3 31.8% 91.4%)",
|
|
20
|
+
ring: "hsl(222.2 84% 4.9%)",
|
|
21
|
+
background: "hsl(0 0% 100%)",
|
|
22
|
+
foreground: "hsl(222.2 84% 4.9%)",
|
|
23
|
+
primary: {
|
|
24
|
+
DEFAULT: "hsl(222.2 47.4% 11.2%)",
|
|
25
|
+
foreground: "hsl(210 40% 98%)",
|
|
26
|
+
},
|
|
27
|
+
secondary: {
|
|
28
|
+
DEFAULT: "hsl(210 40% 96%)",
|
|
29
|
+
foreground: "hsl(222.2 84% 4.9%)",
|
|
30
|
+
},
|
|
31
|
+
muted: {
|
|
32
|
+
DEFAULT: "hsl(210 40% 96%)",
|
|
33
|
+
foreground: "hsl(215.4 16.3% 46.9%)",
|
|
34
|
+
},
|
|
35
|
+
accent: {
|
|
36
|
+
DEFAULT: "hsl(210 40% 96%)",
|
|
37
|
+
foreground: "hsl(222.2 84% 4.9%)",
|
|
38
|
+
},
|
|
39
|
+
card: {
|
|
40
|
+
DEFAULT: "hsl(0 0% 100%)",
|
|
41
|
+
foreground: "hsl(222.2 84% 4.9%)",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
style.
|
|
48
|
+
:root {
|
|
49
|
+
color-scheme: light;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.tree-node {
|
|
53
|
+
transition: all 0.2s ease;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.tree-node.collapsed .tree-children {
|
|
57
|
+
display: none;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.tree-toggle {
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
user-select: none;
|
|
63
|
+
border-radius: 4px;
|
|
64
|
+
transition: background-color 0.2s ease;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.tree-toggle:hover {
|
|
68
|
+
background-color: hsl(210 40% 94%);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.tree-expand-icon {
|
|
72
|
+
transition: transform 0.2s ease;
|
|
73
|
+
display: inline-flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
justify-content: center;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.tree-node.collapsed .tree-expand-icon {
|
|
79
|
+
transform: rotate(0deg);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.tree-node:not(.collapsed) .tree-expand-icon {
|
|
83
|
+
transform: rotate(90deg);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.tree-children {
|
|
87
|
+
border-left: 1px solid hsl(214.3 31.8% 91.4%);
|
|
88
|
+
margin-left: 8px;
|
|
89
|
+
padding-left: 8px;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.tree-item {
|
|
93
|
+
display: flex;
|
|
94
|
+
align-items: center;
|
|
95
|
+
padding: 4px 8px;
|
|
96
|
+
border-radius: 4px;
|
|
97
|
+
transition: background-color 0.2s ease;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.tree-item:hover {
|
|
101
|
+
background-color: hsl(210 40% 96%);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.tree-folder-icon {
|
|
105
|
+
color: hsl(45 100% 51%);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.tree-file-icon {
|
|
109
|
+
color: hsl(215.4 16.3% 46.9%);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.progress-bar {
|
|
113
|
+
background: linear-gradient(90deg, #3b82f6 0%, #1d4ed8 100%);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.lucide-inline {
|
|
117
|
+
display: inline-block;
|
|
118
|
+
vertical-align: middle;
|
|
119
|
+
flex-shrink: 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
body {
|
|
123
|
+
background: radial-gradient(circle at top right, rgba(59, 130, 246, 0.15), transparent 40%),
|
|
124
|
+
radial-gradient(circle at top left, rgba(139, 92, 246, 0.12), transparent 35%);
|
|
125
|
+
min-height: 100vh;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.hero-card {
|
|
129
|
+
background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(241, 245, 249, 0.9));
|
|
130
|
+
backdrop-filter: blur(4px);
|
|
131
|
+
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.08);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.surface-card {
|
|
135
|
+
background: rgba(255, 255, 255, 0.92);
|
|
136
|
+
backdrop-filter: blur(5px);
|
|
137
|
+
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.06);
|
|
138
|
+
transition: box-shadow 0.2s ease, transform 0.2s ease;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.surface-card:hover {
|
|
142
|
+
box-shadow: 0 12px 28px rgba(15, 23, 42, 0.1);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.pill-button {
|
|
146
|
+
border-radius: 9999px;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.lang-toggle-btn.active {
|
|
150
|
+
background: hsl(222.2 47.4% 11.2%);
|
|
151
|
+
color: hsl(210 40% 98%);
|
|
152
|
+
box-shadow: 0 4px 12px rgba(15, 23, 42, 0.22);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.table-scroll::-webkit-scrollbar {
|
|
156
|
+
height: 8px;
|
|
157
|
+
width: 8px;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.table-scroll::-webkit-scrollbar-thumb {
|
|
161
|
+
background-color: rgba(100, 116, 139, 0.35);
|
|
162
|
+
border-radius: 9999px;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.table-scroll::-webkit-scrollbar-track {
|
|
166
|
+
background: transparent;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
body.bg-background.text-foreground
|
|
170
|
+
.min-h-screen
|
|
171
|
+
header.hero-card.border-b.border-border.sticky.top-0.z-20
|
|
172
|
+
.container.mx-auto.px-4.py-6
|
|
173
|
+
.flex.items-center.justify-between
|
|
174
|
+
div
|
|
175
|
+
h1.text-3xl.font-bold.bg-gradient-to-r.from-blue-600.to-indigo-500.bg-clip-text.text-transparent(data-i18n='headerTitle') RN 包分析结果
|
|
176
|
+
p.text-muted-foreground.mt-2(data-i18n='headerSubtitle') React Native 项目包大小分析与可视化
|
|
177
|
+
.flex.items-center.space-x-4
|
|
178
|
+
.inline-flex.items-center.rounded-full.bg-muted.p-1.shadow-sm
|
|
179
|
+
button.lang-toggle-btn.active.px-3.py-1.text-xs.font-semibold.rounded-full.transition-all(type='button' data-lang='zh') 中文
|
|
180
|
+
button.lang-toggle-btn.px-3.py-1.text-xs.font-semibold.rounded-full.transition-all(type='button' data-lang='en') EN
|
|
181
|
+
.text-right
|
|
182
|
+
.text-sm.text-muted-foreground(data-i18n='totalFiles') 总文件数
|
|
183
|
+
#total-files.text-2xl.font-bold -
|
|
184
|
+
.text-right
|
|
185
|
+
.text-sm.text-muted-foreground(data-i18n='totalSize') 总大小
|
|
186
|
+
#total-size.text-2xl.font-bold -
|
|
187
|
+
main.container.mx-auto.px-4.py-8(class='max-w-[1200px]')
|
|
188
|
+
.border-b.border-border.mb-6
|
|
189
|
+
nav.flex.space-x-8
|
|
190
|
+
button.tab-button.active.py-2.px-1.border-b-2.border-primary.text-primary.font-medium(data-tab='files')
|
|
191
|
+
!= icons('list', 'inline w-4 h-4 mr-2')
|
|
192
|
+
span(data-i18n='tabFiles') 文件列表视图
|
|
193
|
+
button(class='tab-button py-2 px-1 border-b-2 border-transparent text-muted-foreground hover:text-foreground font-medium' data-tab='tree')
|
|
194
|
+
!= icons('folder-tree', 'inline w-4 h-4 mr-2')
|
|
195
|
+
span(data-i18n='tabTree') 目录树视图
|
|
196
|
+
button(class='tab-button py-2 px-1 border-b-2 border-transparent text-muted-foreground hover:text-foreground font-medium' data-tab='dependencies')
|
|
197
|
+
!= icons('git-fork', 'inline w-4 h-4 mr-2')
|
|
198
|
+
span(data-i18n='tabDependencies') 反向依赖分析
|
|
199
|
+
#files-tab.tab-content
|
|
200
|
+
.mb-6.flex.flex-col(class='sm:flex-row gap-4')
|
|
201
|
+
.flex-1
|
|
202
|
+
.relative
|
|
203
|
+
span(class='absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground w-4 h-4 pointer-events-none')
|
|
204
|
+
!= icons('search', 'w-4 h-4')
|
|
205
|
+
input#search-input(class='w-full pl-10 pr-4 py-2 border border-input rounded-md bg-background focus:outline-none focus:ring-2 focus:ring-ring' type='text' placeholder='搜索文件名或路径...' data-i18n-placeholder='searchFilesPlaceholder')
|
|
206
|
+
.flex.gap-2
|
|
207
|
+
select#extension-filter(class='px-3 py-2 border border-input rounded-md bg-background focus:outline-none focus:ring-2 focus:ring-ring')
|
|
208
|
+
option(value='' data-i18n='allFileTypes') 所有文件类型
|
|
209
|
+
select#sort-select(class='px-3 py-2 border border-input rounded-md bg-background focus:outline-none focus:ring-2 focus:ring-ring')
|
|
210
|
+
option(value='size-desc' data-i18n='sortSizeDesc') 大小 (大到小)
|
|
211
|
+
option(value='size-asc' data-i18n='sortSizeAsc') 大小 (小到大)
|
|
212
|
+
option(value='name-asc' data-i18n='sortNameAsc') 名称 (A-Z)
|
|
213
|
+
option(value='name-desc' data-i18n='sortNameDesc') 名称 (Z-A)
|
|
214
|
+
.surface-card.rounded-xl.border.overflow-hidden(class='border-border/70')
|
|
215
|
+
.table-scroll.overflow-x-auto
|
|
216
|
+
table.w-full
|
|
217
|
+
thead.bg-muted
|
|
218
|
+
tr
|
|
219
|
+
th.px-6.py-3.text-left.text-xs.font-medium.text-muted-foreground.uppercase.tracking-wider(data-i18n='colFilePath') 文件路径
|
|
220
|
+
th.px-6.py-3.text-left.text-xs.font-medium.text-muted-foreground.uppercase.tracking-wider(data-i18n='colSize') 大小
|
|
221
|
+
th.px-6.py-3.text-left.text-xs.font-medium.text-muted-foreground.uppercase.tracking-wider(data-i18n='colType') 类型
|
|
222
|
+
th.px-6.py-3.text-left.text-xs.font-medium.text-muted-foreground.uppercase.tracking-wider(data-i18n='colModified') 修改时间
|
|
223
|
+
th.px-6.py-3.text-left.text-xs.font-medium.text-muted-foreground.uppercase.tracking-wider(data-i18n='colInverseDeps') 反向依赖
|
|
224
|
+
tbody#files-table-body(class='divide-y divide-border')
|
|
225
|
+
.mt-6.flex.items-center.justify-between
|
|
226
|
+
.text-sm.text-muted-foreground
|
|
227
|
+
span(data-i18n='show') 显示
|
|
228
|
+
|
|
|
229
|
+
span#files-range 0-0
|
|
230
|
+
span(data-i18n='itemsSepA') 项,共
|
|
231
|
+
span#files-total 0
|
|
232
|
+
span(data-i18n='itemsSepB') 项
|
|
233
|
+
.flex.items-center.space-x-2
|
|
234
|
+
button#prev-page(class='px-3 py-1 border border-border rounded text-sm hover:bg-accent disabled:opacity-50' data-i18n='prevPage') 上一页
|
|
235
|
+
span#page-info.px-3.py-1.text-sm 1 / 1
|
|
236
|
+
button#next-page(class='px-3 py-1 border border-border rounded text-sm hover:bg-accent disabled:opacity-50' data-i18n='nextPage') 下一页
|
|
237
|
+
#tree-tab.tab-content.hidden
|
|
238
|
+
.surface-card.rounded-xl.border.p-6(class='border-border/70')
|
|
239
|
+
.mb-4.space-y-4
|
|
240
|
+
.flex.flex-col(class='sm:flex-row gap-4')
|
|
241
|
+
input#tree-search(class='flex-1 px-4 py-2 border border-input rounded-md bg-background focus:outline-none focus:ring-2 focus:ring-ring' type='text' placeholder='搜索目录或文件...' data-i18n-placeholder='searchTreePlaceholder')
|
|
242
|
+
.flex.gap-2
|
|
243
|
+
button#expand-all-btn(class='px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors flex items-center')
|
|
244
|
+
!= icons('chevrons-down', 'w-4 h-4 mr-2')
|
|
245
|
+
span(data-i18n='expandAll') 全部展开
|
|
246
|
+
button#collapse-all-btn(class='px-4 py-2 bg-secondary text-secondary-foreground rounded-md hover:bg-secondary/80 transition-colors flex items-center')
|
|
247
|
+
!= icons('chevrons-up', 'w-4 h-4 mr-2')
|
|
248
|
+
span(data-i18n='collapseAll') 全部折叠
|
|
249
|
+
#tree-container.font-mono.text-sm
|
|
250
|
+
#dependencies-tab.tab-content.hidden
|
|
251
|
+
.grid.grid-cols-1.gap-6.mb-6(class='md:grid-cols-4')
|
|
252
|
+
.surface-card.rounded-xl.border.p-4(class='border-border/70')
|
|
253
|
+
.flex.items-center
|
|
254
|
+
!= icons('file-text', 'w-8 h-8 text-blue-500 mr-3')
|
|
255
|
+
div
|
|
256
|
+
#dep-total-files.text-2xl.font-bold -
|
|
257
|
+
.text-sm.text-muted-foreground(data-i18n='totalFiles') 总文件数
|
|
258
|
+
.surface-card.rounded-xl.border.p-4(class='border-border/70')
|
|
259
|
+
.flex.items-center
|
|
260
|
+
!= icons('git-fork', 'w-8 h-8 text-green-500 mr-3')
|
|
261
|
+
div
|
|
262
|
+
#dep-total-dependencies.text-2xl.font-bold -
|
|
263
|
+
.text-sm.text-muted-foreground(data-i18n='totalDependencyRelations') 总依赖关系数
|
|
264
|
+
.surface-card.rounded-xl.border.p-4(class='border-border/70')
|
|
265
|
+
.flex.items-center
|
|
266
|
+
!= icons('trending-up', 'w-8 h-8 text-orange-500 mr-3')
|
|
267
|
+
div
|
|
268
|
+
#dep-average-dependencies.text-2xl.font-bold -
|
|
269
|
+
.text-sm.text-muted-foreground(data-i18n='avgDependencies') 平均依赖数
|
|
270
|
+
.surface-card.rounded-xl.border.p-4(class='border-border/70')
|
|
271
|
+
.flex.items-center
|
|
272
|
+
!= icons('star', 'w-8 h-8 text-purple-500 mr-3')
|
|
273
|
+
div
|
|
274
|
+
#dep-most-depended.text-2xl.font-bold -
|
|
275
|
+
.text-sm.text-muted-foreground(data-i18n='maxDependencies') 最高依赖数
|
|
276
|
+
.surface-card.rounded-xl.border.p-6.mb-6(class='border-border/70')
|
|
277
|
+
h3.text-lg.font-semibold.mb-4.flex.items-center
|
|
278
|
+
!= icons('flame', 'w-5 h-5 mr-2 text-red-500')
|
|
279
|
+
span(data-i18n='topDepsTitle') 热门依赖文件 Top 10
|
|
280
|
+
#top-dependencies-list.space-y-3
|
|
281
|
+
.surface-card.rounded-xl.border.p-6(class='border-border/70')
|
|
282
|
+
.mb-4.flex.flex-col(class='sm:flex-row gap-4')
|
|
283
|
+
.flex-1
|
|
284
|
+
.relative
|
|
285
|
+
span(class='absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground w-4 h-4 pointer-events-none')
|
|
286
|
+
!= icons('search', 'w-4 h-4')
|
|
287
|
+
input#dep-search-input(class='w-full pl-10 pr-4 py-2 border border-input rounded-md bg-background focus:outline-none focus:ring-2 focus:ring-ring' type='text' placeholder='搜索文件路径...' data-i18n-placeholder='searchDepPlaceholder')
|
|
288
|
+
.flex.gap-2
|
|
289
|
+
select#dep-sort-select(class='px-3 py-2 border border-input rounded-md bg-background focus:outline-none focus:ring-2 focus:ring-ring')
|
|
290
|
+
option(value='dependents-desc' data-i18n='sortDepsDesc') 依赖数 (高到低)
|
|
291
|
+
option(value='dependents-asc' data-i18n='sortDepsAsc') 依赖数 (低到高)
|
|
292
|
+
option(value='name-asc' data-i18n='sortFileNameAsc') 文件名 (A-Z)
|
|
293
|
+
option(value='name-desc' data-i18n='sortFileNameDesc') 文件名 (Z-A)
|
|
294
|
+
select#dep-filter-select(class='px-3 py-2 border border-input rounded-md bg-background focus:outline-none focus:ring-2 focus:ring-ring')
|
|
295
|
+
option(value='' data-i18n='allFiles') 所有文件
|
|
296
|
+
option(value='src' data-i18n='srcFiles') 源码文件
|
|
297
|
+
option(value='node_modules' data-i18n='dependencyPackageFiles') 依赖包文件
|
|
298
|
+
option(value='high-deps' data-i18n='highDependencyFiles') 高依赖文件 (>100)
|
|
299
|
+
.table-scroll.overflow-x-auto
|
|
300
|
+
table.w-full
|
|
301
|
+
thead.bg-muted
|
|
302
|
+
tr
|
|
303
|
+
th.px-6.py-3.text-left.text-xs.font-medium.text-muted-foreground.uppercase.tracking-wider(data-i18n='colFilePath') 文件路径
|
|
304
|
+
th.px-6.py-3.text-left.text-xs.font-medium.text-muted-foreground.uppercase.tracking-wider(data-i18n='colDependentCount') 被依赖次数
|
|
305
|
+
th.px-6.py-3.text-left.text-xs.font-medium.text-muted-foreground.uppercase.tracking-wider(data-i18n='colAction') 操作
|
|
306
|
+
tbody#dependencies-table-body(class='divide-y divide-border')
|
|
307
|
+
.mt-6.flex.items-center.justify-between
|
|
308
|
+
.text-sm.text-muted-foreground
|
|
309
|
+
span(data-i18n='show') 显示
|
|
310
|
+
|
|
|
311
|
+
span#dep-range 0-0
|
|
312
|
+
span(data-i18n='itemsSepA') 项,共
|
|
313
|
+
span#dep-total 0
|
|
314
|
+
span(data-i18n='itemsSepB') 项
|
|
315
|
+
.flex.items-center.space-x-2
|
|
316
|
+
button#dep-prev-page(class='px-3 py-1 border border-border rounded text-sm hover:bg-accent disabled:opacity-50' data-i18n='prevPage') 上一页
|
|
317
|
+
span#dep-page-info.px-3.py-1.text-sm 1 / 1
|
|
318
|
+
button#dep-next-page(class='px-3 py-1 border border-border rounded text-sm hover:bg-accent disabled:opacity-50' data-i18n='nextPage') 下一页
|
|
319
|
+
|
|
320
|
+
script
|
|
321
|
+
include analyse-app.js
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import pug from 'pug'
|
|
4
|
+
|
|
5
|
+
type FeatherIcon = { toSvg: (attrs?: Record<string, string>) => string }
|
|
6
|
+
type FeatherModule = { icons: Record<string, FeatherIcon> }
|
|
7
|
+
|
|
8
|
+
const feather = require('feather-icons') as FeatherModule
|
|
9
|
+
const ICON_NAME_MAP: Record<string, string> = {
|
|
10
|
+
'folder-tree': 'folder',
|
|
11
|
+
'git-fork': 'git-branch',
|
|
12
|
+
flame: 'zap',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function svgInner(kebabName: string): string {
|
|
16
|
+
const iconName = ICON_NAME_MAP[kebabName] || kebabName
|
|
17
|
+
const icon = feather.icons[iconName]
|
|
18
|
+
if (!icon) return ''
|
|
19
|
+
const raw = icon.toSvg()
|
|
20
|
+
const match = raw.match(/<svg[^>]*>([\s\S]*)<\/svg>/i)
|
|
21
|
+
return match ? match[1].trim().replace(/\s+/g, ' ') : ''
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function icons(name: string, extraClass?: string): string {
|
|
25
|
+
const inner = svgInner(name)
|
|
26
|
+
if (!inner) return ''
|
|
27
|
+
const cls = extraClass ? `lucide-inline ${extraClass}` : 'lucide-inline'
|
|
28
|
+
return (
|
|
29
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" ' +
|
|
30
|
+
'fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" ' +
|
|
31
|
+
`class="${cls}">${inner}</svg>`
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const templatePath = path.join(__dirname, 'analyse.pug')
|
|
36
|
+
|
|
37
|
+
export const analyseHtml: string = pug.renderFile(templatePath, {
|
|
38
|
+
pretty: true,
|
|
39
|
+
basedir: __dirname,
|
|
40
|
+
icons,
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
export const iconsInlineJs: string = fs.readFileSync(path.join(__dirname, 'icons-inline.js'), 'utf8')
|
|
44
|
+
|
|
45
|
+
export const tailwindJs: string = fs.readFileSync(path.join(__dirname, 'tailwindcss.js'), 'utf8')
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* Icon runtime map for report template. Keep this file in sync manually. */
|
|
2
|
+
(function () {
|
|
3
|
+
var I = {"list":"<path d=\"M3 5h.01\" /> <path d=\"M3 12h.01\" /> <path d=\"M3 19h.01\" /> <path d=\"M8 5h13\" /> <path d=\"M8 12h13\" /> <path d=\"M8 19h13\" />","folder-tree":"<path d=\"M20 10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1h-2.5a1 1 0 0 1-.8-.4l-.9-1.2A1 1 0 0 0 15 3h-2a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1Z\" /> <path d=\"M20 21a1 1 0 0 0 1-1v-3a1 1 0 0 0-1-1h-2.9a1 1 0 0 1-.88-.55l-.42-.85a1 1 0 0 0-.92-.6H13a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1Z\" /> <path d=\"M3 5a2 2 0 0 0 2 2h3\" /> <path d=\"M3 3v13a2 2 0 0 0 2 2h3\" />","git-fork":"<circle cx=\"12\" cy=\"18\" r=\"3\" /> <circle cx=\"6\" cy=\"6\" r=\"3\" /> <circle cx=\"18\" cy=\"6\" r=\"3\" /> <path d=\"M18 9v2c0 .6-.4 1-1 1H7c-.6 0-1-.4-1-1V9\" /> <path d=\"M12 12v3\" />","search":"<path d=\"m21 21-4.34-4.34\" /> <circle cx=\"11\" cy=\"11\" r=\"8\" />","chevrons-down":"<path d=\"m7 6 5 5 5-5\" /> <path d=\"m7 13 5 5 5-5\" />","chevrons-up":"<path d=\"m17 11-5-5-5 5\" /> <path d=\"m17 18-5-5-5 5\" />","file-text":"<path d=\"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\" /> <path d=\"M14 2v4a2 2 0 0 0 2 2h4\" /> <path d=\"M10 9H8\" /> <path d=\"M16 13H8\" /> <path d=\"M16 17H8\" />","trending-up":"<path d=\"M16 7h6v6\" /> <path d=\"m22 7-8.5 8.5-5-5L2 17\" />","star":"<path d=\"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z\" />","flame":"<path d=\"M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z\" />","file":"<path d=\"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\" /> <path d=\"M14 2v4a2 2 0 0 0 2 2h4\" />","package":"<path d=\"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z\" /> <path d=\"M12 22V12\" /> <polyline points=\"3.29 7 12 12 20.71 7\" /> <path d=\"m7.5 4.27 9 5.15\" />","chevron-right":"<path d=\"m9 18 6-6-6-6\" />","folder":"<path d=\"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\" />","x":"<path d=\"M18 6 6 18\" /> <path d=\"m6 6 12 12\" />","info":"<circle cx=\"12\" cy=\"12\" r=\"10\" /> <path d=\"M12 16v-4\" /> <path d=\"M12 8h.01\" />"};
|
|
4
|
+
window.iconSvg = function (name, className) {
|
|
5
|
+
var inner = I[name];
|
|
6
|
+
if (!inner) return '';
|
|
7
|
+
var cls = className ? 'lucide-inline ' + className : 'lucide-inline';
|
|
8
|
+
return (
|
|
9
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="' +
|
|
10
|
+
cls +
|
|
11
|
+
'">' +
|
|
12
|
+
inner +
|
|
13
|
+
'</svg>'
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
window.lucide = {
|
|
17
|
+
createIcons: function () {
|
|
18
|
+
document.querySelectorAll('[data-lucide]').forEach(function (el) {
|
|
19
|
+
var name = el.getAttribute('data-lucide');
|
|
20
|
+
if (!name) return;
|
|
21
|
+
var cls = el.getAttribute('class') || '';
|
|
22
|
+
var svg = window.iconSvg(name, cls);
|
|
23
|
+
if (svg) el.outerHTML = svg;
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
})();
|