diff --git a/docs/superpowers/specs/code-reader/spec.md b/docs/superpowers/specs/code-reader/spec.md index f4fadfa..19cc9a1 100644 --- a/docs/superpowers/specs/code-reader/spec.md +++ b/docs/superpowers/specs/code-reader/spec.md @@ -182,9 +182,9 @@ | health 健康检查 | `activity` | start 启动 | `play` | trait 特质 | `network` | | impl 实现 | `square-function` | module 模块 | `layers` | attribute 编译属性 | `sliders-horizontal` | - 库规则的种类用规则给的图标(`KindBadge.icon`),跟在语言的种类图标后面:SQLAlchemy 数据表 `database`、数据类 `package`、Pydantic 数据模型 `braces`(和类型块同一个图标,颜色不同)、Celery 应用 `server-cog`、定时任务 `calendar-clock`、FastAPI 接口 `globe`、FastAPI 路由器 `network`、React 组件 `atom`、钩子和自定义钩子 `fishing-hook`、事件处理函数 `mouse-pointer-click`、渲染输出 `layout-template`、serde 可序列化 `braces`、thiserror 错误 `triangle-alert`、axum 接口 `globe`、sqlx 查询 `database`、tauri 桌面命令 `square-function`。数据类写了 `frozen=True` 再加一把锁(`lock`,悬停「不可修改」);React 自带的钩子再加一个作用图标(状态 `toggle-right`、副作用 `zap`、引用 `anchor`、性能 `sigma`、上下文 `share-2`、并发 `hourglass`、外部数据源 `database`)。钩子卡片、自定义钩子卡片不带语言的种类图标,左边第一个就是钩子图标(`RuleCard.languageConcepts: false`)。实现块、特质块再由规则 `rust.impl`、`rust.trait` 换成卡片,左边因此有两个「实现」「特质」图标。 + 库规则的种类用规则给的图标(`KindBadge.icon`),跟在语言的种类图标后面:SQLAlchemy 数据表 `database`、数据类 `package`、Pydantic 数据模型 `braces`(和类型块同一个图标,颜色不同)、Celery 应用 `server-cog`、定时任务 `calendar-clock`、FastAPI 接口 `globe`、FastAPI 路由器 `network`、React 组件 `atom`、自定义钩子和钩子返回值 / 钩子调用 `fishing-hook`、状态 `toggle-right`、引用 `anchor`、记忆值和记忆函数 `sigma`、上下文值 `share-2`、过渡 `hourglass`、副作用 `zap`、事件处理函数 `mouse-pointer-click`、渲染输出 `layout-template`、serde 可序列化 `braces`、thiserror 错误 `triangle-alert`、axum 接口 `globe`、sqlx 查询 `database`、tauri 桌面命令 `square-function`。数据类写了 `frozen=True` 再加一把锁(`lock`,悬停「不可修改」);没有自己那种卡片的 React 内置钩子(useId、useDeferredValue……)讲成钩子返回值时再加一个作用图标(状态、副作用、引用、性能、上下文、并发,外部数据源 `database`)。规则卡片可以让语言的种类图标照另一种内置种类画(`RuleCard.languageKind`):React 的记忆函数(`const submit = useCallback(…)`,语言报的是变量)第一个图标是函数。种类图标悬停的字、图标颜色可以和筛选栏里的名字、描边色不一样(`KindBadge.tooltip`、`iconColor`):状态悬停「React 状态」,记忆函数描边是函数色、sigma 图标是记忆值的绿。实现块、特质块再由规则 `rust.impl`、`rust.trait` 换成卡片,左边因此有两个「实现」「特质」图标。 - 这组图标由插件自己定义,是一个封闭的集合:契约里的 `KIND_ICON_NAMES`(上表 26 个——命令、管道、执行共用一个,解释器、解析指令共用一个,选项、设置、编译属性共用一个,字段、标签共用一个,类型、接口共用一个——加库规则用的 16 个(React 的组件、钩子、钩子的七种作用、事件处理函数、渲染输出用到其中 11 个),lucide 的 kebab-case 名字),类型 `KindIconName` 是它们的联合,概念的 `icon` 只能写其中一个,写别的是类型错误。内置种类 → 图标名在 `contract.ts` 的 `KIND_ICONS`(宿主写进概念列表)。webview 给每个名字配一个逐个 import 的 lucide 图标组件(`kindIcons.tsx` 的 `KIND_ICON_COMPONENTS`,打包只带这些,预览脚本约 157 kB);webview 的 `KindIconName` 照契约手抄,`kindIconNames.test.ts` 核对两边一样。规则要新图标就把名字加进这组、在 webview 配上图标,没有按任意名字找图标的路。 + 这组图标由插件自己定义,是一个封闭的集合:契约里的 `KIND_ICON_NAMES`(上表 26 个——命令、管道、执行共用一个,解释器、解析指令共用一个,选项、设置、编译属性共用一个,字段、标签共用一个,类型、接口共用一个——加库规则用的 16 个(React 的组件、钩子、状态 / 副作用 / 引用 / 记忆值 / 上下文 / 过渡 / 外部数据源、事件处理函数、渲染输出用到其中 11 个),lucide 的 kebab-case 名字),类型 `KindIconName` 是它们的联合,概念的 `icon` 只能写其中一个,写别的是类型错误。内置种类 → 图标名在 `contract.ts` 的 `KIND_ICONS`(宿主写进概念列表)。webview 给每个名字配一个逐个 import 的 lucide 图标组件(`kindIcons.tsx` 的 `KIND_ICON_COMPONENTS`,打包只带这些,预览脚本约 157 kB);webview 的 `KindIconName` 照契约手抄,`kindIconNames.test.ts` 核对两边一样。规则要新图标就把名字加进这组、在 webview 配上图标,没有按任意名字找图标的路。 - 右上角的图标按钮(原型组件 `Reader / BlockTools`,普通块、属性表块、库规则的卡片共用):只有图标、不带字,名字写在悬停提示和 `aria-label` 里;整排是 `role="group"`(`aria-label="块操作"`)。最前面是「按注释规范重写」(注释图标,块还没有注释时叫「按注释规范写注释」,重写过、记录收着时叫「展开重写记录」;不能写注释的块没有,见「重写注释」),然后是「问 AI」(sparkles 图标,点开 / 收起块下面的问答区,展开时带按下的底色、`aria-expanded`;文件不在工作区文件夹里时没有,见「问 AI」),再是「编辑 / 预览」切换:预览时铅笔「编辑」,编辑时眼睛「预览」、带按下的底色(`--vscode-toolbar-activeBackground`)。按钮宽 24px、高 20px(和种类图标同高),图标 14px、`descriptionForeground` 色;悬停 `--vscode-toolbar-hoverBackground`,键盘聚焦描 1px `--vscode-focusBorder`;Tab 能走到,回车 / 空格切换。 - 悬停提示(整个插件的网页只走这一条路,预览和看板共用同一个组件):带提示的元素只写 `data-tooltip="提示"`(名字照旧写在 `aria-label` 里,只有图标的按钮必须有 `aria-label`),页面根上挂一个 `TooltipHost`(`webview-ui/src/components/ui/tooltip.tsx`)统一弹,不用原生 `title`;提示里的换行照样换行(看板摘修复弹框里「迁移」列出的几个文件一行一个);注释、回答里 Markdown 链接的标题(`[文字](网址 "标题")`)也写成 `data-tooltip`。网页的 TSX 里写原生 `title` 属性是 lint 错误(`vscode/eslint.config.mjs`),只有 `iframe` 这种必须带标题的元素例外,组件自己叫 `title` 的属性不算。原因:macOS 上 VS Code 带的 Electron(1.139 是 Electron 43)只在鼠标压着带 `title` 的元素自身边缘时才弹原生提示,停在它里面的图标、文字上不弹(electron/electron#49843,Electron 38 起),种类图标 20px 的框几乎被 16px 的图形占满,基本弹不出来;样子也是系统的。样子照 VS Code 的悬停框:`--vscode-editorHoverWidget-background` 底、`--vscode-editorHoverWidget-border` 边框、`--vscode-editorHoverWidget-foreground` 字、`0 2px 8px --vscode-widget-shadow` 阴影,11px 字,圆角 4px,最宽 22rem;优先在元素上方,上方放不下翻到下方,水平对着元素中间,贴边留 8px,不接鼠标。鼠标停 500ms 才弹,在同一个元素里移动不重新计时,已经弹着时移到另一个带提示的元素上立刻换;移开、移出页面、按下鼠标、按任意键(含 Esc)、滚动就收,收了之后鼠标不离开这个元素不再弹。键盘把焦点移到带提示的元素上(`:focus-visible`)立刻弹,焦点离开就收;提示不是元素自己的名字(`aria-label` 或它的字)时用 `aria-describedby` 挂到元素上,读屏当描述念。 - 种类图标和底色按种类区分(颜色见「颜色」);文件开头的说明(种类「注释」)虚线框。 @@ -257,6 +257,8 @@ 输入参数的表格(原型 `paramRows`):往右缩进 5px,第一行是表头「名称 | 类型 | 默认值」,下面每个参数一行。列宽按整列的内容定,webview 不认是哪种表格(库规则的字段表同样排,见 `tableTemplate`):整张表格一个网格、各行借用它的列,前几列宽裕时放到整列不换行,最后一列(默认值、说明)分剩下的、至少留 `min(20%, 8em)`;放不下时先让最后一列换行,编辑区再窄前几列平分剩下的宽度、在格子里换行(长名字从中间断开),不撑出卡片、不藏掉哪一列。格子左右留 8px、上下 2px,长类型、长默认值在格子里换行,不挤掉别的列。外框 1px、圆角 4px,格子之间、行之间 1px 分隔线,颜色都是主题的表格分隔色(`--vscode-tree-tableColumnsBorder`,主题没给时退到 `--vscode-editorWidget-border`);表头垫主题的表头底色(`--vscode-keybindingTable-headerBackground`,比编辑区深一档或浅一档),列名界面字体 12px、`descriptionForeground` 色。没有默认值的格子留空。格子可以是 Markdown(参数的「说明」、「异常」表的两列、对不上的参数的说明):按「注释的 Markdown 排版」显示(界面字体、注释色),着色的词照旧排在等宽字体的段落里,差异逐词标。属性行跟着的说明(`PropertyRow.note`,输出参数的 `@return`)接在值后面,同一行放得下就并排,剩下的地方不到 12 个字宽时换到下一行。折叠「输入参数」那一行时整张表收起;子行 id、跳到定义闪「它那个参数」、高亮名字的各处出现都和列表一样,闪的是表格里那一行(行边框和相邻行共用,改在行里面描一圈聚焦色)。哪些子行排成表格由翻译插件定:给了列名(`PropertyRow.columns`)的排成表格,没给的(导入项、字典 / 对象的各项)照旧是列表,webview 只看有没有列名。 +表格的行、属性行可以带操作(`PropertyItem.actions`、`PropertyRow.actions`,现在只有看调用树一种,见「内置:React 组件」的钩子卡片):表里有行带操作时,表最后多一列「操作」(列模板在 `tableTemplate` 后面接 `max-content`,宽度按按钮最多的那一行,表头「操作」),各行的按钮在这一格里从左往右排,没有操作的行空着;属性行带操作时(单个名字的「名称」一行)按钮排在这一行最右边。按钮同块右上角的调用树按钮(`BlockTools.tsx` 的 `CallTreeButton`):`git-branch` 图标,次数大于 0 时带小圆标,0 只有图标;悬停、读屏写操作自己的说法(「谁用了这个状态」),弹框开着时带按下的底色。宿主排视图数据时给卡片上的操作挨个起键(`actionKey`:块的记号加序号,顺序是属性表从上往下、一行里先行自己再子行,`blockView.ts` 的 `mapActions`),页面按键对次数、点开调用树(`webview-ui/src/codeReader/rowActions.ts` 的 `RowActionsContext`,每张卡片自己给,子卡片不沿用);定义卡片浮窗、删掉的块的旧内容不给,不出「操作」一列。 + | 种类 | 行 | | --- | --- | | 函数 | 名称(函数色;匿名函数写「匿名」)/ 说明(有正文才显示:JSDoc 去掉 `/**`、`*/` 和每行开头的 `*`,docstring 去掉引号;再去掉共同缩进和首尾空行,拆掉块标签(见「注释的 Markdown 排版」),剩下的正文按 Markdown 渲染)/ 对不上的参数(说明里有 `@param` 的名字在输入参数里没有时才显示:`N 个`,展开成表格「名称 \| 说明」,名称是 hint 色、悬停「没有这个参数」)/ 访问级别 / 异步(是 / 否)/ 装饰器(有才显示,源码原样照抄、按源码着色,多个换行)/ 输入参数(`N 个` 或「无」,展开成表格,列名 名称 \| 类型 \| 默认值,每个参数一行:名称 \| 类型(没标注写「未标注」)\| 默认值(译文,没有留空);任何一个参数对上了 `@param` 时多一列「说明」(Markdown,没对上的格子留空),按名字对,`*args` / `**kwargs` / `...rest` 去掉前缀对)/ 输出参数(返回类型的译文,没标注写「未标注」;写了 `@return` 时类型后面跟着这段说明,Markdown、注释色)/ 异常(写了 `@throws` 才显示:`N 个`,展开成表格「异常 \| 触发条件」,一条一行,都是 Markdown,异常名能点,见「注释的 Markdown 排版」的引用) | @@ -1126,6 +1128,24 @@ export interface PropertyItem extends Defines { cells: PreviewText[] items?: PropertyItem[] table?: PreviewTable // 最后一格的值里那次调用的实参表:表格的行排在最后一格里、文字下面,排成列表的子行排在它下面;总是展开,表里的行又能带 items、table + actions?: RowAction[] // 这一行能做的操作:表格的行排在最后多出来的「操作」一列,从左往右;列表的子行没有这一列 +} + +/** 表格一行、属性一行上能做的一个操作,页面画成一个按钮。现在只有看调用树一种。 */ +export type RowAction = CallTreeAction + +/** + * 看调用树:查源码里一个名字被谁用、被谁调用,按钮上带次数(0 次只画图标),点开是调用树弹框。 + * calls 查谁调用了它(编辑器的调用关系,认不出这个名字时改查引用、只留调用处),次数是落在几棵调用树里; + * references 查所有用到它的地方,按所在的函数、组件分组,次数是用到几处(名字自己的定义处、落在 except 里的不算)。 + */ +export interface CallTreeAction { + kind: 'callTree' + name: SourceRange // 查的那个名字 + mode: 'calls' | 'references' + label: string // 按钮的悬停文字:「谁用了这个状态」「谁改了这个状态」 + except?: SourceRange[] // 不算的地方(React 钩子的依赖数组里写的那一次) + key?: string // 宿主排视图数据时填的键(actionKey(块的记号, 序号)),页面按它对次数、点开调用树;规则不填 } /** @@ -1134,7 +1154,7 @@ export interface PropertyItem extends Defines { * note 是跟在值后面的一段说明(Markdown,注释色):输出参数那一行,返回类型后面是说明里的 `@return`。 * chain 是值(链的起点)后面接着的链式调用各步,排成竖轨道(见「链式调用卡片」)。 */ -export interface PropertyRow extends Defines { label: string, value: PreviewText, note?: Markdown, items?: PropertyItem[], columns?: string[], chain?: ChainStep[] } +export interface PropertyRow extends Defines { label: string, value: PreviewText, note?: Markdown, items?: PropertyItem[], columns?: string[], chain?: ChainStep[], actions?: RowAction[] /* 按钮排在这一行最右边 */ } /** 一张带表头和边框的表:列名,每行几列对齐的格子,同 PropertyRow 给了 columns 的子行。 */ export interface PreviewTable { columns: string[], items: PropertyItem[] } @@ -1192,6 +1212,11 @@ export interface LanguageAdapter { displayNames?: DisplayNameReader /** 这块除了自己的种类,还认得出的概念(异步、抽象)。认到才返回;不填就只有种类那一个。种类由宿主补在最前面,这里不要再报。 */ concepts?: (block: CodeBlock) => BlockConcept[] + /** + * 一个函数值(箭头函数、函数表达式)的主体分成的块:语句块是各句,直接返回表达式的是一个返回块(节点是那个表达式,翻译插件在译文前补「返回」,见 ZhTable.returnWritten)。 + * 库规则要把实参里函数的主体排成卡片的子块时用(RuleCard.expands);不填就排不出来。 + */ + functionBody?: (fn: Node, languageId: string) => CodeBlock[] } /** 代码里给一个定义起的中文名:name 是定义处那个名字,text 是中文名。 */ @@ -1265,8 +1290,8 @@ export const KIND_ICONS: Record /** 一块上认出的一个概念。颜色不填的是语言的种类(按 id 用 CSS 的种类色);规则的概念填颜色,只给这个图标上色。 */ export interface BlockConcept { id: string, label: string, icon: KindIconName, color?: ThemeColor } -/** 库规则的种类:筛选栏里叫 label,卡片边框用 color,icon 进概念列表;icon 只能从 KindIconName 里挑。 */ -export interface KindBadge { label: string, color: ThemeColor, icon: KindIconName } +/** 库规则的种类:筛选栏里叫 label,卡片边框用 color,icon 进概念列表;icon 只能从 KindIconName 里挑。tooltip、iconColor 是种类图标悬停的字、图标的颜色,不填同 label、color。 */ +export interface KindBadge { label: string, color: ThemeColor, icon: KindIconName, tooltip?: string, iconColor?: ThemeColor } /** 库规则认领一块后给出的替身,下面挂着原块留下的子块:规则自己的卡片,或认成的现成属性表块;这块讲在了别的卡片里时是略去它。 */ export type RuleBlock = RuleCard | RuleFacts | RuleOmit @@ -1279,9 +1304,10 @@ export interface RuleCard { kind: string // 种类 id,「规则 id.名字」(sqlalchemy.table):筛选的 kind 值,要稳定 badge: KindBadge // 种类的名字、颜色、图标;筛选栏里这个种类也叫这个名字,卡片边框用这个颜色 concepts?: BlockConcept[] // 额外认出的概念,排在种类后面;语言的概念仍在更前面,同一个 id 只留第一个 - languageConcepts?: false // 填 false 时左边不带语言的概念,从种类画起(React 钩子卡片左边第一个是钩子图标) - tint?: ThemeColor // 卡片淡底的颜色,不填用种类色;边框仍是种类色(React 钩子卡片描边都是钩子紫,淡底按来源分) - calls?: SourceRange // 能看调用树,查这个名字被谁调用(钩子卡片查返回的 setOpen,自定义钩子卡片查钩子自己);BlockView.callTree.name 就是它 + languageKind?: BlockKind // 左边第一个图标(语言的种类)照这种内置种类画,不填是原块自己的种类(React 记忆函数的变量块画成函数) + tint?: ThemeColor // 卡片淡底的颜色,不填用种类色;边框仍是种类色(React 钩子返回值描边是钩子紫,淡底按来源分) + calls?: true // 能看调用树,查卡片自己的名字(defines)被谁调用,按钮在卡片右上角(React 自定义钩子);属性表里各行自己查的名字见 RowAction + expands?: Node[] // 原块里这几个函数值(实参里的箭头函数)的主体也排成卡片的子块(LanguageAdapter.functionBody),语言插件已经排成子块的不重复排 rows: PropertyRow[] defines?: SourceRange // 块自己的名字(类名):跳到的定义是它时闪整块 attributes?: BlockAttributes // 规则自己的筛选属性,叠在宿主从原块推出的上面;kind 填了不算;名字由 LibraryRule.attributeNames 给 @@ -1842,7 +1868,7 @@ export interface CommandRule { ### 内置:React 组件(TypeScript / JavaScript) -`vscode/src/codeReader/rules/react.ts`(读语法树的办法在 `rules/reactTree.ts`,都是纯函数),`languageIds: ['typescriptreact', 'javascriptreact', 'typescript', 'javascript']`,`libraries: ['react']`,`alwaysIn: ['typescriptreact', 'javascriptreact']`:新的 JSX 写法不用导入 react,TSX / JSX 文件都启用;自定义钩子常写在 .ts / .js 文件里,这两种导入了 react(或它的子模块)才启用,免得把 zustand 的 `useXxx` store 这类当成钩子。.ts / .js 里没有 JSX,认不出组件、渲染输出,只出自定义钩子卡片、钩子卡片(样例 `fixtures/useShellEvents.ts.txt`,luffy 的 `lib/desktop/use-shell-events.ts` 精简版)。原型:`docs/prototype/code-reader/openpencil/react.js` 的三张画板「编辑器全貌」「卡片种类」「对照」(导出图 `exports/react-main.png`、`react-kinds.png`、`react-compare.png`),钩子卡片照 `react-hooks.js` 的两张画板(导出图 `exports/react-hooks-panel.png`、`react-hooks-custom.png`,样例源码同 `fixtures/hooksPanel.tsx.txt`);样例是 luffy 的 `chat/code/bubbles/QueuedBubble.tsx`(`fixtures/queuedBubble.tsx.txt`)和 `chat/code/PlanChecklist.tsx` 第 91–226 行(`fixtures/planChecklist.tsx.txt`,前面带上文件开头的导入),以前的 `DesktopTitlebar`、`LegalDocPage`、`DeleteAppDialog`、`DesktopSettingsDialog`、`AppVaultSummary`、`ShareButton`、`PosterDialog`、`OverviewSection` 也在 `fixtures/`。 +`vscode/src/codeReader/rules/react.ts`(读语法树的办法在 `rules/reactTree.ts`,都是纯函数),`languageIds: ['typescriptreact', 'javascriptreact', 'typescript', 'javascript']`,`libraries: ['react']`,`alwaysIn: ['typescriptreact', 'javascriptreact']`:新的 JSX 写法不用导入 react,TSX / JSX 文件都启用;自定义钩子常写在 .ts / .js 文件里,这两种导入了 react(或它的子模块)才启用,免得把 zustand 的 `useXxx` store 这类当成钩子。.ts / .js 里没有 JSX,认不出组件、渲染输出,只出自定义钩子卡片和钩子体里的钩子卡片(样例 `fixtures/useShellEvents.ts.txt`,luffy 的 `lib/desktop/use-shell-events.ts` 精简版)。原型:`docs/prototype/code-reader/openpencil/react.js` 的三张画板「编辑器全貌」「卡片种类」「对照」(导出图 `exports/react-main.png`、`react-kinds.png`、`react-compare.png`),钩子卡片按变量讲,照 `react-state.js` 的三张画板「登录页」「其他写法」「搜索面板」(导出图 `exports/react-state-login.png`、`react-state-variants.png`、`react-state-hooks.png`,样例源码同 `fixtures/loginPage.tsx.txt`(luffy 的 `app/desktop/login/page.tsx`)、`fixtures/stateVariants.tsx.txt`(三行 useState 包进一个组件)、`fixtures/searchPanel.tsx.txt`),自定义钩子卡片照 `react-hooks.js`(导出图 `exports/react-hooks-custom.png`,样例源码同 `fixtures/hooksPanel.tsx.txt`);样例是 luffy 的 `chat/code/bubbles/QueuedBubble.tsx`(`fixtures/queuedBubble.tsx.txt`)和 `chat/code/PlanChecklist.tsx` 第 91–226 行(`fixtures/planChecklist.tsx.txt`,前面带上文件开头的导入),以前的 `DesktopTitlebar`、`LegalDocPage`、`DeleteAppDialog`、`DesktopSettingsDialog`、`AppVaultSummary`、`ShareButton`、`PosterDialog`、`OverviewSection` 也在 `fixtures/`。 TSX 和 Python 一样,从上往下一块语法一张卡片,嵌套的块排在父卡片下面,缩进、竖线、折叠同函数体。规则只换掉 React 的几种写法,别的块(导入、接口、类型、常量、普通变量、if、尝试……)照语言默认的卡片,注释照常挂在它讲的卡片上。组件卡片、自定义钩子卡片不把函数体并进来:语句照源码顺序是它的子块,照常交给各规则看。表格的格子里只写名字和位置,函数体只出现在子卡片里。 @@ -1851,12 +1877,20 @@ TSX 和 Python 一样,从上往下一块语法一张卡片,嵌套的块排 | 种类 id | 名字 | 图标 | 颜色 | 认哪一块 | 行 | | --- | --- | --- | --- | --- | --- | | `react.component` | React 组件 | `atom` | #61dafb / #0a7ea4 | 组件的声明 | 名称 / 说明 / 构造参数 | -| `react.hook` | 钩子 | `fishing-hook` | #b180d7 / #7f3fa6 | 直接写在组件体、自定义钩子体里的钩子调用:`const x = useX(…)`、`const [a, b] = useX(…)`、整句的 `useEffect(…)` | 钩子 / 类型参数 / 参数 / 返回 | +| `react.state` | 状态(图标悬停「React 状态」) | `toggle-right` | #9cdcfe / #001080 | `useState`、`useReducer` | 名称 / 来自 / 状态类型 / 默认值;useReducer 是 名称 / 来自 / 处理函数 / 状态类型 / 初始值 / 初始化函数 | +| `react.ref` | 引用 | `anchor` | #4fc1ff / #0070c1 | `useRef` | 名称 / 来自 / 指向类型 / 初始值 | +| `react.memo` | 记忆值 | `sigma` | #b5cea8 / #098658 | `useMemo` | 名称 / 来自 / 计算 / 重算时机 | +| `react.memoFn` | 记忆函数 | `sigma`(图标 #b5cea8 / #098658) | #dcdcaa / #795e26 | `useCallback` | 名称 / 来自 / 参数 / 函数体 / 重建时机 | +| `react.context` | 上下文值 | `share-2` | #4ec9b0 / #267f99 | `useContext` | 名称 / 来自 / 上下文 | +| `react.transition` | 过渡 | `hourglass` | #ce9178 / #a31515 | `useTransition` | 名称 / 来自 | +| `react.effect` | 副作用 | `zap` | #e5c07b / #9a6a00 | `useEffect`、`useLayoutEffect`、`useInsertionEffect` | 触发时机 / 来自 / 执行 | +| `react.hookValue` | 钩子返回值 | `fishing-hook` | #b180d7 / #7f3fa6 | 别的钩子(第三方、自己写的、没有自己那种卡片的内置钩子)接住了返回值 | 名称 / 来自 / 说明 / 参数 | +| `react.hookCall` | 钩子调用 | `fishing-hook` | #b180d7 / #7f3fa6 | 别的钩子整句只是调用、没接返回值 | 来自 / 参数 | | `react.customHook` | 自定义钩子 | `fishing-hook` | #b180d7 / #7f3fa6 | 自定义钩子的声明(`function useXxx`、`const useXxx = () => …`) | 名称 / 说明 / 参数 / 返回 | | `react.handler` | 事件处理函数 | `mouse-pointer-click` | #dcdcaa / #795e26 | 组件体里定义的函数(函数声明、值是函数的常量) | 名称 / 说明 / 参数 / 绑定事件(说明里的块标签另有几行,见下) | | `react.render` | 渲染输出 | `layout-template` | #89d185 / #388a34 | 组件函数自己返回 JSX 的 return | JSX 结构大纲 | -组件色同时用在渲染大纲里的组件、「客户端组件」标签、React 自带钩子的淡底上;钩子卡片、自定义钩子卡片描边都是钩子紫,淡底按来源分(见下);事件处理函数同「函数」块,渲染输出同「返回」块的绿。筛选栏的「种类」按这几个 id 筛,叫上表的名字。 +组件色同时用在渲染大纲里的组件、「客户端组件」标签、React 内置钩子讲成钩子返回值时的淡底上;React 的几种概念借语法色(状态同变量、引用同常量、记忆值同数字、上下文同类型、过渡同字符串、副作用同「选项」块的黄),记忆函数描边同「函数」块;钩子返回值、钩子调用、自定义钩子卡片描边都是钩子紫,淡底按来源分(见下);事件处理函数同「函数」块,渲染输出同「返回」块的绿。筛选栏的「种类」按这几个 id 筛,叫上表的名字。 认哪些是组件:名字大写开头;是函数声明、值是函数的变量(箭头函数、函数表达式,直接返回 JSX 的也算),或被 `memo(…)` / `forwardRef(…)`(`React.memo` 也算,可以套几层)包着的函数;函数自己的 return(嵌套函数里的不算)里有一处返回 JSX(元素、片段,三元、`&&` 的某一支是 JSX 也算;和 `null` 混着返回也算)。小写开头的工具函数、不返回 JSX 的大写函数照常是函数块。组件里又定义的组件自己也是一张组件卡片,不算事件处理函数。 @@ -1864,10 +1898,10 @@ TSX 和 Python 一样,从上往下一块语法一张卡片,嵌套的块排 - 组件块(函数块、只声明一个变量的常量 / 变量块)是组件时换成组件卡片。文件开头的 `"use client"`(文件里有组件时)略去(`RuleOmit`),讲成卡片上的「客户端组件」标签;它挂着注释时不略去(注释没地方放),照常是一张语句卡片。组件上面的 JSDoc 是组件块自己的说明(TypeScript 的 JSDoc 能当常量、变量块的说明,`memo(…)`、直接返回 JSX 的常量块也是),讲成卡片的「说明」。 - 自定义钩子的声明(函数块、只声明一个变量的常量 / 变量块;名字是 `use` 后面接大写字母或数字,只叫 `use` 的不算,`customHookAt`)换成自定义钩子卡片。 -- 组件体、钩子体里的块:语法树往上找,块的语句直接是某个组件函数或自定义钩子主体(语句块)的子语句才认(`enclosingComponent` / `enclosingCustomHook`:所在的函数找回声明它的语句,再用 `componentAt` / `customHookAt` 核对)。只声明一个变量、值是钩子调用(`React.useX` 也算),或整句就是一次钩子调用的(`hookCallAt`),认成钩子卡片;组件体里定义的函数认成事件处理函数(`bodyOf`)。值是钩子调用再取属性的(`useX()?.a ?? b`)照常是变量卡片。 +- 组件体、钩子体里的块:语法树往上找,块的语句直接是某个组件函数或自定义钩子主体(语句块)的子语句才认(`enclosingComponent` / `enclosingCustomHook`:所在的函数找回声明它的语句,再用 `componentAt` / `customHookAt` 核对)。只声明一个变量、值是钩子调用(`React.useX` 也算),或整句就是一次钩子调用的(`hookCallAt`),按变量讲成钩子卡片(见下);组件体里定义的函数认成事件处理函数(`bodyOf`)。值是钩子调用再取属性、再调用的(`useX()?.a ?? b`、`useSearchParams().get("from")`)接住的不是钩子的返回值,照常是变量卡片。 - `return` 块:所在的最内层函数(`enclosingFunction`)是组件函数、返回的是 JSX 时认成渲染输出;写在 `if` 里的提前返回 JSX 也算,它是如果卡片下面的子块。返回 `null` 这类的照常是返回块。 - 别的照语言默认:组件体里普通的 `const x = 表达式` 是变量卡片,`if (…) return null` 是如果卡片、下面是返回卡片,注释是它讲的那张卡片的「注释」一行。 -- 回调、函数里的语句来自 TypeScript 语言插件本来给的子块:调用的实参是带语句块的函数时(任何调用都一样),那句语句、那个变量的子块就是函数里的语句,所以 `useEffect(() => {…})`、`useCallback(() => {…})`、`useMemo(() => {…})` 的语句(连返回清理函数的那句 return)排在钩子卡片下面;事件处理函数、自定义钩子是函数块,函数体照常是子块。 +- 回调、函数里的语句来自 TypeScript 语言插件本来给的子块:调用的实参是带语句块的函数时(任何调用都一样),那句语句、那个变量的子块就是函数里的语句,所以 `useEffect(() => {…})`、`useCallback(() => {…})`、`useMemo(() => {…})` 的语句(连返回清理函数的那句 return)排在钩子卡片下面。钩子卡片把实参里写的每个函数交给宿主展开(`RuleCard.expands`):语言插件没排成子块的(直接返回表达式的 `() => results.filter(…)`、`() => loadItems()`,第二个起带语句块的函数)由 TypeScript 语言插件的 `functionBody` 排成子块,直接返回的表达式是一张「返回 …」卡片(源码里没写 return,翻译插件照写了的那样补「返回」,`ZhTable.returnWritten`),并进来的照源码先后排。事件处理函数、自定义钩子是函数块,函数体照常是子块。 组件卡片: @@ -1887,24 +1921,65 @@ TSX 和 Python 一样,从上往下一块语法一张卡片,嵌套的块排 构造参数:属性类型的字段照类型里的顺序一行一个(类型字面量、同文件的接口 / 类型别名,交叉类型各部分接起来,`Readonly<…>`、`PropsWithChildren<…>` 看里面;没标注参数类型时 `const X: FC` 的泛型实参、`forwardRef` 的第二个泛型实参),解构里有、类型里没有的接在后面,`...rest` 最后(类型写「其余的属性」)。名称是属性名(定义处带下标:解构出来的是解构那处,没解构的是字段;跳到定义只闪这一行),`children` 后面标「子元素」、函数类型的属性(`(x) => R`、方法签名)标「回调」(组件色的小标签),解构时改了名写「(组件内名为 x)」;类型照翻译插件翻,方法签名写成函数签名;默认值取解构的默认值,没有写「—」;必填看类型的 `?`(是 / 否,storage 色),没类型可看时写了默认值的「否」、别的「—」;说明是字段上面的 JSDoc / 注释、这一行行尾的注释(comment 色,几行接成一行)。类型是导入的名字时经工作区索引查它的字段(索引 `react.propTypes`:看工作区里所有 `**/*.{ts,tsx}`,预筛有 `interface X` / `type X` 才解析,按 typescriptreact 解析;从文件顶层认出接口、类型别名,键是名字、值是各字段的名字、类型写法、可省略、回调、说明的 JSON),查法同「规则认领时查别的文件里的定义」:先照解构的出行、类型「未标注」,查到了按字段重排、重发;别的文件里的类型照写文字(type 色)。 -钩子卡片(所有钩子共用一种,不分析钩子里写了什么;行照钩子签名排,没有的行不显示): +钩子卡片按变量讲:卡片讲接住返回值的那个变量是什么(状态、引用、记忆值、记忆函数、上下文值、过渡,别的钩子是钩子返回值),副作用讲那一句;钩子退到「来自」一行。不分析钩子里写了什么,行照签名表排,没有的行不显示。原型 `react-state.js` 的搜索面板(`fixtures/searchPanel.tsx.txt`)逐张对得上: + +``` +react.hookValue 11 + 名称: router + 来自: useRouter + 说明: 路由器,用于页面跳转 +react.context 12 + 名称: { user, logout } 对象解构 + user + logout + 来自: useContext + 上下文: AuthContext +react.state 13 + 名称: [query, setQuery] 数组解构 + 1 | query | 当前值 + 2 | setQuery | 修改函数 + 来自: useState + 状态类型: 未标注 + 默认值: initialQuery +react.memo 18 + 名称: visible + 来自: useMemo + 计算: ⟦函数 · 1 句⟧ + 重算时机: results 变化时 + return 18: 返回 results.filter((r) => r.hidden 不成立) +react.memoFn 20 + 名称: submit + 来自: useCallback + 参数: 1 个 + e | FormEvent + 函数体: ⟦函数 · 2 句⟧ + 重建时机: router、query 变化时 +react.effect 25 + 触发时机: 仅挂载时 + 来自: useEffect + 执行: ⟦函数 · 1 句⟧ +``` | 行 | 内容 | | --- | --- | -| 钩子 | 被调的钩子名(function 色,带下标:自己写的能跳到定义);第三方钩子悬停「来自 next/navigation」(`Segment.tooltip`) | -| 类型参数 | 源码写了 `useRef` 才有,照常翻(`number` 是「数值」),几个「, 」隔开 | -| 参数 | `N 个`(hint),下面「参数 \| 值」表,一个实参一行;一行都没有时不出这一行 | -| 返回 | `N 个`(hint),下面接住返回值的各项一行:React 自带、第三方的钩子是「名称 \| 是什么」表,自己写的只有「名称」一列;没接返回值时不出这一行 | +| 名称 | 只用一个名字接住返回值时是那个名字(带下标,能调用的用 function 色),它也是卡片自己的名字(`defines`);解构时照源码写出解构(各项的名字着色,对象解构改了名的写 `键: 名字`),后面灰字「数组解构」「对象解构」,展开是一张表:数组「第几项 \| 名称 \| 说明」,对象「名称 \| 说明」(改了名时前面多一列「键」),签名表没说是什么的项时不出「说明」一列(对象解构都没有)。没接返回值时(副作用、钩子调用)不出这一行 | +| 来自 | 被调的钩子名(function 色,带下标:自己写的能跳到定义);悬停「React 内置钩子」「next/navigation 提供的钩子」「自定义钩子」(`Segment.tooltip`) | +| 状态类型、指向类型 | 第一个类型实参(`useState` 的 LoginTab,`useRef`),照常翻;没写时「未标注」 | +| 默认值、初始值、处理函数、初始化函数、计算、函数体、执行、上下文 | 签名表登记的那个实参,按形参的种类写(见下);没传时照签名表写「没写,未定义」,签名表没给说法的不出这一行(useReducer 只传两个实参时没有「初始化函数」)。上下文的名字用上下文色 | +| 重算时机、重建时机、触发时机 | 依赖项:`[a, b]` 是「a、b 变化时」,`[]` 是「仅挂载时」,写成别的表达式时「deps 变化时」(「变化时」「仅挂载时」keyword 色);没写时记忆值、记忆函数「没写,每次渲染时」,副作用「没写,每次渲染后」 | +| 参数(记忆函数) | `useCallback` 收的函数的参数「名称 \| 类型」表(没标注写「未标注」),这时「函数体」的小框里不再写参数;没有参数不出这一行 | +| 说明(钩子返回值) | 只用一个名字接住时讲它是什么:第三方钩子照词表(next/navigation 的 `usePathname` 当前路径、`useRouter` 路由器,用于页面跳转、`useSearchParams` URL 查询参数、`useParams` 路由动态参数、`useSelectedLayoutSegment(s)` 当前激活的下一级 / 各级布局段,next/router 的 `useRouter`,react-dom 的 `useFormStatus`),没有自己那种卡片的内置钩子照签名表(useId「稳定的唯一标识」、useDeferredValue「延迟更新的值」);自己写的钩子、解构接住的没有 | +| 参数(钩子返回值、钩子调用) | `N 个`(hint),下面「参数 \| 值」表,一个实参一行:内置钩子照签名表的形参名,自己写的照定义处的形参(同文件的从语法树读,别的文件的经工作区索引 `react.customHooks` 查:看 `**/*.{ts,tsx,js,jsx}`,预筛有 `useX` 字样才解析,从文件顶层认出自定义钩子,键是名字、值是各形参写法的 JSON;查法同构造参数的类型,先照位置写、查到了重排),都不知道时照位置写「第 1 个」;一行都没有时不出这一行 | - 钩子从哪来:写成 `React.useX`、从 `'react'` 导入的是 React 自带;从别的包导入的是第三方库;从相对路径、`@/`、`~/`、`#` 开头的别名导入的是自己写的。没导入的:这个文件里定义了这个钩子的是自己写的,签名表里有的是 React 自带(自动导入 React 钩子的项目),别的也算自己写的。 -- 签名表(`rules/reactHooks.ts` 的 `REACT_HOOKS`,每个钩子登记一次):作用分类(状态 / 副作用 / 引用 / 性能 / 上下文 / 并发 / 外部数据源)、形参名照 `@types/react`(useEffect 的 `effect, deps`,useReducer 的 `reducer, initialState`,传三个实参时换成重载的 `reducer, initialArg, init`)、每个形参的种类(普通值 / 可以是函数的初始值 / 函数 / 依赖项 / 引用)、没传时怎么写(依赖项「没写,每次渲染后」,useRef 的 initialValue「没写,未定义」;没给说法的参数没传就不出那一行)、返回各项的说法(useState「当前值」「修改函数」,useReducer「当前值」「派发函数」,useRef「引用对象」,useMemo「算出的值」,useCallback「记住的函数」,useContext「上下文的值」,useTransition「是否正在过渡」「启动过渡的函数」……)和哪几项是函数。登记了 react 包的全部钩子:useState、useReducer、useActionState、useOptimistic、useId、useContext、use、useRef、useImperativeHandle、useEffect、useLayoutEffect、useInsertionEffect、useEffectEvent、useDebugValue、useMemo、useCallback、useTransition、useDeferredValue、useSyncExternalStore。 -- 参数表的「参数」一格:React 自带的照签名表的形参名,自己写的照定义处的形参(同文件的从语法树读,别的文件的经工作区索引 `react.customHooks` 查:看 `**/*.{ts,tsx,js,jsx}`,预筛有 `useX` 字样才解析,从文件顶层认出自定义钩子,键是名字、值是各形参写法的 JSON;查法同构造参数的类型,先照位置写、查到了重排),都不知道时照位置写「第 1 个」。 -- 「值」一格按形参的种类:依赖项 `[a, b]` 是「a、b 变化时」、`[]` 是「仅挂载时」、写成别的表达式时「deps 变化时」(「变化时」「仅挂载时」keyword 色);可以是函数的初始值传的函数直接返回一次调用时写「首次渲染时调用 readOpen(id)」;写在这里的函数主体是语句块时收成 fold 小框「函数 (next: 布尔) · 2 句」(没参数不写括号),函数体照常是卡片的子块,展开收起交给卡片自己的折叠箭头(小框不在链式调用的某一步里,只当摘要);直接返回表达式的函数没有子块可放,照常翻整个函数;函数、引用种类传的是名字时(reducer、ThemeContext)照抄成带源码下标的名字(函数的名字 function 色);别的照常翻(`null` 是「空」,`[]` 是「空数组」)。 -- 返回表:变量名接住的是整个返回值(返回元组的钩子「是什么」写全部各项「当前值、修改函数」),数组解构照位置(空着的位置跳过,`...rest` 前面带 `...`),对象解构一个键一项(「是什么」写「—」)。名称带下标(跳到定义只闪这一行),返回里是函数的那项用 function 色。第三方钩子的「是什么」照词表(next/navigation 的 `usePathname` 当前路径、`useRouter` 路由器,用于页面跳转、`useSearchParams` URL 查询参数、`useParams` 路由动态参数、`useSelectedLayoutSegment(s)` 当前激活的下一级 / 各级布局段,next/router 的 `useRouter`,react-dom 的 `useFormStatus`),变量名整个接住时才写,别的「—」。 -- 样子:左边第一个是钩子图标 `fishing-hook`(钩子紫,不带它所在那句常量、语句的图标),React 自带的再加一个作用图标(`RuleCard.concepts`,悬停分类名;useLayoutEffect 悬停「副作用 · 浏览器绘制前执行」,useInsertionEffect「副作用 · 布局副作用之前执行」):状态 `toggle-right` #9cdcfe / #001080、副作用 `zap` #e5c07b / #9a6a00、引用 `anchor` #4fc1ff / #0070c1、性能 `sigma` #b5cea8 / #098658、上下文 `share-2` #4ec9b0 / #267f99、并发 `hourglass` #ce9178 / #a31515、外部数据源 `database` #dcdcaa / #795e26。描边是钩子紫,淡底按来源(`RuleCard.tint`,webview 的 `.cr-block[data-tint]`):React 自带 #61dafb / #0a7ea4、第三方 #e5c07b / #9a6a00、自己写的 #89d185 / #388a34。只用一个变量名接住返回值时那个名字是卡片自己的名字(`defines`)。 -- 调用树:返回里有函数的钩子卡片带调用树按钮(`RuleCard.calls` → `BlockView.callTree.name`),查接住那个函数的名字:useState 查 setOpen,useReducer 查 dispatch,useTransition 查 startTransition,useCallback 查 toggle。TypeScript 的调用层级认不出这种名字(数组解构出来的、`const x = useCallback(…)` 的,`vscode.prepareCallHierarchy` 给空的),调用树服务这时改查引用(`callTree/referenceCalls.ts`):`vscode.executeReferenceProvider` 查名字的各处引用,只留调用处(名字后面紧跟实参的括号,中间可以隔着 `?.`、泛型实参),每处在文件大纲(`vscode.executeDocumentSymbolProvider`)里从里往外找第一个调用层级认得的符号当调用者(`setOpen(next)` 写在 `useCallback` 的回调里,调用者是组件 Panel;`startTransition(…)` 在 handleClick 里,调用者是 handleClick),都不认得时按文件算,再从调用者往上照常问编辑器。 +- 签名表(`rules/reactHooks.ts` 的 `REACT_HOOKS`,每个钩子登记一次,同一语义只这一份):作用分类(状态 / 副作用 / 引用 / 性能 / 上下文 / 并发 / 外部数据源)、讲成哪种卡片和卡片从上往下的各行(`CardSpec`:名称 / 来自 / 第一个类型实参 / 第几个实参 / 第几个实参的参数表)、形参名照 `@types/react`(传三个实参的 useReducer 换成重载的 `reducer, initialArg, init`)和每个形参的种类(普通值 / 可以是函数的初始值 / 函数 / 依赖项 / 引用)、没传时怎么写、返回各项是什么(useState「当前值」「修改函数」,useReducer「当前值」「派发函数」,useTransition「是否正在过渡」「启动过渡的函数」……)和接住它的名字能做什么(值 / 状态 / 修改函数 / 派发函数 / 函数,决定那一项的调用树悬停字)。登记了 react 包的全部钩子:useState、useReducer、useActionState、useOptimistic、useId、useContext、use、useRef、useImperativeHandle、useEffect、useLayoutEffect、useInsertionEffect、useEffectEvent、useDebugValue、useMemo、useCallback、useTransition、useDeferredValue、useSyncExternalStore;有自己那种卡片的是 useState、useReducer、useRef、useMemo、useCallback、useContext、useTransition 和三个副作用钩子,别的讲成钩子返回值(没接返回值的 useImperativeHandle、useDebugValue 是钩子调用)。 +- 实参那一格按形参的种类:写在这里的函数都收成 fold 小框「函数 (next: 布尔) · 2 句」(没参数不写括号,直接返回表达式的算 1 句),函数体是卡片的子块(直接返回的表达式是一张「返回 …」卡片),小框能点,和卡片的折叠箭头是同一个开关(webview 的 `ChainFoldContext`,卡片有排在下面的子块时由卡片给);可以是函数的初始值传的函数写「首次渲染时调用」加小框;函数、引用种类传的是名字时(filterReducer、AuthContext)照抄成带源码下标的名字(函数的名字 function 色);别的照常翻(`null` 是「空」,`[]` 是「空数组」)。 +- 样子:左边两个图标,先是语言的种类(变量;记忆函数是函数,`RuleCard.languageKind`;副作用、钩子调用是语句),再是 React 的概念(上表的图标,悬停卡片种类的名字;状态悬停「React 状态」,useLayoutEffect 的副作用悬停「副作用 · 浏览器绘制前执行」,useInsertionEffect「副作用 · 布局副作用之前执行」,`KindBadge.tooltip`)。描边、淡底是 React 概念的颜色;记忆函数描边、淡底是函数色,sigma 图标是记忆值的绿(`KindBadge.iconColor`)。钩子返回值、钩子调用描边是钩子紫,淡底按来源(`RuleCard.tint`,webview 的 `.cr-block[data-tint]`):React 内置 #61dafb / #0a7ea4、第三方 #e5c07b / #9a6a00、自己写的 #89d185 / #388a34;内置钩子再加一个作用图标(`RuleCard.concepts`):状态 `toggle-right`、副作用 `zap`、引用 `anchor`、性能 `sigma`、上下文 `share-2`、并发 `hourglass`、外部数据源 `database` #dcdcaa / #795e26。 +- 调用树:卡片右上角没有调用树按钮,接住返回值的每一项各一个调用树操作(`CallTreeAction`,见「属性表」的「操作」一列):解构的每一项在表的「操作」一列,只接一个名字时在「名称」一行最右边。悬停按接住它的名字能做什么写:值「谁用了」、状态的当前值「谁用了这个状态」(useState、useReducer 的第一项)、修改函数「谁改了这个状态」、派发函数「谁派发了动作」、别的函数「谁调用了」;签名表说不清的项(第三方、自己写的钩子、对象解构)在组件体、钩子体里被调用过的算函数,否则算值。都查所有引用(`mode: 'references'`,只查调用的话 `onTabChange={setActiveTab}`、`onSubmit={submit}` 这种当值传下去的都漏了),组件体、钩子体里 React 内置钩子依赖数组的那几段不算(`except`:依赖项只告诉 React 什么时候重跑,不是在用它)。按钮上的数是用到几处:搜索面板里 query 3、inputRef 2、别的各 1,同原型。 +- 查所有引用(调用树服务的 references 查法,`callTree/query.ts` 的 `loadTargetCalls` / `loadCallEdges`):起点按名字起点自己写一个(变量);`vscode.executeReferenceProvider` 查名字的各处引用,去掉名字自己的定义处和起点落在 `except` 里的(`callTree/referenceCalls.ts` 的 `countedSites`),每处在文件大纲(`vscode.executeDocumentSymbolProvider`)里从里往外找第一个调用层级认得的符号当调用者(写在 `useCallback` 回调里的,调用者是组件 SearchPanel),都不认得时按文件算,同一个调用者的几处并成一项,再从调用者往上照常问编辑器。次数是直接连着起点的调用边条数(一处一条,`session.ts` 的 `countOf`)。查调用(calls,函数、类、自定义钩子卡片右上角的按钮)照旧:编辑器的调用层级认不出名字时(数组解构出来的、`const x = useCallback(…)` 的,`vscode.prepareCallHierarchy` 给空的)同样改查引用,但只留调用处(名字后面紧跟实参的括号,中间可以隔着 `?.`、泛型实参),次数是落在几棵调用树里。 +- 调用树服务按「调用树的键」数、查(`callTree/session.ts` 的 `callTargets`):块自己的调用树键是块的记号,卡片上的操作键是操作的键(`actionKey`);`callTreeCounts` 消息按键发次数,页面点开发 `openCallTree { version, key }`,回 `callTree { key, … }`。同一版文档重发时问法(名字起点、查法、接口、不算的范围)没变的不再问。 -自定义钩子卡片:名称(function 色,带下标,后面跟「具名导出」「默认导出」小标签,同组件卡片)/ 说明(JSDoc 的正文)/ 对不上的参数 / 参数(「名称 \| 类型」表,有参数带默认值时多一列默认值,说明里有参数对上了 `@param` 时多一列说明;没有参数写「无」)/ 返回(只列名称:从最后那句 return 读,对象写的取各个键(简写的、改了名的),数组取各项,标识符是它自己,直接返回表达式的箭头函数读那个表达式;读不出、说明里也没写 `@return` 时不出这一行)/ 异常。样子同钩子卡片(钩子图标、钩子紫描边、自己写的淡底),能看调用树(查这个钩子在哪被调用);钩子体里的钩子调用是钩子卡片。 +自定义钩子卡片:名称(function 色,带下标,后面跟「具名导出」「默认导出」小标签,同组件卡片)/ 说明(JSDoc 的正文)/ 对不上的参数 / 参数(「名称 \| 类型」表,有参数带默认值时多一列默认值,说明里有参数对上了 `@param` 时多一列说明;没有参数写「无」)/ 返回(只列名称:从最后那句 return 读,对象写的取各个键(简写的、改了名的),数组取各项,标识符是它自己,直接返回表达式的箭头函数读那个表达式;读不出、说明里也没写 `@return` 时不出这一行)/ 异常。左边是函数、钩子两个图标,钩子紫描边、自己写的淡底,能看调用树(`RuleCard.calls`:右上角的按钮,查这个钩子在哪被调用);钩子体里的钩子调用同组件体里的一样按变量讲。 事件处理函数:名称是函数名(function 色,带下标);参数照常翻(`e: KeyboardEvent`),几个「, 」隔开,没有写「无」;绑定事件从 JSX 属性反查:「
(修改排队消息) 的 onKeyDown」,在属性值里调用时写传入的实参「(传入 h.id)」,在列表里一项项渲染的写「每个