v1.0.10 两件大事:
1. 界面中英双语(英文界面无中文残留)
- 新增 web/i18n.js(约 4200 条词条),零依赖零构建
- 后端下发中文数据走 bt4() 查表翻译;独立模块(upstream/netdetail/
realtime/update)纳入翻译并注册切语言重绘钩子
- 后端「状态/聚合」接口只回稳定枚举+原始数值,不下发中文文案
- 顺带修一个真实 XSS:顶层 const 不挂 window,独立脚本 esc 静默退化成零转义
2. 修掉「文字竖着排/错位」(多分辨率反复暴露)
- 单元格 min-content 只有 1 字宽 → word-break:keep-all + 表头 nowrap
- 依赖卡片正文被标签/按钮挤成 27px → .dep-body{flex:1 1 200px} + flex-wrap
- 裸 flex:1(下限为0)给正文 → 一律改 flex:1 1 <px>
- .dep-item 横向容器直接塞块级子项 → 退回块级
- 关键陷阱:auto-fill 布局屏越宽列数越多单卡越窄,窄屏反而测不出来,
真机审计推进到「逐视图点按钮 + 1920/2560 宽视口 + 中英双语」
- 守卫 t-layout.py 扩到 35 条,12 处反向验证全红
3. 修真缺陷:_link_since() 重启检测被误改成 if False:(注释还写着「已修」),
uptime 归零后相减得负数 → 恢复比对 boot_id
附带:新增 25 个检查器(t-*.py)、排版审计工具链(shot-*/ocr-*/live-*)、
版本号兜底值同步到 1.0.10、.gitignore 收纳 i18n/排版排查的一次性脚本。
110 lines
3.6 KiB
Python
110 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""检查多行字符串拼接错误 —— **委托给 Node 解析器**(权威)。
|
|
|
|
⚠️ 之前自己用正则扫,试了 3 版全是假红:
|
|
v1 把正则字符类 `/[&<>"']/g` 当引号
|
|
v2 忽略了**跨行的模板字符串**(反引号 852 行开、853 行闭)
|
|
v3 忽略了**注释里的中文引号**(「绝不能静默降级」被当成字符串开合)
|
|
|
|
自己写 JS 词法分析器是不现实的 —— **直接用 Node 的解析器**,
|
|
它对字符串/模板/正则/注释的处理是完全正确的(跟浏览器同一套)。
|
|
|
|
只做一件事:把 Node 报的「语法错误 + 行号」翻译成人能懂的提示。
|
|
Node 的报错信息形如:
|
|
SyntaxError: Unexpected string
|
|
app.js:272
|
|
en: 'first '
|
|
+ 'second',
|
|
→ 直接告诉用户「第 272 行这里可能是多行字符串缺 + 号」
|
|
"""
|
|
import io
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
ROOT = os.path.dirname(HERE)
|
|
NODE = None
|
|
for base in (r'C:\Users\lyrz-pve-win10\.workbuddy\binaries\node\versions',
|
|
'/c/Users/lyrz-pve-win10/.workbuddy/binaries/node/versions'):
|
|
if os.path.isdir(base):
|
|
for d in sorted(os.listdir(base), reverse=True):
|
|
p = os.path.join(base, d, 'node.exe' if os.name == 'nt' else 'node')
|
|
if os.path.isfile(p):
|
|
NODE = p
|
|
break
|
|
if NODE:
|
|
break
|
|
if not NODE:
|
|
print('找不到 node,跳过')
|
|
sys.exit(0)
|
|
|
|
TARGETS = ['web/i18n.js', 'web/app.js', 'web/update.js', 'web/upstream.js',
|
|
'web/netdetail.js', 'web/realtime.js']
|
|
|
|
fails = []
|
|
n = 0
|
|
|
|
|
|
def ck(desc, cond, extra=''):
|
|
global n
|
|
n += 1
|
|
print(('ok ' if cond else 'FAIL ') + desc + (' ' + str(extra) if extra else ''))
|
|
if not cond:
|
|
fails.append(desc)
|
|
|
|
|
|
# 写长英文句子时最容易漏的提示
|
|
HINTS = [
|
|
(re.compile(r'Unexpected string', re.I),
|
|
"可能是多行字符串漏了 + 号:\n"
|
|
" en: 'first part '\n"
|
|
" 'second part', ← 这里要写 + 'second part',\n"
|
|
" 英文句子比较长时容易忘,注意每一行末尾都要有 +"),
|
|
(re.compile(r'Invalid or unexpected token', re.I),
|
|
'可能是中文标点(,、)混进了代码,或者引号不成对'),
|
|
(re.compile(r'Unexpected end of input', re.I),
|
|
'可能有未闭合的引号或括号'),
|
|
]
|
|
|
|
print('=== 语法检查(委托 Node 解析器)===')
|
|
for rel in TARGETS:
|
|
p = os.path.join(ROOT, rel)
|
|
if not os.path.isfile(p):
|
|
continue
|
|
r = subprocess.run([NODE, '--check', p], capture_output=True)
|
|
if r.returncode == 0:
|
|
ck('%s 语法正确' % rel, True)
|
|
continue
|
|
err = (r.stderr or b'').decode('utf-8', 'replace')
|
|
m = re.search(r':(\d+)\s*$', err, re.M)
|
|
line = m.group(1) if m else '?'
|
|
hint = ''
|
|
for pat, h in HINTS:
|
|
if pat.search(err):
|
|
hint = h
|
|
break
|
|
# 打印出错行上下文
|
|
try:
|
|
lines = io.open(p, encoding='utf-8').read().split('\n')
|
|
n0 = int(line)
|
|
ctx = '\n'.join(' %4d| %s' % (i + 1, lines[i])
|
|
for i in range(max(0, n0 - 3),
|
|
min(len(lines), n0 + 1)))
|
|
except Exception:
|
|
ctx = ''
|
|
ck('%s 语法正确' % rel, False,
|
|
'\n 第 %s 行:%s%s' % (line, err.strip().split('\n')[0], hint))
|
|
if ctx:
|
|
print(ctx)
|
|
|
|
print()
|
|
print('=' * 56)
|
|
print('语法检查 %d 条,失败 %d 条' % (n, len(fails)))
|
|
for f in fails:
|
|
print(' FAIL: %s' % f)
|
|
sys.exit(1 if fails else 0)
|