@pubinfo-pr/devtools 0.203.1 → 0.203.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/client/assets/Navbar-D8ux538U.css +18 -0
  2. package/dist/client/assets/Navbar-DCdslOKs.js +219 -0
  3. package/dist/client/assets/PanelGrids-Bq_2z9g3.js +9 -0
  4. package/dist/client/assets/SelectTabs-Chnu7x16.js +171 -0
  5. package/dist/client/assets/_plugin-vue_export-helper-D8E0syuh.js +6 -0
  6. package/dist/client/assets/component-Qe9twpoz.js +468 -0
  7. package/dist/client/assets/{core-DZ0_U_pO.js → core-D6JqxgYq.js} +134 -133
  8. package/dist/client/assets/{engine-oniguruma-Cxk0otvy.js → engine-oniguruma-n-bafM3H.js} +8 -8
  9. package/dist/client/assets/{fetch-Df05JmPt.js → fetch-CwAFBmMG.js} +122 -6
  10. package/dist/client/assets/import-DV9l8S2T.js +375 -0
  11. package/dist/client/assets/{index-Cn9-H915.js → index-ByOJyids.js} +1174 -1123
  12. package/dist/client/assets/index-DNthkvua.css +443 -0
  13. package/dist/client/assets/issue-BHrGN1_d.css +10 -0
  14. package/dist/client/assets/issue-MdUzHAB3.js +130 -0
  15. package/dist/client/assets/pages-D4LiKgxN.js +285 -0
  16. package/dist/client/assets/pages-DQ8FtB9Y.css +17 -0
  17. package/dist/client/assets/{server-router-8PynUpe5.css → server-router-B1AB70as.css} +0 -18
  18. package/dist/client/assets/{server-router-BHD-n_Wi.js → server-router-DuEpkdvh.js} +26 -238
  19. package/dist/client/assets/vue-DZSPIjN6.js +27 -0
  20. package/dist/client/component.svg +1 -0
  21. package/dist/client/import.svg +1 -0
  22. package/dist/client/index.html +2 -2
  23. package/dist/client/issue.svg +1 -0
  24. package/dist/client/logo.svg +1 -0
  25. package/dist/constants.d.mts +1 -2
  26. package/dist/dirs.mjs +15 -1
  27. package/dist/index.d.mts +0 -15
  28. package/dist/index.mjs +1968 -52
  29. package/dist/panel/index.d.mts +1 -0
  30. package/dist/panel/index.mjs +75 -3776
  31. package/package.json +29 -18
  32. package/dist/client/assets/index-Blntvu93.css +0 -443
  33. package/dist/client/assets/pages-BdQpgtx4.js +0 -20
  34. package/dist/client/assets/vue-Be3tcD1h.js +0 -27
  35. package/dist/dirs2.mjs +0 -17
@@ -1,4 +1,4 @@
1
- import { B as effectScope, C as nextTick, F as watch, G as readonly, H as isRef, J as shallowRef, K as ref, T as onMounted, U as onScopeDispose, V as getCurrentScope, X as toValue, Y as toRef$1, Z as unref, _ as defineComponent, q as shallowReadonly, u as computed, v as getCurrentInstance, z as customRef } from "./index-Cn9-H915.js";
1
+ import { $ as toRef$1, E as nextTick, G as isRef, H as customRef, J as readonly, K as onScopeDispose, M as renderSlot, O as onMounted, Q as toRaw, R as watch, U as effectScope, W as getCurrentScope, X as shallowReadonly, Y as ref, Z as shallowRef, b as defineComponent, et as toValue, f as computed, g as createElementBlock, k as openBlock, tt as unref, x as getCurrentInstance } from "./index-ByOJyids.js";
2
2
  function tryOnScopeDispose(fn, failSilently) {
3
3
  if (getCurrentScope()) {
4
4
  onScopeDispose(fn, failSilently);
@@ -89,6 +89,19 @@ function promiseTimeout(ms, throwOnTimeout = false, reason = "Timeout") {
89
89
  else setTimeout(resolve, ms);
90
90
  });
91
91
  }
92
+ function createSingletonPromise(fn) {
93
+ let _promise;
94
+ function wrapper() {
95
+ if (!_promise) _promise = fn();
96
+ return _promise;
97
+ }
98
+ wrapper.reset = async () => {
99
+ const _prev = _promise;
100
+ _promise = void 0;
101
+ if (_prev) await _prev;
102
+ };
103
+ return wrapper;
104
+ }
92
105
  function containsProp(obj, ...props) {
93
106
  return props.some((k) => k in obj);
94
107
  }
@@ -167,7 +180,6 @@ function watchPausable(source, cb, options = {}) {
167
180
  isActive
168
181
  };
169
182
  }
170
- var pausableWatch = watchPausable;
171
183
  function tryOnMounted(fn, sync = true, target) {
172
184
  if (getLifeCycleTarget(target)) onMounted(fn, target);
173
185
  else if (sync) fn();
@@ -345,7 +357,7 @@ function keysToCamelKebabCase(obj) {
345
357
  }
346
358
  var defaultWindow = isClient ? window : void 0;
347
359
  isClient && window.document;
348
- isClient && window.navigator;
360
+ var defaultNavigator = isClient ? window.navigator : void 0;
349
361
  isClient && window.location;
350
362
  function unrefElement(elRef) {
351
363
  var _$el;
@@ -480,6 +492,94 @@ function useSupported(callback) {
480
492
  return Boolean(callback());
481
493
  });
482
494
  }
495
+ function usePermission(permissionDesc, options = {}) {
496
+ const { controls = false, navigator: navigator$1 = defaultNavigator } = options;
497
+ const isSupported = /* @__PURE__ */ useSupported(() => navigator$1 && "permissions" in navigator$1);
498
+ const permissionStatus = shallowRef();
499
+ const desc = typeof permissionDesc === "string" ? { name: permissionDesc } : permissionDesc;
500
+ const state = shallowRef();
501
+ const update = () => {
502
+ var _permissionStatus$val, _permissionStatus$val2;
503
+ state.value = (_permissionStatus$val = (_permissionStatus$val2 = permissionStatus.value) === null || _permissionStatus$val2 === void 0 ? void 0 : _permissionStatus$val2.state) !== null && _permissionStatus$val !== void 0 ? _permissionStatus$val : "prompt";
504
+ };
505
+ useEventListener(permissionStatus, "change", update, { passive: true });
506
+ const query = createSingletonPromise(async () => {
507
+ if (!isSupported.value) return;
508
+ if (!permissionStatus.value) try {
509
+ permissionStatus.value = await navigator$1.permissions.query(desc);
510
+ } catch (_unused) {
511
+ permissionStatus.value = void 0;
512
+ } finally {
513
+ update();
514
+ }
515
+ if (controls) return toRaw(permissionStatus.value);
516
+ });
517
+ query();
518
+ if (controls) return {
519
+ state,
520
+ isSupported,
521
+ query
522
+ };
523
+ else return state;
524
+ }
525
+ function useClipboard(options = {}) {
526
+ const { navigator: navigator$1 = defaultNavigator, read = false, source, copiedDuring = 1500, legacy = false } = options;
527
+ const isClipboardApiSupported = /* @__PURE__ */ useSupported(() => navigator$1 && "clipboard" in navigator$1);
528
+ const permissionRead = usePermission("clipboard-read");
529
+ const permissionWrite = usePermission("clipboard-write");
530
+ const isSupported = computed(() => isClipboardApiSupported.value || legacy);
531
+ const text = shallowRef("");
532
+ const copied = shallowRef(false);
533
+ const timeout = useTimeoutFn(() => copied.value = false, copiedDuring, { immediate: false });
534
+ async function updateText() {
535
+ let useLegacy = !(isClipboardApiSupported.value && isAllowed(permissionRead.value));
536
+ if (!useLegacy) try {
537
+ text.value = await navigator$1.clipboard.readText();
538
+ } catch (_unused) {
539
+ useLegacy = true;
540
+ }
541
+ if (useLegacy) text.value = legacyRead();
542
+ }
543
+ if (isSupported.value && read) useEventListener(["copy", "cut"], updateText, { passive: true });
544
+ async function copy(value = toValue(source)) {
545
+ if (isSupported.value && value != null) {
546
+ let useLegacy = !(isClipboardApiSupported.value && isAllowed(permissionWrite.value));
547
+ if (!useLegacy) try {
548
+ await navigator$1.clipboard.writeText(value);
549
+ } catch (_unused2) {
550
+ useLegacy = true;
551
+ }
552
+ if (useLegacy) legacyCopy(value);
553
+ text.value = value;
554
+ copied.value = true;
555
+ timeout.start();
556
+ }
557
+ }
558
+ function legacyCopy(value) {
559
+ const ta = document.createElement("textarea");
560
+ ta.value = value;
561
+ ta.style.position = "absolute";
562
+ ta.style.opacity = "0";
563
+ ta.setAttribute("readonly", "");
564
+ document.body.appendChild(ta);
565
+ ta.select();
566
+ document.execCommand("copy");
567
+ ta.remove();
568
+ }
569
+ function legacyRead() {
570
+ var _document$getSelectio, _document, _document$getSelectio2;
571
+ return (_document$getSelectio = (_document = document) === null || _document === void 0 || (_document$getSelectio2 = _document.getSelection) === null || _document$getSelectio2 === void 0 || (_document$getSelectio2 = _document$getSelectio2.call(_document)) === null || _document$getSelectio2 === void 0 ? void 0 : _document$getSelectio2.toString()) !== null && _document$getSelectio !== void 0 ? _document$getSelectio : "";
572
+ }
573
+ function isAllowed(status) {
574
+ return status === "granted" || status === "prompt";
575
+ }
576
+ return {
577
+ isSupported,
578
+ text: readonly(text),
579
+ copied: readonly(copied),
580
+ copy
581
+ };
582
+ }
483
583
  function cloneFnJSON(source) {
484
584
  return JSON.parse(JSON.stringify(source));
485
585
  }
@@ -547,7 +647,7 @@ function useStorage(key, defaults$1, storage, options = {}) {
547
647
  const rawInit = toValue(defaults$1);
548
648
  const type = guessSerializerType(rawInit);
549
649
  const serializer = (_options$serializer = options.serializer) !== null && _options$serializer !== void 0 ? _options$serializer : StorageSerializers[type];
550
- const { pause: pauseWatch, resume: resumeWatch } = pausableWatch(data, (newValue) => write(newValue), {
650
+ const { pause: pauseWatch, resume: resumeWatch } = watchPausable(data, (newValue) => write(newValue), {
551
651
  flush,
552
652
  deep,
553
653
  eventFilter
@@ -985,7 +1085,23 @@ function useVModel(props, key, emit, options = {}) {
985
1085
  }
986
1086
  });
987
1087
  }
1088
+ var _hoisted_1 = { class: "n-badge" };
1089
+ var Badge_default = /* @__PURE__ */ defineComponent({
1090
+ name: "Badge",
1091
+ __name: "Badge",
1092
+ setup(__props) {
1093
+ return (_ctx, _cache) => {
1094
+ return openBlock(), createElementBlock("span", _hoisted_1, [renderSlot(_ctx.$slots, "default")]);
1095
+ };
1096
+ }
1097
+ });
988
1098
  var API_ROOT = "/__pubinfo_devtools_api";
989
- const infoFetch = useFetch(`${API_ROOT}`).json();
1099
+ const overviewFetch = useFetch(`${API_ROOT}/overview`, { immediate: false }).json();
990
1100
  const apiListFetch = useFetch(`${API_ROOT}/api-list`, { immediate: false }).json();
991
- export { useElementSize as a, createSharedComposable as c, onClickOutside as i, infoFetch as n, useLocalStorage as o, createReusableTemplate as r, useVModel as s, apiListFetch as t };
1101
+ const componentUsageFetch = useFetch(`${API_ROOT}/component-usage`, { immediate: false }).json();
1102
+ const importUsageFetch = useFetch(`${API_ROOT}/import-usage`, { immediate: false }).json();
1103
+ function usePackageVersion(packageName) {
1104
+ return useFetch(`${API_ROOT}/package-version?package=${encodeURIComponent(packageName)}`, { immediate: false }).json();
1105
+ }
1106
+ useFetch(`${API_ROOT}/environment-info`, { immediate: false }).json();
1107
+ export { usePackageVersion as a, onClickOutside as c, useLocalStorage as d, useVModel as f, overviewFetch as i, useClipboard as l, createSharedComposable as m, componentUsageFetch as n, Badge_default as o, createEventHook as p, importUsageFetch as r, createReusableTemplate as s, apiListFetch as t, useElementSize as u };
@@ -0,0 +1,375 @@
1
+ import { B as withCtx, D as onBeforeUnmount, G as isRef, M as renderSlot, N as resolveComponent, Y as ref, b as defineComponent, f as computed, g as createElementBlock, h as createCommentVNode, it as toDisplayString, j as renderList, k as openBlock, m as createBlock, nt as normalizeClass, p as createBaseVNode, tt as unref, u as Fragment, v as createTextVNode, y as createVNode } from "./index-ByOJyids.js";
2
+ import { a as Icon_default, i as SectionBlock_default, r as Button_default, t as Navbar_default } from "./Navbar-DCdslOKs.js";
3
+ import { l as useClipboard, o as Badge_default, r as importUsageFetch } from "./fetch-CwAFBmMG.js";
4
+ import { n as FilepathItem_default, t as SelectTabs_default } from "./SelectTabs-Chnu7x16.js";
5
+ var _hoisted_1$2 = { class: "flex flex-col gap-1 items-start of-hidden" };
6
+ var _hoisted_2$2 = { class: "flex gap-2 items-center px-3" };
7
+ var _hoisted_3$2 = { class: "text-sm font-mono" };
8
+ var _hoisted_4$1 = {
9
+ key: 0,
10
+ class: "border-t n-border-base max-h-60 w-full of-auto px3 py3"
11
+ };
12
+ var _hoisted_5$1 = { "text-sm": "" };
13
+ var _hoisted_6$1 = { "text-primary": "" };
14
+ var _hoisted_7 = {
15
+ key: 0,
16
+ flex: "~ col gap-2",
17
+ "items-start": "",
18
+ pt3: "",
19
+ "text-sm": "",
20
+ op75: ""
21
+ };
22
+ var ImportDetails_default = /* @__PURE__ */ defineComponent({
23
+ __name: "ImportDetails",
24
+ props: {
25
+ importItem: {},
26
+ dependents: {},
27
+ locations: {}
28
+ },
29
+ setup(__props) {
30
+ const props = __props;
31
+ const referenceEntries = computed(() => {
32
+ const rawLocations = props.locations ?? props.importItem.locations ?? [];
33
+ if (rawLocations.length) return rawLocations.map((location) => ({
34
+ filepath: location.file,
35
+ line: location.line,
36
+ column: location.column
37
+ }));
38
+ return (props.dependents ?? props.importItem.dependents ?? []).map((filepath) => ({ filepath }));
39
+ });
40
+ const sortedReferenceEntries = computed(() => {
41
+ return [...referenceEntries.value].sort((a, b) => {
42
+ if (a.filepath === b.filepath) return (a.line ?? 0) - (b.line ?? 0);
43
+ return a.filepath.localeCompare(b.filepath);
44
+ });
45
+ });
46
+ const referencesCount = computed(() => sortedReferenceEntries.value.length);
47
+ const showDependentsPanel = computed(() => referencesCount.value > 0);
48
+ const importNameForCopy = computed(() => {
49
+ if (props.importItem.camelName) return props.importItem.camelName;
50
+ if (props.importItem.name) return props.importItem.name;
51
+ return "";
52
+ });
53
+ const { copy: copyToClipboard } = useClipboard({ legacy: true });
54
+ const copyState = ref("idle");
55
+ let copyResetHandle;
56
+ const canCopyName = computed(() => Boolean(importNameForCopy.value));
57
+ const nameCopyTooltip = computed(() => {
58
+ if (!canCopyName.value) return "Import name unavailable";
59
+ if (copyState.value === "copied") return "Copied import name";
60
+ if (copyState.value === "error") return "Failed to copy name";
61
+ return "Copy import name";
62
+ });
63
+ const nameCopyLabel = computed(() => {
64
+ if (copyState.value === "copied") return "Copied";
65
+ if (copyState.value === "error") return "Retry";
66
+ return "Copy";
67
+ });
68
+ const nameCopyIcon = computed(() => {
69
+ if (copyState.value === "copied") return "i-carbon-checkmark";
70
+ if (copyState.value === "error") return "i-carbon-warning-alt";
71
+ return "i-carbon-copy";
72
+ });
73
+ function resetCopyState() {
74
+ if (copyResetHandle) clearTimeout(copyResetHandle);
75
+ copyResetHandle = setTimeout(() => {
76
+ copyState.value = "idle";
77
+ copyResetHandle = void 0;
78
+ }, 2e3);
79
+ }
80
+ async function copyImportName() {
81
+ if (!importNameForCopy.value || !canCopyName.value) return;
82
+ try {
83
+ await copyToClipboard(importNameForCopy.value);
84
+ copyState.value = "copied";
85
+ } catch (error) {
86
+ console.error("Failed to copy import name:", error);
87
+ copyState.value = "error";
88
+ } finally {
89
+ resetCopyState();
90
+ }
91
+ }
92
+ onBeforeUnmount(() => {
93
+ if (copyResetHandle) clearTimeout(copyResetHandle);
94
+ });
95
+ return (_ctx, _cache) => {
96
+ const _component_Badge = Badge_default;
97
+ const _component_FilepathItem = FilepathItem_default;
98
+ return openBlock(), createElementBlock("div", _hoisted_1$2, [
99
+ createBaseVNode("div", _hoisted_2$2, [
100
+ createBaseVNode("code", _hoisted_3$2, toDisplayString(__props.importItem.camelName || __props.importItem.name), 1),
101
+ __props.importItem.meta?.docs && typeof __props.importItem.meta.docs === "string" ? (openBlock(), createBlock(unref(Button_default), {
102
+ key: 0,
103
+ title: "Open docs",
104
+ class: "flex-none n-xs",
105
+ to: __props.importItem.meta.docs,
106
+ target: "_blank",
107
+ icon: "i-carbon-catalog"
108
+ }, {
109
+ default: withCtx(() => [..._cache[0] || (_cache[0] = [createTextVNode(" Docs ", -1)])]),
110
+ _: 1
111
+ }, 8, ["to"])) : createCommentVNode("", true),
112
+ createVNode(unref(Button_default), {
113
+ class: "flex-none n-xs",
114
+ disabled: !canCopyName.value,
115
+ icon: nameCopyIcon.value,
116
+ title: nameCopyTooltip.value,
117
+ onClick: copyImportName
118
+ }, {
119
+ default: withCtx(() => [createTextVNode(toDisplayString(nameCopyLabel.value), 1)]),
120
+ _: 1
121
+ }, 8, [
122
+ "disabled",
123
+ "icon",
124
+ "title"
125
+ ]),
126
+ __props.importItem.meta?.category ? (openBlock(), createBlock(_component_Badge, {
127
+ key: 1,
128
+ class: "n-blue",
129
+ title: `Category: ${__props.importItem.meta.category}`
130
+ }, {
131
+ default: withCtx(() => [createTextVNode(toDisplayString(__props.importItem.meta.category), 1)]),
132
+ _: 1
133
+ }, 8, ["title"])) : createCommentVNode("", true)
134
+ ]),
135
+ showDependentsPanel.value ? (openBlock(), createElementBlock("div", _hoisted_4$1, [createBaseVNode("div", _hoisted_5$1, [createBaseVNode("strong", _hoisted_6$1, toDisplayString(referencesCount.value), 1), _cache[1] || (_cache[1] = createBaseVNode("span", { op50: "" }, " references", -1))]), referencesCount.value ? (openBlock(), createElementBlock("div", _hoisted_7, [(openBlock(true), createElementBlock(Fragment, null, renderList(sortedReferenceEntries.value, (item) => {
136
+ return openBlock(), createBlock(_component_FilepathItem, {
137
+ key: `${item.filepath}-${item.line ?? 0}-${item.column ?? 0}`,
138
+ filepath: item.filepath,
139
+ line: item.line,
140
+ column: item.column
141
+ }, null, 8, [
142
+ "filepath",
143
+ "line",
144
+ "column"
145
+ ]);
146
+ }), 128))])) : createCommentVNode("", true)])) : createCommentVNode("", true),
147
+ renderSlot(_ctx.$slots, "default")
148
+ ]);
149
+ };
150
+ }
151
+ });
152
+ var _hoisted_1$1 = { class: "group flex gap-2 w-full items-center rounded px-2 py-1 hoverLbg-active" };
153
+ var _hoisted_2$1 = { class: "text-sm font-mono" };
154
+ var _hoisted_3$1 = {
155
+ key: 0,
156
+ class: "ml--1 text-primary"
157
+ };
158
+ var ImportItem_default = /* @__PURE__ */ defineComponent({
159
+ __name: "ImportItem",
160
+ props: {
161
+ importItem: {},
162
+ dependents: {}
163
+ },
164
+ setup(__props) {
165
+ const props = __props;
166
+ const dependentsList = computed(() => props.dependents ?? props.importItem.dependents ?? []);
167
+ const referenceLocations = computed(() => props.importItem.locations ?? []);
168
+ const referenceCount = computed(() => referenceLocations.value.length || dependentsList.value.length);
169
+ return (_ctx, _cache) => {
170
+ const _component_ImportDetails = ImportDetails_default;
171
+ const _component_VDropdown = resolveComponent("VDropdown");
172
+ const _component_Badge = Badge_default;
173
+ return openBlock(), createElementBlock("div", _hoisted_1$1, [
174
+ createVNode(_component_VDropdown, null, {
175
+ popper: withCtx(() => [createVNode(_component_ImportDetails, {
176
+ "import-item": __props.importItem,
177
+ dependents: dependentsList.value,
178
+ locations: referenceLocations.value,
179
+ class: "w-100 py3"
180
+ }, null, 8, [
181
+ "import-item",
182
+ "dependents",
183
+ "locations"
184
+ ])]),
185
+ default: withCtx(() => [createBaseVNode("button", { class: normalizeClass(["hover:text-primary", referenceCount.value === 0 ? "op50" : ""]) }, [createBaseVNode("code", _hoisted_2$1, toDisplayString(__props.importItem.camelName || __props.importItem.name), 1)], 2)]),
186
+ _: 1
187
+ }),
188
+ referenceCount.value ? (openBlock(), createElementBlock("sup", _hoisted_3$1, " x" + toDisplayString(referenceCount.value), 1)) : createCommentVNode("", true),
189
+ __props.importItem.meta?.category ? (openBlock(), createBlock(_component_Badge, {
190
+ key: 1,
191
+ class: "n-blue",
192
+ title: `Category: ${__props.importItem.meta.category}`
193
+ }, {
194
+ default: withCtx(() => [createTextVNode(toDisplayString(__props.importItem.meta.category), 1)]),
195
+ _: 1
196
+ }, 8, ["title"])) : createCommentVNode("", true),
197
+ renderSlot(_ctx.$slots, "default")
198
+ ]);
199
+ };
200
+ }
201
+ });
202
+ var _hoisted_1 = { class: "relative h-full flex flex-col of-hidden" };
203
+ var _hoisted_2 = { class: "flex items-center gap-2" };
204
+ var _hoisted_3 = { class: "flex-1 of-auto" };
205
+ var _hoisted_4 = { class: "flex flex-col gap-2 px4 py3" };
206
+ var _hoisted_5 = {
207
+ key: 0,
208
+ class: "text-sm text-red op75"
209
+ };
210
+ var _hoisted_6 = {
211
+ key: 1,
212
+ class: "text-sm op50 px2 py1"
213
+ };
214
+ var import_default = /* @__PURE__ */ defineComponent({
215
+ name: "ImportPage",
216
+ __name: "import",
217
+ setup(__props) {
218
+ const search = ref("");
219
+ const filterMode = ref("all");
220
+ const { execute, data, error, isFetching } = importUsageFetch;
221
+ if (!data.value) execute();
222
+ computed(() => data.value?.stats ?? {
223
+ total: 0,
224
+ used: 0,
225
+ unused: 0
226
+ });
227
+ const imports = computed(() => data.value?.imports ?? []);
228
+ const normalizedSearch = computed(() => search.value.trim().toLowerCase());
229
+ const packageStats = computed(() => {
230
+ const map = /* @__PURE__ */ new Map();
231
+ imports.value.forEach((importItem) => {
232
+ if (!map.has(importItem.package)) map.set(importItem.package, {
233
+ total: 0,
234
+ used: 0,
235
+ unused: 0
236
+ });
237
+ const stats = map.get(importItem.package);
238
+ stats.total += 1;
239
+ if (importItem.count > 0) stats.used += 1;
240
+ else stats.unused += 1;
241
+ });
242
+ return map;
243
+ });
244
+ function matchesFilter(importItem, mode) {
245
+ if (mode === "using") return importItem.count > 0;
246
+ if (mode === "not-used") return importItem.count === 0;
247
+ return true;
248
+ }
249
+ function matchesQuery(importItem, query) {
250
+ if (!query) return true;
251
+ return [
252
+ importItem.name,
253
+ importItem.camelName,
254
+ importItem.package,
255
+ ...importItem.dependents
256
+ ].join(" ").toLowerCase().includes(query);
257
+ }
258
+ const filteredImports = computed(() => {
259
+ const query = normalizedSearch.value;
260
+ const mode = filterMode.value;
261
+ return [...imports.value].sort((a, b) => {
262
+ if (a.count === b.count) return a.name.localeCompare(b.name);
263
+ return b.count - a.count;
264
+ }).filter((importItem) => matchesFilter(importItem, mode) && matchesQuery(importItem, query));
265
+ });
266
+ computed(() => filteredImports.value.length);
267
+ const FALLBACK_GROUP_ORDER = Number.MAX_SAFE_INTEGER;
268
+ function resolvePackageGroupMeta(pkg) {
269
+ return {
270
+ label: pkg,
271
+ icon: "i-carbon-function",
272
+ order: FALLBACK_GROUP_ORDER
273
+ };
274
+ }
275
+ const groupedImports = computed(() => {
276
+ const grouped = /* @__PURE__ */ new Map();
277
+ filteredImports.value.forEach((importItem) => {
278
+ if (!grouped.has(importItem.package)) grouped.set(importItem.package, []);
279
+ grouped.get(importItem.package).push(importItem);
280
+ });
281
+ return Array.from(grouped.entries()).map(([pkg, items]) => {
282
+ const meta = resolvePackageGroupMeta(pkg);
283
+ const stats = packageStats.value.get(pkg) ?? {
284
+ total: items.length,
285
+ used: items.filter((item) => item.count > 0).length,
286
+ unused: items.filter((item) => item.count === 0).length
287
+ };
288
+ return {
289
+ id: pkg,
290
+ label: meta.label,
291
+ icon: meta.icon,
292
+ order: meta.order ?? Number.MAX_SAFE_INTEGER,
293
+ items,
294
+ stats
295
+ };
296
+ }).sort((a, b) => {
297
+ if (a.order === b.order) return a.label.localeCompare(b.label);
298
+ return a.order - b.order;
299
+ });
300
+ });
301
+ const emptyStateMessage = computed(() => {
302
+ if (isFetching.value && !imports.value.length) return "正在扫描 Import/Hook 使用情况...";
303
+ if (!imports.value.length) return "还没有可追踪的 Import/Hook。";
304
+ return "没有符合条件的 Import/Hook。";
305
+ });
306
+ const requestError = computed(() => {
307
+ const raw = error.value;
308
+ if (!raw) return "";
309
+ if (typeof raw === "string") return raw;
310
+ if (raw instanceof Error) return raw.message;
311
+ try {
312
+ return JSON.stringify(raw);
313
+ } catch {
314
+ return "获取 Import/Hook 使用数据失败";
315
+ }
316
+ });
317
+ return (_ctx, _cache) => {
318
+ const _component_Icon = Icon_default;
319
+ const _component_SelectTabs = SelectTabs_default;
320
+ const _component_Navbar = Navbar_default;
321
+ const _component_ImportItem = ImportItem_default;
322
+ const _component_SectionBlock = SectionBlock_default;
323
+ return openBlock(), createElementBlock("div", _hoisted_1, [createVNode(_component_Navbar, {
324
+ search: unref(search),
325
+ "onUpdate:search": _cache[1] || (_cache[1] = ($event) => isRef(search) ? search.value = $event : null),
326
+ class: "pb3 flex-none"
327
+ }, {
328
+ default: withCtx(() => [createBaseVNode("div", _hoisted_2, [createVNode(_component_Icon, {
329
+ icon: "i-carbon-filter",
330
+ class: "op50"
331
+ }), createVNode(_component_SelectTabs, {
332
+ modelValue: unref(filterMode),
333
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => isRef(filterMode) ? filterMode.value = $event : null),
334
+ class: "n-primary n-sm",
335
+ options: [
336
+ {
337
+ label: "All",
338
+ value: "all"
339
+ },
340
+ {
341
+ label: "Using",
342
+ value: "using"
343
+ },
344
+ {
345
+ label: "Not used",
346
+ value: "not-used"
347
+ }
348
+ ]
349
+ }, null, 8, ["modelValue"])])]),
350
+ _: 1
351
+ }, 8, ["search"]), createBaseVNode("div", _hoisted_3, [createBaseVNode("div", _hoisted_4, [unref(requestError) ? (openBlock(), createElementBlock("div", _hoisted_5, toDisplayString(unref(requestError)), 1)) : !unref(filteredImports).length ? (openBlock(), createElementBlock("div", _hoisted_6, toDisplayString(unref(emptyStateMessage)), 1)) : (openBlock(true), createElementBlock(Fragment, { key: 2 }, renderList(unref(groupedImports), (group) => {
352
+ return openBlock(), createBlock(_component_SectionBlock, {
353
+ key: group.id,
354
+ text: group.label,
355
+ description: `Total imports: ${group.stats.total}`,
356
+ icon: group.icon
357
+ }, {
358
+ default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(group.items, (importEntry) => {
359
+ return openBlock(), createBlock(_component_ImportItem, {
360
+ key: `${importEntry.package}-${importEntry.name}`,
361
+ "import-item": importEntry,
362
+ dependents: importEntry.dependents
363
+ }, null, 8, ["import-item", "dependents"]);
364
+ }), 128))]),
365
+ _: 2
366
+ }, 1032, [
367
+ "text",
368
+ "description",
369
+ "icon"
370
+ ]);
371
+ }), 128))])])]);
372
+ };
373
+ }
374
+ });
375
+ export { import_default as default };