#!/usr/bin/env python3 """JCAI one-pager 目标件的底线自检 —— 只守底线,不管设计。 目标件是「带脚本演示页」(照仓里 PRD 方法论):允许 ', ' ', html, flags=re.I) def visible_text(html): """人看得见的正文:去脚本、去注释、去 ', ' ', h, flags=re.I) return re.sub(r'<[^>]*>', ' ', h) def run(path): html = Path(path).read_text(encoding='utf-8') markup = strip_scripts(html) # 剥掉脚本后的标记面(内联事件/外链在这上面查) text = visible_text(html) styles = ''.join(re.findall(r']*>([\s\S]*?)', html, re.I)) checks = [] def c(name, passed, evidence=''): checks.append({'text': name, 'passed': bool(passed), 'evidence': str(evidence)}) m = re.search(r'https?://', html, re.I) c('无外链(样式/字体/图标/脚本全内联)', not m, m.group(0) if m else '0 命中') m = re.search(r'\son[a-z]+=', markup, re.I) c('无内联事件处理器(脚本集中在 script 标签里,平移一剥就净)', not m, m.group(0) if m else '0 命中') c('standalone 可直接打开(doctype + charset)', html.lstrip().lower().startswith(' 在)', ' 总量 ≥ 25KB)', len(styles.encode('utf-8')) >= 25000, '%d 字节' % len(styles.encode('utf-8'))) c('三层壳依序(proto-root → app-shell → jc-stage → jc-report)', bool(re.search(r'proto-root[\s\S]*app-shell[\s\S]*jc-stage[\s\S]*jc-report', html))) c('家族令牌未换色(--brand: #3370ff)', bool(re.search(r'--brand:\s*#3370ff', html))) c('图标是内联精灵( + )', ']*>\s*[a-z0-9_]{2,}\s*<', markup) c('表头不摆 snake_case 内部名(列名用人读名)', not m, m.group(0) if m else '无') c('正文不带 markdown 星号(**)', '**' not in text) c('有 @keyframes 就有 prefers-reduced-motion 守卫', ('@keyframes' not in styles) or ('prefers-reduced-motion' in styles)) c('无 emoji(图标一律精灵 SVG)', not EMOJI.search(text)) c('交付带平移指引(文内含「平移指引」注释段)', '平移指引' in html) return checks def main(): ap = argparse.ArgumentParser() ap.add_argument('file') ap.add_argument('--json', action='store_true') a = ap.parse_args() checks = run(a.file) if a.json: print(json.dumps(checks, ensure_ascii=False, indent=2)) else: for k in checks: mark = 'PASS' if k['passed'] else 'FAIL' tail = (' —— ' + k['evidence']) if (k['evidence'] and not k['passed']) else '' print('%s %s%s' % (mark, k['text'], tail)) n = sum(1 for k in checks if k['passed']) print('%d/%d 通过' % (n, len(checks))) sys.exit(0 if all(k['passed'] for k in checks) else 1) if __name__ == '__main__': main()