#!/usr/bin/env node /** * 代码内定义矢量图标提取与合成工具(TypeScript 版) * * Jetpack Compose 应用的图标来自 `androidx.compose.material:material-icons-*`, * 是 Kotlin 代码生成的 `ImageVector`,编译进 `classes*.dex`,**不进** `res/drawable`, * 也不进 `resources.arsc`。因此本 skill 其余所有基于 `res/` 的步骤都看不见它们: * 转换报告显示「依赖全部满足」,而迁移后的页面一个图标都不显示。 * * 本工具做三件事: * 1. 从 `classes*.dex` 字符串池提取图标引用清单(权威范围,含库内部使用) * 2. 从 Android 源码 `.kt` 提取归属(哪个页面用哪个图标)——dex 无法提供 * 3. 按确定性规则解析到上游 Material Icons 图形,写出 HarmonyOS `base/media/*.svg` * * 规则依据见 ../references/code-vector-icon-rules.md。 * * 零第三方依赖,仅使用 Node 内置模块,可独立分发。 * 需要 Node >= 22.18(原生 strip-types,直接 `node code_vector_icons.ts` 运行)。 * * 用法: * node code_vector_icons.ts --dex --out * [--android-src ] * (--fetch | --snapshot ) * [--ref ] [--json ] * [--attributed-only] [--dry-run] [--quiet] * * --attributed-only: 只为源码中真正引用到的图标产出图形。用于图标库未被 R8 裁剪、 * 整库被打进 APK 的工程(工具会在检测到时给出提示)。 * * 退出码: * 0 全部图标解析成功(或无代码内图标) * 1 存在无法解析的图标(必须记入报告的 unmappable 行) * 2 用法错误 / 路径不存在 / 图形来源不可用 * * 注意:--attributed-only 主动跳过的图标不算失败,不影响退出码。 */ import * as fs from 'node:fs'; import * as path from 'node:path'; // ───────────────────────────────────────────── // 常量 // ───────────────────────────────────────────── /** 上游 google/material-design-icons 固定 commit。移动分支不可复现,必须 pin。 */ const DEFAULT_REF = '50f0603134ce7b70b2d71b686cc13e8b57ccb74c'; const RAW_BASE = 'https://raw.githubusercontent.com/google/material-design-icons/'; /** Compose 风格 → 上游目录名 / 产物文件名后缀 */ const STYLE: Record = { Filled: { dir: 'materialicons', suffix: 'filled' }, Outlined: { dir: 'materialiconsoutlined', suffix: 'outlined' }, Rounded: { dir: 'materialiconsround', suffix: 'round' }, Sharp: { dir: 'materialiconssharp', suffix: 'sharp' }, TwoTone: { dir: 'materialiconstwotone', suffix: 'twotone' }, }; /** * dex 字符串池中的图标名。`Icons.Default` 在 dex 中总是记为 `Filled.*`。 * * 名字必须以大写字母或 `_` 开头:Compose 图标名是 PascalCase,数字开头的加 `_` 前缀。 * 这条约束用于排除 `Outlined.kt` 这类误命中——dex 里存在 Kotlin 源文件名字符串, * 形如 `