uni-oaview 1.9.13 → 1.9.14

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.
@@ -43,6 +43,8 @@
43
43
  secretArray.push(count);
44
44
  if (secretArray.join('') === secret) {
45
45
  showLog.value = true;
46
+ /** 如果秘钥正确则进入调试模式 */
47
+ uni.setStorageSync('isDebug', true);
46
48
  }
47
49
  } else {
48
50
  clickCount = 0;
@@ -38,6 +38,7 @@
38
38
  <script lang="ts" setup>
39
39
  import { computed, onBeforeUnmount, ref, shallowRef } from 'vue';
40
40
  import awesomeDisplayInfo from './awesome-display-info.vue';
41
+ import { stringifyForSearch } from './utils';
41
42
  import { nativeEventSubject, getNativeEventLogs } from 'uniapp-log-sdk';
42
43
 
43
44
  interface NativeEventLog {
@@ -125,20 +126,10 @@
125
126
 
126
127
  const normalizeKeyword = (value: string): string => value.trim().toLowerCase();
127
128
 
128
- const safeStringify = (value: unknown): string => {
129
- if (value === null || value === undefined) return '';
130
- if (typeof value === 'string') return value;
131
- try {
132
- return JSON.stringify(value);
133
- } catch (error) {
134
- return String(value);
135
- }
136
- };
137
-
138
129
  const matchesKeyword = (meta: NativeEventLogMeta, keywordValue: string): boolean => {
139
130
  if (!keywordValue) return true;
140
131
  const detail = getNativeEventDetail(meta.id);
141
- const searchText = `${meta.title} ${meta.key} ${safeStringify(detail?.params)} ${safeStringify(
132
+ const searchText = `${meta.title} ${meta.key} ${stringifyForSearch(detail?.params)} ${stringifyForSearch(
142
133
  detail?.response,
143
134
  )}`.toLowerCase();
144
135
  return searchText.includes(keywordValue);
@@ -1,12 +1,121 @@
1
1
  const MAX_DEPTH = 10;
2
2
  const MAX_ARRAY_LENGTH = 100;
3
- const MAX_STRING_LENGTH = 10000;
3
+ const MAX_OBJECT_KEYS = 100;
4
+ const MAX_STRING_LENGTH = 200;
5
+ const MAX_READABLE_PREVIEW_LENGTH = 200;
6
+ const MAX_UNREADABLE_PREVIEW_LENGTH = 50;
7
+ const MAX_SEARCH_DEPTH = 4;
8
+ const MAX_SEARCH_ARRAY_LENGTH = 20;
9
+ const MAX_SEARCH_OBJECT_KEYS = 20;
4
10
 
5
11
  interface RichTextNode {
6
- type: string;
12
+ type: 'text';
7
13
  text: string;
8
14
  }
9
15
 
16
+ const isPlainObject = (value: unknown): value is Record<string, unknown> => {
17
+ return Object.prototype.toString.call(value) === '[object Object]';
18
+ };
19
+
20
+ const isLikelyEncodedText = (value: string): boolean => {
21
+ if (value.length < 32 || /\s/.test(value)) {
22
+ return false;
23
+ }
24
+
25
+ return /^[A-Za-z0-9+/=_-]+$/.test(value);
26
+ };
27
+
28
+ const getControlCharacterCount = (value: string): number => {
29
+ let count = 0;
30
+ for (let index = 0; index < value.length; index += 1) {
31
+ const code = value.charCodeAt(index);
32
+ const isControlChar = (code >= 0 && code <= 8) || (code >= 14 && code <= 31) || code === 127;
33
+ if (isControlChar) {
34
+ count += 1;
35
+ }
36
+ }
37
+ return count;
38
+ };
39
+
40
+ const isHumanReadableString = (value: string): boolean => {
41
+ if (!value) {
42
+ return true;
43
+ }
44
+
45
+ if (isLikelyEncodedText(value)) {
46
+ return false;
47
+ }
48
+
49
+ const controlCharacterCount = getControlCharacterCount(value);
50
+ if (controlCharacterCount === 0) {
51
+ return true;
52
+ }
53
+
54
+ return controlCharacterCount / value.length < 0.05;
55
+ };
56
+
57
+ const buildStringPreview = (value: string): string => {
58
+ const previewLength = isHumanReadableString(value) ? MAX_READABLE_PREVIEW_LENGTH : MAX_UNREADABLE_PREVIEW_LENGTH;
59
+
60
+ if (value.length <= previewLength) {
61
+ return value;
62
+ }
63
+
64
+ return `${value.slice(0, previewLength)}...`;
65
+ };
66
+
67
+ const formatString = (value: string): string => {
68
+ const preview = buildStringPreview(value);
69
+ if (preview === value) {
70
+ return `"${value}"`;
71
+ }
72
+
73
+ return `"${preview}" (长度 ${value.length})`;
74
+ };
75
+
76
+ const buildSearchText = (value: unknown, depth = 0): string => {
77
+ if (value === null || value === undefined) {
78
+ return '';
79
+ }
80
+
81
+ if (typeof value === 'string') {
82
+ return buildStringPreview(value);
83
+ }
84
+
85
+ if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
86
+ return String(value);
87
+ }
88
+
89
+ if (depth >= MAX_SEARCH_DEPTH) {
90
+ return '[...]';
91
+ }
92
+
93
+ if (Array.isArray(value)) {
94
+ const items = value.slice(0, MAX_SEARCH_ARRAY_LENGTH).map((item) => buildSearchText(item, depth + 1));
95
+ const suffix = value.length > MAX_SEARCH_ARRAY_LENGTH ? ` ...(${value.length})` : '';
96
+ return `[${items.join(', ')}${suffix}]`;
97
+ }
98
+
99
+ if (isPlainObject(value)) {
100
+ const keys = Object.keys(value);
101
+ const items = keys
102
+ .slice(0, MAX_SEARCH_OBJECT_KEYS)
103
+ .map((key) => `${key}:${buildSearchText(value[key], depth + 1)}`);
104
+ const suffix = keys.length > MAX_SEARCH_OBJECT_KEYS ? ` ...(${keys.length})` : '';
105
+ return `{${items.join(', ')}${suffix}}`;
106
+ }
107
+
108
+ try {
109
+ return String(value);
110
+ } catch (error) {
111
+ return '[unserializable]';
112
+ }
113
+ };
114
+
115
+ export const stringifyForSearch = (value: unknown): string => {
116
+ return buildSearchText(value);
117
+ };
118
+
10
119
  export const formatJson = (data: any, indent = 0): RichTextNode[] => {
11
120
  const indentStr = ' '.repeat(indent);
12
121
 
@@ -62,13 +171,23 @@ const formatArray = (data: any[], indent: number, indentStr: string): RichTextNo
62
171
  const formatObject = (data: Record<string, any>, indent: number, indentStr: string): RichTextNode[] => {
63
172
  let formatted: RichTextNode[] = [{ type: 'text', text: '{\n' }];
64
173
  const keys = Object.keys(data);
65
- keys.forEach((key, index) => {
174
+ const displayKeys = keys.slice(0, MAX_OBJECT_KEYS);
175
+
176
+ displayKeys.forEach((key, index) => {
66
177
  formatted.push({ type: 'text', text: indentStr + ' '.repeat(4) + key + ': ' });
67
178
  formatted.push(...formatJson(data[key], indent + 4));
68
- if (index < keys.length - 1) {
179
+ if (index < displayKeys.length - 1 || keys.length > MAX_OBJECT_KEYS) {
69
180
  formatted.push({ type: 'text', text: ',\n' });
70
181
  }
71
182
  });
183
+
184
+ if (keys.length > MAX_OBJECT_KEYS) {
185
+ formatted.push({
186
+ type: 'text',
187
+ text: indentStr + ` ... (共 ${keys.length} 个键,显示 ${displayKeys.length} 个)\n`,
188
+ });
189
+ }
190
+
72
191
  formatted.push({ type: 'text', text: '\n' + indentStr + '}' });
73
192
 
74
193
  return formatted;
@@ -76,14 +195,8 @@ const formatObject = (data: Record<string, any>, indent: number, indentStr: stri
76
195
 
77
196
  const formatPrimitive = (data: any): RichTextNode[] => {
78
197
  if (typeof data === 'string') {
79
- // 字符串超过长度限制时截断
80
- if (data.length > MAX_STRING_LENGTH) {
81
- return [
82
- {
83
- type: 'text',
84
- text: `"${data.slice(0, MAX_STRING_LENGTH)}..." (长度 ${data.length})`,
85
- },
86
- ];
198
+ if (data.length > MAX_STRING_LENGTH || !isHumanReadableString(data)) {
199
+ return [{ type: 'text', text: formatString(data) }];
87
200
  }
88
201
  return [{ type: 'text', text: `"${data}"` }];
89
202
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uni-oaview",
3
- "version": "1.9.13",
3
+ "version": "1.9.14",
4
4
  "description": "uniapp小程序组件库",
5
5
  "main": "dist/index.esm.js",
6
6
  "typings": "dist/index.d.ts",