dsh-desktop-statusbar 2.2.1 → 3.0.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/lib/holiday.js CHANGED
@@ -17,15 +17,46 @@ const NOTICE_DATE = /(?:(\d{4})年)?(?:(\d{1,2})月)?(\d{1,2})日/g
17
17
  const DAY_MS = 86400000
18
18
  /** 一段假期最长不会超过这个天数,防正则意外把超长区间展开 */
19
19
  const MAX_RANGE_DAYS = 40
20
+ /** HTML 解析的体积上限(字符):真实通知页 100~300KB,2MB 已经非常宽松。
21
+ * 超过就只看前 2MB —— 宁可解析不全,也不能让 host 主线程卡住(见 holidayHtmlToText)。 */
22
+ const HOLIDAY_HTML_MAX = 2 * 1024 * 1024
20
23
 
21
- /** HTML → 纯文本:去脚本、样式与标签,解常见实体。 */
24
+ /**
25
+ * 线性切掉成对标签里的整段内容(`<script ...>...</script>` 这类)。
26
+ * 用 indexOf 前进而不是懒惰量词:找不到闭合标签时直接放弃剩余部分,
27
+ * 复杂度严格 O(n);`/<script[\s\S]*?<\/script>/gi` 在缺闭合时会从每个 `<` 往后扫到文末,
28
+ * 实测 40 万个未闭合 `<script>` 要 6 秒(卡死 host 事件循环)。
29
+ */
30
+ function stripBlocks(text, tag) {
31
+ const open = '<' + tag
32
+ const close = '</' + tag
33
+ const lower = text.toLowerCase()
34
+ let out = ''
35
+ let at = 0
36
+ for (;;) {
37
+ const start = lower.indexOf(open, at)
38
+ if (start === -1) return out + text.slice(at)
39
+ out += text.slice(at, start)
40
+ const end = lower.indexOf(close, start)
41
+ if (end === -1) return out /* 没有闭合:整段丢弃,不再往后扫 */
42
+ const gt = text.indexOf('>', end)
43
+ if (gt === -1) return out
44
+ at = gt + 1
45
+ }
46
+ }
47
+
48
+ /** HTML → 纯文本:去脚本、样式与标签,解常见实体。
49
+ *
50
+ * 这段处理的是**外部网页**(国务院通知),内容不受我们控制,所以两处做了防御:
51
+ * ① 先按长度截断,避免超大文档把主线程占满;
52
+ * ② `<[^<>]+>` 而不是 `<[^>]+>` —— 后者不排除 `<`,大量孤立 `<` 时会反复跨越大段文本,
53
+ * 实测 20 万字符要 12 秒。 */
22
54
  export function holidayHtmlToText(html) {
23
- return String(html === null || html === undefined ? '' : html)
24
- .replace(/<script[\s\S]*?<\/script>/gi, ' ')
25
- .replace(/<style[\s\S]*?<\/style>/gi, ' ')
55
+ const raw = String(html === null || html === undefined ? '' : html).slice(0, HOLIDAY_HTML_MAX)
56
+ return stripBlocks(stripBlocks(raw, 'script'), 'style')
26
57
  .replace(/<br\s*\/?>/gi, '\n')
27
58
  .replace(/<\/p>/gi, '\n')
28
- .replace(/<[^>]+>/g, '')
59
+ .replace(/<[^<>]+>/g, '')
29
60
  .replace(/&nbsp;/g, ' ')
30
61
  .replace(/&amp;/g, '&')
31
62
  .replace(/&lt;/g, '<')
@@ -49,7 +80,9 @@ const pad = (n) => (n < 10 ? '0' + String(n) : String(n))
49
80
  export function parseHolidayNotice(text, year) {
50
81
  const days = new Set()
51
82
  const flat = String(text === null || text === undefined ? '' : text)
52
- .replace(/<[^>]+>/g, ' ')
83
+ .slice(0, HOLIDAY_HTML_MAX)
84
+ /* `[^<>]` 而不是 `[^>]`:理由同 holidayHtmlToText —— 大量孤立 `<` 时会退化 */
85
+ .replace(/<[^<>]+>/g, ' ')
53
86
  .replace(/\s+/g, ' ')
54
87
  /* 只认含"放假"的句子;含"上班"的句子是调休上班日,不能算进空闲 */
55
88
  flat.split(/[。;;\n]/).forEach((sentence) => {