@linkdesk/plugin-sdk 0.1.22 → 0.1.24

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.
@@ -0,0 +1,47 @@
1
+ /**
2
+ * CSS 选择器原语——插件侧两条命名空间判据的**共用底座**(E6#109h-b①)。
3
+ *
4
+ * ── 为什么单独一个文件 ──
5
+ * 「什么算**裸定义**」这件事只允许有**一份**实现(详案 15 §一:不许另写一个近似版)。
6
+ * 两条判据(`reserved-classes.ts` 的宿主保留名 / `plugin-prefix.ts` 的本仓前缀)都用
7
+ * `bareClassDefinitions()` 这一个遍历产出候选,再各自接上自己的裁决——于是「口径漂移」
8
+ * 这件事由构造不可能发生(两条腿读同一份候选,只是裁决条件不同)。
9
+ *
10
+ * 🔴 入参口径:`cleaned` 必须是 `stripComments(src)` 的输出(**等长**替换 ⇒ m.index 偏移与原文
11
+ * 对齐 ⇒ 行号可直接映射)。传原文会让注释里的 `{ }` 参与解析、且行号漂移。
12
+ *
13
+ * 判据口径(与壳仓 `scripts/check-css-namespace.mjs` 同源,见 11-样式命名空间审计.md):
14
+ * 裸定义 = 逗号切开后的某个 compound、**无祖先**(无空格/`>`/`+`/`~`)、主体**恰好是一个类名**
15
+ * (`.x.on` 这种复合不算——它不占名)。`.control-bar .combobox { }` 这类 **scoped 调优**是
16
+ * 合法消费,不在任何一条判据的射程内。
17
+ */
18
+ /** 一个「裸定义」的类名(占名行为的单位) */ export interface BareClassDefinition {
19
+ /** 类名(不含前导点) */
20
+ name: string;
21
+ /** 1-based;= **该规则块选择器首个非空白字符**所在行(多选择器块里各条共享这一行) */
22
+ line: number;
23
+ /** 逗号切开后的那一份选择器文本(保留原文,供报点回显) */
24
+ selector: string;
25
+ }
26
+ /** 一个 `@keyframes <name>` 的定义点 */
27
+ export interface KeyframeDefinition {
28
+ name: string;
29
+ /** 1-based;= `@keyframes` 关键字所在行 */
30
+ line: number;
31
+ }
32
+ /** 剥伪类/伪元素后取主体 compound */
33
+ export declare function subjectOf(compound: string): string;
34
+ /** 该复合选择器是否有祖先(有 ⇒ scoped 调优,不是裸定义) */
35
+ export declare function hasAncestor(compound: string): boolean;
36
+ /** 按逗号切选择器(括号深度感知) */
37
+ export declare function splitSelector(sel: string): string[];
38
+ /** 偏移 → 1-based 行号(cleaned 与原文等长,行号可直接映射) */
39
+ export declare const lineAt: (text: string, index: number) => number;
40
+ /**
41
+ * 列举一张样式表里的**裸定义**类名(同一条规则块里的多个选择器各出一份,共享块首行)。
42
+ * 入参 = `stripComments(src)` 的输出。
43
+ */
44
+ export declare function bareClassDefinitions(cleaned: string): BareClassDefinition[];
45
+ /** 列举 `@keyframes` 名(关键帧名同样是全局标识符——第二条命名空间) */
46
+ export declare function keyframeDefinitions(cleaned: string): KeyframeDefinition[];
47
+ //# sourceMappingURL=css-selectors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css-selectors.d.ts","sourceRoot":"","sources":["../../../src/eslint/checks/css-selectors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,0BAA0B,CAAA,MAAM,WAAW,mBAAmB;IAC5D,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,kCAAkC;AAClC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,2BAA2B;AAC3B,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIlD;AAED,uCAAuC;AACvC,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED,sBAAsB;AACtB,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAcnD;AAED,6CAA6C;AAC7C,eAAO,MAAM,MAAM,GAAI,MAAM,MAAM,EAAE,OAAO,MAAM,KAAG,MAAiD,CAAC;AAKvG;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAiB3E;AAED,+CAA+C;AAC/C,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAMzE"}
@@ -0,0 +1,70 @@
1
+ /** 剥伪类/伪元素后取主体 compound */
2
+ export function subjectOf(compound) {
3
+ const noPseudo = compound.replace(/::?[a-zA-Z-]+(\([^)]*\))?/g, "");
4
+ const parts = noPseudo.trim().split(/[\s>+~]+/);
5
+ return parts[parts.length - 1] ?? "";
6
+ }
7
+ /** 该复合选择器是否有祖先(有 ⇒ scoped 调优,不是裸定义) */
8
+ export function hasAncestor(compound) {
9
+ const noPseudo = compound.replace(/::?[a-zA-Z-]+(\([^)]*\))?/g, "").trim();
10
+ return noPseudo.split(/[\s>+~]+/).length > 1;
11
+ }
12
+ /** 按逗号切选择器(括号深度感知) */
13
+ export function splitSelector(sel) {
14
+ const parts = [];
15
+ let depth = 0;
16
+ let buf = "";
17
+ for (const ch of sel) {
18
+ if (ch === "(" || ch === "[")
19
+ depth++;
20
+ else if (ch === ")" || ch === "]")
21
+ depth--;
22
+ if (ch === "," && depth === 0) {
23
+ parts.push(buf);
24
+ buf = "";
25
+ }
26
+ else
27
+ buf += ch;
28
+ }
29
+ if (buf.trim())
30
+ parts.push(buf);
31
+ return parts.map((p) => p.trim()).filter(Boolean);
32
+ }
33
+ /** 偏移 → 1-based 行号(cleaned 与原文等长,行号可直接映射) */
34
+ export const lineAt = (text, index) => text.slice(0, index).split("\n").length;
35
+ /** 单类名主体——`.x` 命中、`.x.on` / `#id` / `div` 一律不命中(不占名) */
36
+ const SOLE_CLASS = /^\.(-?[_a-zA-Z][\w-]*)$/;
37
+ /**
38
+ * 列举一张样式表里的**裸定义**类名(同一条规则块里的多个选择器各出一份,共享块首行)。
39
+ * 入参 = `stripComments(src)` 的输出。
40
+ */
41
+ export function bareClassDefinitions(cleaned) {
42
+ const out = [];
43
+ for (const m of cleaned.matchAll(/([^{}]+)\{([^{}]*)\}/g)) {
44
+ const sel = m[1].trim();
45
+ if (sel.startsWith("@") || !m[2].trim())
46
+ continue; // @media 等 at-rule 头 / 空规则体不算定义
47
+ // 行号 = 选择器**第一个非空白字符**所在行(m.index 落在前导空白上——注释被等长替换成空格后
48
+ // 尤其明显;用 m.index 会把行号算到注释那一行 ⇒ disable 注释永远差一行)
49
+ const selStart = m.index + (m[1].length - m[1].trimStart().length);
50
+ const line = lineAt(cleaned, selStart);
51
+ for (const one of splitSelector(sel)) {
52
+ if (hasAncestor(one))
53
+ continue; // scoped 调优 = 合法消费
54
+ const cls = SOLE_CLASS.exec(subjectOf(one));
55
+ if (!cls)
56
+ continue; // 复合(.x.on)或非类选择器
57
+ out.push({ name: cls[1], line, selector: one });
58
+ }
59
+ }
60
+ return out;
61
+ }
62
+ /** 列举 `@keyframes` 名(关键帧名同样是全局标识符——第二条命名空间) */
63
+ export function keyframeDefinitions(cleaned) {
64
+ const out = [];
65
+ for (const m of cleaned.matchAll(/@keyframes\s+([\w-]+)/g)) {
66
+ out.push({ name: m[1], line: lineAt(cleaned, m.index) });
67
+ }
68
+ return out;
69
+ }
70
+ //# sourceMappingURL=css-selectors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css-selectors.js","sourceRoot":"","sources":["../../../src/eslint/checks/css-selectors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { type CheckViolation } from "./scan.js";
2
+ import { type ReservedNames } from "./reserved-classes.js";
3
+ /** `pluginId` 从哪来(判据④要求把「用了目录名兜底」这件事响亮打印出来) */
4
+ export type PluginIdSource = "plugin.json" | "dir-name";
5
+ export interface PluginIdResolution {
6
+ pluginId: string | null;
7
+ source: PluginIdSource | null;
8
+ /** 非 null = **拿不到前缀**(判据④ fail-closed 的原因原文);此时 pluginId/source 均为 null */
9
+ error: string | null;
10
+ /** 目录名兜底时的提示行(不为 null ⇒ 报告里必须打印,不许静默) */
11
+ note: string | null;
12
+ }
13
+ /**
14
+ * 取本仓 `pluginId`——**复用 loader 自己的裁决函数**(`derivePluginId` + `readPluginManifest`,
15
+ * 硬约束 11 的同一份契约),不另写一套 id 规则(否则门禁认可的 id 与运行时安装的 id 会漂移)。
16
+ *
17
+ * `plugin.json` 是 **JSONC**(可注释/尾逗号,作者面允许)⇒ 走 `readPluginManifest`(jsonc-parser)。
18
+ */
19
+ export declare function resolvePluginIdForCss(root: string): PluginIdResolution;
20
+ /** 一处不合规站点(审计工具与报点共用同一份数据——③–⑦ 的改名映射表由它生成) */
21
+ export interface PrefixSite {
22
+ /** 工程相对路径(正斜杠) */
23
+ file: string;
24
+ /** 1-based;类名站点 = 规则块选择器首行,关键帧站点 = `@keyframes` 所在行 */
25
+ line: number;
26
+ /** 现名(不含前导点) */
27
+ name: string;
28
+ /** 应改成的名字(叠加形状:`<pluginId>-` + 现名) */
29
+ suggested: string;
30
+ /** 类名站点独有:逗号切开后的那一份选择器文本 */
31
+ selector?: string;
32
+ /** 该名字**同时**是宿主保留名(清单 `reserved-class-names.json`)——只影响措辞,不影响是否报 */
33
+ reserved: boolean;
34
+ reservedWhy?: string;
35
+ }
36
+ export interface PluginPrefixReport {
37
+ root: string;
38
+ pluginId: string | null;
39
+ pluginIdSource: PluginIdSource | null;
40
+ /** 目录名兜底的提示(必须打印) */
41
+ pluginIdNote: string | null;
42
+ /** 判据④:非 null ⇒ fail-closed 红 */
43
+ error: string | null;
44
+ /** 判据③:`pluginId` 以 `ldk-` 开头时 = 那个 pluginId,否则 null */
45
+ boundary: string | null;
46
+ /** 判据① 的站点(已过豁免) */
47
+ classes: PrefixSite[];
48
+ /** 判据② 的站点(已过豁免) */
49
+ keyframes: PrefixSite[];
50
+ /** 腿的报点 = ③④(先行、不可豁免)+ ①②(过豁免);顺序即打印顺序 */
51
+ violations: CheckViolation[];
52
+ }
53
+ /**
54
+ * 跑本仓前缀判据。返回结构化报告(审计工具用)+ 腿报点(`lint.ts` 用)——**同一份实现**,
55
+ * 没有第二条判据路径。
56
+ */
57
+ export declare function runPluginPrefixCheck(root: string, reserved?: ReservedNames): PluginPrefixReport;
58
+ //# sourceMappingURL=plugin-prefix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-prefix.d.ts","sourceRoot":"","sources":["../../../src/eslint/checks/plugin-prefix.ts"],"names":[],"mappings":"AAoCA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjE,OAAO,EAAqB,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE9E,+CAA+C;AAC/C,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,UAAU,CAAC;AAExD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9B,2EAA2E;IAC3E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,yCAAyC;IACzC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAkDtE;AAED,8CAA8C;AAC9C,MAAM,WAAW,UAAU;IACzB,kBAAkB;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,qBAAqB;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,iCAAiC;IACjC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,oBAAoB;IACpB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,oBAAoB;IACpB,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,0CAA0C;IAC1C,UAAU,EAAE,cAAc,EAAE,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,aAAmC,GAAG,kBAAkB,CA0GpH"}
@@ -0,0 +1,192 @@
1
+ /**
2
+ * check-css-namespace 腿·**本仓前缀判据**(E6#109h-b①)——插件 CSS 里**给自有元素起的类名、以及
3
+ * 自己的 `@keyframes` 名,必须以本仓 `pluginId` 加一个连字符开头**。
4
+ *
5
+ * ── 为什么(本系列立项的那条轴)──
6
+ * 插件视图的一张样式表里同时装着宿主 CSS + 共享组件 CSS + **所有已加载插件的 CSS**(实机读数:池文档
7
+ * 8 张样式表)⇒ 裸类名是**全局标识符**。件 1/件 4 把宿主与共享组件侧清成了 `ldk-`,剩下的
8
+ * **插件 ↔ 插件轴今天完全没有保护**——而且不是理论风险:`file-tree/SearchView.css:24` 与
9
+ * `serial-monitor/SerialMonitorView.css:147` **裸定义了同一个 `.search-input`**(两份规则体不同 ⇒
10
+ * 级联合并、视觉走形),这正是 `.badge` 案的同一形态(**不报错、只是长得不对**)。
11
+ * 升级后的规则**不需要任何清单**:唯一性由 `pluginId` 免费提供(硬约束 11:发布后不可变)。
12
+ *
13
+ * ── 四条判据(详案 15 §一;全部可机械校验)──
14
+ * ① 裸定义类名必须以 `<pluginId>-` 开头
15
+ * ② `@keyframes` 名必须以 `<pluginId>-` 开头(拍板 Q3=(A):关键帧名同样是全局的)
16
+ * ③ `pluginId` 自身不得以 `ldk-` 开头(拍板 Q4=(A):`ldk-` 是宿主命名空间——作者面 §12
17
+ * 「凡 `ldk-` 开头都是宿主/共享组件的」,一个 `pluginId: "ldk-tools"` 的插件用自己的
18
+ * `<pluginId>-*` 前缀就会**由构造落进宿主空间**,且让 ①② 全部失效)
19
+ * ④ **fail-closed**:`plugin.json` 不存在 / 解析失败 / 拿不到合法的 `pluginId`(含目录名兜底也不行)
20
+ * ⇒ 红。**拿不到前缀就无法校验——静默放过 = 门禁变瞎子**。
21
+ *
22
+ * ── 口径与豁免 ──
23
+ * · 「裸定义」的遍历与宿主保留名判据**共用同一份实现**(`css-selectors.ts` 的
24
+ * `bareClassDefinitions`;巡检单元也共用 `scan.ts` 的 `collectCssUnits`)——两条腿看到的是
25
+ * **同一批站点**,只是裁决不同。
26
+ * · 保留名清单不删:命中的名字**同时**是宿主保留名时,报点里补一句措辞(详案 15 §二)。
27
+ * · 知情绕行 = 标准 disable 注释(`CHECK_IDS.cssNamespace`,与保留名判据**同一个 id**)。
28
+ * ⚠️ **③/④ 不参与豁免**:它们说的不是「你的 CSS 怎么写」,而是「你的身份/清单拿不拿得到」——
29
+ * 那是工程根的问题,不该被样式表里的一行注释绕过去。
30
+ * · 前缀形状 = **叠加**(`ms-item` → `marketplace-ms-item`):只插入不改词干,是唯一能用
31
+ * 「逐字节只插入前缀」机械证明零视觉变化的形状(详案 10 §二)。故 `suggested` 一律是
32
+ * `<pluginId>-` + 原名。
33
+ */
34
+ import { existsSync } from "node:fs";
35
+ import { basename, join, resolve } from "node:path";
36
+ import { derivePluginId, readPluginManifest } from "../../validate.js";
37
+ import { collectCssUnits } from "./scan.js";
38
+ import { bareClassDefinitions, keyframeDefinitions } from "./css-selectors.js";
39
+ import { isDisabled, CHECK_IDS } from "./disable.js";
40
+ import { loadReservedNames } from "./reserved-classes.js";
41
+ /**
42
+ * 取本仓 `pluginId`——**复用 loader 自己的裁决函数**(`derivePluginId` + `readPluginManifest`,
43
+ * 硬约束 11 的同一份契约),不另写一套 id 规则(否则门禁认可的 id 与运行时安装的 id 会漂移)。
44
+ *
45
+ * `plugin.json` 是 **JSONC**(可注释/尾逗号,作者面允许)⇒ 走 `readPluginManifest`(jsonc-parser)。
46
+ */
47
+ export function resolvePluginIdForCss(root) {
48
+ const absRoot = resolve(root);
49
+ const dirName = basename(absRoot);
50
+ const manifestPath = join(absRoot, "plugin.json");
51
+ if (!existsSync(manifestPath)) {
52
+ return {
53
+ pluginId: null,
54
+ source: null,
55
+ error: `plugin.json 不在工程根(${manifestPath})——本判据以「本仓 pluginId」为唯一前缀来源,读不到它就无从校验`,
56
+ note: null,
57
+ };
58
+ }
59
+ let manifest;
60
+ try {
61
+ manifest = readPluginManifest(manifestPath);
62
+ }
63
+ catch (e) {
64
+ return {
65
+ pluginId: null,
66
+ source: null,
67
+ error: `plugin.json 读不出(${e instanceof Error ? e.message : String(e)})`,
68
+ note: null,
69
+ };
70
+ }
71
+ const declared = manifest?.pluginId;
72
+ try {
73
+ const pluginId = derivePluginId(manifest, dirName);
74
+ if (declared === undefined || declared === null) {
75
+ return {
76
+ pluginId,
77
+ source: "dir-name",
78
+ error: null,
79
+ note: `plugin.json 未显式声明 pluginId——本判据按工程目录名 "${pluginId}" 兜底` +
80
+ `(发布后身份不可变,建议显式声明以防目录改名 = 身份漂移)`,
81
+ };
82
+ }
83
+ return { pluginId, source: "plugin.json", error: null, note: null };
84
+ }
85
+ catch (e) {
86
+ return {
87
+ pluginId: null,
88
+ source: null,
89
+ error: `${e instanceof Error ? e.message : String(e)}——且工程目录名 "${dirName}" 也不能兜底` +
90
+ `(目录名同样不合法)`,
91
+ note: null,
92
+ };
93
+ }
94
+ }
95
+ /**
96
+ * 跑本仓前缀判据。返回结构化报告(审计工具用)+ 腿报点(`lint.ts` 用)——**同一份实现**,
97
+ * 没有第二条判据路径。
98
+ */
99
+ export function runPluginPrefixCheck(root, reserved = loadReservedNames()) {
100
+ const absRoot = resolve(root);
101
+ const resolution = resolvePluginIdForCss(absRoot);
102
+ const violations = [];
103
+ const report = {
104
+ root: absRoot,
105
+ pluginId: resolution.pluginId,
106
+ pluginIdSource: resolution.source,
107
+ pluginIdNote: resolution.note,
108
+ error: resolution.error,
109
+ boundary: null,
110
+ classes: [],
111
+ keyframes: [],
112
+ violations,
113
+ };
114
+ // ── ④ fail-closed(不可豁免:拿不到前缀 = 这条腿瞎了)──
115
+ if (resolution.error || !resolution.pluginId) {
116
+ violations.push({
117
+ file: "plugin.json",
118
+ line: 1,
119
+ message: `拿不到本仓前缀:${resolution.error}。**判据不许静默放过**——无法校验「裸定义/关键帧是否带本仓` +
120
+ `前缀」时本腿一律报红(静默放过 = 门禁变瞎子)。在插件工程根修好 plugin.json(或在 plugin.json ` +
121
+ `显式声明 pluginId),不要用 disable 注释绕:③/④ 这类身份问题不受豁免注释管辖。`,
122
+ });
123
+ return report;
124
+ }
125
+ const pluginId = resolution.pluginId;
126
+ const prefix = `${pluginId}-`;
127
+ // ── ③ `ldk-` 边界(不可豁免:借的是宿主命名空间,且会让 ①② 全部失效)──
128
+ if (pluginId.startsWith("ldk-")) {
129
+ report.boundary = pluginId;
130
+ violations.push({
131
+ file: "plugin.json",
132
+ line: 1,
133
+ message: `pluginId "${pluginId}" 以 "ldk-" 开头——\`ldk-\` 是**宿主/共享组件命名空间**(作者面 §12:` +
134
+ `凡 ldk- 开头都是宿主的)。用它派生的 <pluginId>-* 前缀会**由构造落进宿主空间**,` +
135
+ `与本判据 ①② 自相矛盾(两条都失效)。请改 pluginId(硬约束 11:发布后身份不可变,现在改最便宜);` +
136
+ `schema 侧同一句约束由 1.14⑧ 收进 pattern。`,
137
+ });
138
+ }
139
+ // ── ①② 裸定义类名 / `@keyframes` 名必须以 `<pluginId>-` 开头 ──
140
+ const classReserved = new Map(reserved.classes.map((c) => [c.name, c]));
141
+ const kfReserved = new Map(reserved.keyframes.map((k) => [k.name, k]));
142
+ const pushSite = (file, line, message, unitDisabled) => {
143
+ if (isDisabled(unitDisabled, line, CHECK_IDS.cssNamespace))
144
+ return false;
145
+ violations.push({ file, line, message });
146
+ return true;
147
+ };
148
+ for (const unit of collectCssUnits(absRoot, [CHECK_IDS.cssNamespace])) {
149
+ for (const def of bareClassDefinitions(unit.cleaned)) {
150
+ if (def.name.startsWith(prefix))
151
+ continue; // 合规:本仓前缀
152
+ const reservedEntry = classReserved.get(def.name);
153
+ const site = {
154
+ file: unit.rel,
155
+ line: def.line,
156
+ name: def.name,
157
+ suggested: prefix + def.name,
158
+ selector: def.selector,
159
+ reserved: reservedEntry !== undefined,
160
+ ...(reservedEntry ? { reservedWhy: reservedEntry.why } : {}),
161
+ };
162
+ const kept = pushSite(unit.rel, def.line, `${def.selector} ← 裸定义类名不带本仓前缀(本插件 pluginId = "${pluginId}",应以 "${prefix}" 开头)` +
163
+ `——插件视图里宿主、共享组件与**所有已加载插件**同表,裸类名是全局标识符(「.badge」案同形:` +
164
+ `不报错、只是长得不对)。改成 .${site.suggested}(前缀只插入、不改词干 ⇒ 零视觉变化);` +
165
+ `要那个样子就直接用对应组件(@linkdesk/ui)` +
166
+ (reservedEntry ? `。⚠ 且这是**宿主保留名**(${reservedEntry.why})` : ""), unit.disabled);
167
+ if (kept)
168
+ report.classes.push(site);
169
+ }
170
+ for (const kf of keyframeDefinitions(unit.cleaned)) {
171
+ if (kf.name.startsWith(prefix))
172
+ continue;
173
+ const reservedEntry = kfReserved.get(kf.name);
174
+ const site = {
175
+ file: unit.rel,
176
+ line: kf.line,
177
+ name: kf.name,
178
+ suggested: prefix + kf.name,
179
+ reserved: reservedEntry !== undefined,
180
+ ...(reservedEntry ? { reservedWhy: reservedEntry.why } : {}),
181
+ };
182
+ const kept = pushSite(unit.rel, kf.line, `@keyframes ${kf.name} ← 关键帧名不带本仓前缀(pluginId = "${pluginId}",应以 "${prefix}" 开头)` +
183
+ `——关键帧名同样是全局的,先加载者/后定义者互相覆盖。改成 @keyframes ${site.suggested},` +
184
+ `**并同笔改 animation: 引用处**(漏改引用 = 动画静默消失,同形风险)` +
185
+ (reservedEntry ? `。⚠ 且与**宿主关键帧**同名(${reservedEntry.why})` : ""), unit.disabled);
186
+ if (kept)
187
+ report.keyframes.push(site);
188
+ }
189
+ }
190
+ return report;
191
+ }
192
+ //# sourceMappingURL=plugin-prefix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-prefix.js","sourceRoot":"","sources":["../../../src/eslint/checks/plugin-prefix.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"reserved-classes.d.ts","sourceRoot":"","sources":["../../../src/eslint/checks/reserved-classes.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAqE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAYnH,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,SAAS,EAAE,aAAa,EAAE,CAAC;CAC5B;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,MAAsB,GAAG,aAAa,CAU7E;AAmCD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,aAAmC,GAAG,cAAc,EAAE,CAsDnH"}
1
+ {"version":3,"file":"reserved-classes.d.ts","sourceRoot":"","sources":["../../../src/eslint/checks/reserved-classes.ts"],"names":[],"mappings":"AAkCA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAWjE,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,SAAS,EAAE,aAAa,EAAE,CAAC;CAC5B;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,MAAsB,GAAG,aAAa,CAU7E;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,aAAmC,GAAG,cAAc,EAAE,CAsCnH"}
@@ -1,5 +1,6 @@
1
1
  /**
2
- * check-css-namespace 腿(E6#109e)——插件 CSS **不得裸定义宿主保留名**。
2
+ * check-css-namespace 腿·**宿主保留名判据**(E6#109e;E6#109h-b① 起为双判据之一)——插件 CSS
3
+ * **不得裸定义宿主保留名**。
3
4
  *
4
5
  * 🔴 判据(与壳仓 `scripts/check-css-namespace.mjs` 同源,见 11-样式命名空间审计.md):
5
6
  * 插件视图的一张样式表里**同时装着宿主 CSS + 共享组件 CSS + 所有已加载插件的 CSS**(实机读数:
@@ -13,14 +14,27 @@
13
14
  * 保留名清单 = 包内 `schemas/reserved-class-names.json`(**单一真相源**,壳仓门禁读同一份);
14
15
  * 清单里没有的名字随便用——但请给自有元素带插件前缀(作者面纪律见 05-插件UI写法规约 §12)。
15
16
  *
17
+ * ── 🔴 E6#109h-b① 起本判据的**位置变了**(用户拍板 Q1=(A),详案 15 §二)──
18
+ * 命名空间判据从「不许裸定义**保留名**」(黑名单,要查表)升级为「裸定义必须以 **`<pluginId>-`**
19
+ * 开头」(`plugin-prefix.ts`,**不需要任何清单**)。在「裸定义」这一轴上,**前缀判据完全覆盖本判据**
20
+ * (插件不可能再裸定义 `.badge`——它必须以 `<pluginId>-` 开头),故:
21
+ * ① **不重复报同一处**:`lint.ts` 里两条判据的报点按 `文件:行` 去重(前缀优先,见该文件);
22
+ * ② 清单的角色变成**报点措辞的补充**——前缀腿命中一个同时是保留名的名字时,消息里补一句
23
+ * 「且这是宿主保留名(`reserved-class-names.json`,<why>)」;
24
+ * ③ 本判据仍**独立保留**:拿不到前缀(`plugin.json` 缺失/损坏 ⇒ 前缀腿 fail-closed)时它是唯一
25
+ * 能逐点报出「你占了一个宿主名字」的腿。⚠️ **清单本身不许删**——它仍是作者面 §12 表、
26
+ * `check-reserved-names-doc-sync` 对账门禁与 scoped 调优纪律的真相源。
27
+ *
16
28
  * 知情绕行 = 标准 disable 注释(`CHECK_IDS.cssNamespace`),与另三条腿同一套机制。
29
+ * ⚠️ 已知口径(详案 15 §二·选项 (A) 的代价,写进作者面是 1.14⑧ 的活):**同一个 id 同时盖住
30
+ * 「保留名」与「前缀」两条判据**——既有 disable 注释会一起绕行(作者面已声明 disable = 知情绕行)。
17
31
  */
18
32
  import { readFileSync, existsSync } from "node:fs";
19
33
  import { resolve, dirname } from "node:path";
20
34
  import { fileURLToPath } from "node:url";
21
- import { collectFiles, relPath, readSource, stripComments, isTestOrMockRel } from "./scan.js";
22
- import { buildDisableIndex, isDisabled, CHECK_IDS } from "./disable.js";
23
- const EXT_CSS = [".css"];
35
+ import { collectCssUnits } from "./scan.js";
36
+ import { bareClassDefinitions, keyframeDefinitions } from "./css-selectors.js";
37
+ import { isDisabled, CHECK_IDS } from "./disable.js";
24
38
  /**
25
39
  * 包内保留名清单定位(dist/eslint/checks/x.js → ../../../schemas = 包根/schemas;src 直跑同样命中)。
26
40
  * 🔴 写法必须是「路径式」(resolve + fileURLToPath)——`new URL(<字面量>, import.meta.url)` 是
@@ -37,88 +51,34 @@ export function loadReservedNames(file = RESERVED_FILE) {
37
51
  keyframes: raw.keyframes ?? [],
38
52
  };
39
53
  }
40
- /** 剥伪类/伪元素后取主体 compound */
41
- function subjectOf(compound) {
42
- const noPseudo = compound.replace(/::?[a-zA-Z-]+(\([^)]*\))?/g, "");
43
- const parts = noPseudo.trim().split(/[\s>+~]+/);
44
- return parts[parts.length - 1] ?? "";
45
- }
46
- /** 该复合选择器是否有祖先(有 ⇒ scoped 调优,不是裸定义) */
47
- function hasAncestor(compound) {
48
- const noPseudo = compound.replace(/::?[a-zA-Z-]+(\([^)]*\))?/g, "").trim();
49
- return noPseudo.split(/[\s>+~]+/).length > 1;
50
- }
51
- /** 按逗号切选择器(括号深度感知) */
52
- function splitSelector(sel) {
53
- const parts = [];
54
- let depth = 0;
55
- let buf = "";
56
- for (const ch of sel) {
57
- if (ch === "(" || ch === "[")
58
- depth++;
59
- else if (ch === ")" || ch === "]")
60
- depth--;
61
- if (ch === "," && depth === 0) {
62
- parts.push(buf);
63
- buf = "";
64
- }
65
- else
66
- buf += ch;
67
- }
68
- if (buf.trim())
69
- parts.push(buf);
70
- return parts.map((p) => p.trim()).filter(Boolean);
71
- }
72
- /** 偏移 → 1-based 行号(cleaned 与原文等长,行号可直接映射) */
73
- const lineAt = (text, index) => text.slice(0, index).split("\n").length;
74
54
  export function runReservedClassCheck(root, reserved = loadReservedNames()) {
75
55
  const violations = [];
76
56
  if (!reserved.classes.length && !reserved.keyframes.length)
77
57
  return violations;
78
58
  const classMap = new Map(reserved.classes.map((c) => [c.name, c]));
79
59
  const kfMap = new Map(reserved.keyframes.map((k) => [k.name, k]));
80
- for (const file of collectFiles(root, EXT_CSS)) {
81
- const rel = relPath(root, file);
82
- if (isTestOrMockRel(rel))
83
- continue;
84
- const src = readSource(file);
85
- const cleaned = stripComments(src); // 等长替换 ⇒ 偏移与原文对齐
86
- const disabled = buildDisableIndex(src, [CHECK_IDS.cssNamespace]);
60
+ for (const unit of collectCssUnits(root, [CHECK_IDS.cssNamespace])) {
87
61
  const push = (line, message) => {
88
- if (isDisabled(disabled, line, CHECK_IDS.cssNamespace))
62
+ if (isDisabled(unit.disabled, line, CHECK_IDS.cssNamespace))
89
63
  return;
90
- violations.push({ file: rel, line, message });
64
+ violations.push({ file: unit.rel, line, message });
91
65
  };
92
66
  // ① 裸定义宿主保留类名
93
- for (const m of cleaned.matchAll(/([^{}]+)\{([^{}]*)\}/g)) {
94
- const sel = m[1].trim();
95
- if (sel.startsWith("@") || !m[2].trim())
67
+ for (const def of bareClassDefinitions(unit.cleaned)) {
68
+ const entry = classMap.get(def.name);
69
+ if (!entry)
96
70
  continue;
97
- // 行号 = 选择器**第一个非空白字符**所在行(m.index 落在前导空白上——注释被等长替换成空格后
98
- // 尤其明显;用 m.index 会把行号算到注释那一行 ⇒ disable 注释永远差一行)
99
- const selStart = m.index + (m[1].length - m[1].trimStart().length);
100
- for (const one of splitSelector(sel)) {
101
- if (hasAncestor(one))
102
- continue; // scoped 调优 = 合法消费
103
- const subject = subjectOf(one);
104
- const cls = subject.match(/^\.(-?[_a-zA-Z][\w-]*)$/);
105
- if (!cls)
106
- continue; // 复合(.x.on)或非类选择器
107
- const entry = classMap.get(cls[1]);
108
- if (!entry)
109
- continue;
110
- push(lineAt(cleaned, selStart), `${sel} ← 裸定义宿主保留名 .${entry.name}(${entry.why})——插件视图里宿主、共享组件与` +
111
- `所有插件同表,这个名字会命中别的元素。给自有元素改用插件前缀类名(如 .<你的插件>-…);` +
112
- `要那个样子就直接用对应组件(@linkdesk/ui)`);
113
- }
71
+ push(def.line, `${def.selector} ← 裸定义宿主保留名 .${entry.name}(${entry.why})——插件视图里宿主、共享组件与` +
72
+ `所有插件同表,这个名字会命中别的元素。给自有元素改用插件前缀类名(如 .<你的插件>-…);` +
73
+ `要那个样子就直接用对应组件(@linkdesk/ui)`);
114
74
  }
115
75
  // ② 关键帧名撞宿主(@keyframes 同样是全局的)
116
- for (const m of cleaned.matchAll(/@keyframes\s+([\w-]+)/g)) {
117
- const entry = kfMap.get(m[1]);
76
+ for (const kf of keyframeDefinitions(unit.cleaned)) {
77
+ const entry = kfMap.get(kf.name);
118
78
  if (!entry)
119
79
  continue;
120
- push(lineAt(cleaned, m.index), `@keyframes ${m[1]} ← 与宿主关键帧同名(${entry.why})——先加载者/后定义者互相覆盖。` +
121
- `改用插件前缀名(如 <你的插件>-${m[1]})`);
80
+ push(kf.line, `@keyframes ${kf.name} ← 与宿主关键帧同名(${entry.why})——先加载者/后定义者互相覆盖。` +
81
+ `改用插件前缀名(如 <你的插件>-${kf.name})`);
122
82
  }
123
83
  }
124
84
  return violations;
@@ -1 +1 @@
1
- {"version":3,"file":"reserved-classes.js","sourceRoot":"","sources":["../../../src/eslint/checks/reserved-classes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reserved-classes.js","sourceRoot":"","sources":["../../../src/eslint/checks/reserved-classes.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { type DisableIndex } from "./disable.js";
1
2
  export declare const SKIP_DIRS: Set<string>;
2
3
  /** 收集 dir 下指定扩展名文件(跳过 SKIP_DIRS)。返回绝对路径数组。 */
3
4
  export declare function collectFiles(dir: string, exts: string[]): string[];
@@ -17,4 +18,23 @@ export interface CheckViolation {
17
18
  /** eslint-disable 知情绕行的理由(若该行被豁免注释标记);未豁免 = undefined */
18
19
  bypassReason?: string;
19
20
  }
21
+ /** 一条**命名空间判据**的巡检单元——CSS 文件 + 它的解析输入 + 它的豁免索引 */
22
+ export interface CssScanUnit {
23
+ /** 工程相对路径(正斜杠)——报点里一律用它 */
24
+ rel: string;
25
+ /** 原文(豁免索引从它建:disable 注释是给人读的注释,剥注释后仍在原文里) */
26
+ src: string;
27
+ /** `stripComments(src)` 的输出——等长替换 ⇒ 行号与原文对齐,判据的解析输入 */
28
+ cleaned: string;
29
+ /** 本 check 的知情绕行索引 */
30
+ disabled: DisableIndex;
31
+ }
32
+ /**
33
+ * 收集**两条命名空间判据**(宿主保留名 / 本仓前缀)的巡检单元(E6#109h-b①)。
34
+ *
35
+ * 🔴 为什么做成共用函数而不是各写一遍 for 循环:两条判据必须**看到完全同一批站点**
36
+ * (同一组文件、同一套「跳过测试/mock」口径、同一份豁免索引)——否则「前缀判据覆盖保留名判据」
37
+ * 这句话就只是约定而非结构。射程 = 只扫 `.css`(`EXT_CSS`,与现腿一致)。
38
+ */
39
+ export declare function collectCssUnits(root: string, wantedIds: string[]): CssScanUnit[];
20
40
  //# sourceMappingURL=scan.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/eslint/checks/scan.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,SAAS,aAAyF,CAAC;AAEhH,8CAA8C;AAC9C,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAoBlE;AAED,kBAAkB;AAClB,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,sCAAsC;AACtC,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB"}
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/eslint/checks/scan.ts"],"names":[],"mappings":"AAUA,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAEpE,eAAO,MAAM,SAAS,aAAyF,CAAC;AAEhH,8CAA8C;AAC9C,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAoBlE;AAED,kBAAkB;AAClB,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,sCAAsC;AACtC,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAKD,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC1B,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,sBAAsB;IACtB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAShF"}
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import { readdirSync, readFileSync, existsSync } from "node:fs";
10
10
  import { join, relative, sep } from "node:path";
11
+ import { buildDisableIndex } from "./disable.js";
11
12
  export const SKIP_DIRS = new Set(["node_modules", "dist", "dist-electron", ".git", ".vite", "coverage", "out"]);
12
13
  /** 收集 dir 下指定扩展名文件(跳过 SKIP_DIRS)。返回绝对路径数组。 */
13
14
  export function collectFiles(dir, exts) {
@@ -60,4 +61,24 @@ export function isTestOrMockRel(rel) {
60
61
  export function readSource(abs) {
61
62
  return readFileSync(abs, "utf8");
62
63
  }
64
+ /** 命名空间判据的扫描扩展名 */
65
+ const EXT_CSS = [".css"];
66
+ /**
67
+ * 收集**两条命名空间判据**(宿主保留名 / 本仓前缀)的巡检单元(E6#109h-b①)。
68
+ *
69
+ * 🔴 为什么做成共用函数而不是各写一遍 for 循环:两条判据必须**看到完全同一批站点**
70
+ * (同一组文件、同一套「跳过测试/mock」口径、同一份豁免索引)——否则「前缀判据覆盖保留名判据」
71
+ * 这句话就只是约定而非结构。射程 = 只扫 `.css`(`EXT_CSS`,与现腿一致)。
72
+ */
73
+ export function collectCssUnits(root, wantedIds) {
74
+ const out = [];
75
+ for (const file of collectFiles(root, EXT_CSS)) {
76
+ const rel = relPath(root, file);
77
+ if (isTestOrMockRel(rel))
78
+ continue;
79
+ const src = readSource(file);
80
+ out.push({ rel, src, cleaned: stripComments(src), disabled: buildDisableIndex(src, wantedIds) });
81
+ }
82
+ return out;
83
+ }
63
84
  //# sourceMappingURL=scan.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/eslint/checks/scan.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAEhD,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC;AAEhH,8CAA8C;AAC9C,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,IAAc;IACtD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,CAAC,GAAW,EAAQ,EAAE;QACjC,IAAI,OAAO,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,eAAe;QACzB,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;oBAAE,SAAS;gBACxC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAC9B,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IACF,IAAI,UAAU,CAAC,GAAG,CAAC;QAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,kBAAkB;AAClB,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,GAAW;IAC/C,OAAO,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED,sCAAsC;AACtC,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,CAAS;IACrC,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,MAAM,EAAE,IAAI,CAAC;QAAE,IAAI,EAAE,KAAK,IAAI;YAAE,CAAC,EAAE,CAAC;IACzC,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,OAAO,6BAA6B,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,gCAAgC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/F,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,OAAO,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AACnC,CAAC"}
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/eslint/checks/scan.ts"],"names":[],"mappings":"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"}
@@ -5,11 +5,18 @@
5
5
  * "lint": "linkdesk-plugin-sdk lint" // 两条腿全跑 + 打印报告(bin)
6
6
  * // 或编程:linkdeskPluginLintConfig() 展开进作者自配 eslint.config.js
7
7
  *
8
- * 全量门禁 = eslint 规则腿 + check 扫描腿(lint.ts 编排)。规则 id 与 disable 注释格式
9
- * 见 src/eslint/rules.ts 头注(双源注记)。这里不暴露内部 check 函数——bin lint 已聚合。
8
+ * 全量门禁 = eslint 规则腿 + 四条 check 扫描腿(lint.ts 编排)。规则 id 与 disable 注释格式
9
+ * 见 src/eslint/rules.ts 头注(双源注记)。除下面这一条**审计入口**外不暴露内部 check 函数——
10
+ * bin lint 已聚合。
11
+ *
12
+ * 🔴 E6#109h-b①:`runPluginPrefixCheck` 是**唯一一个对内 check 的具名导出**,专供壳仓只读审计工具
13
+ * `scripts/plugin-css-prefix-audit.mjs`(改名轮 ③–⑦ 生成「旧名 → 新名」映射、⑧ 全量复核)。
14
+ * **它不是第二条判据路径**:`lint.ts` 的腿用的是**同一个函数**——工具与腿同源,改一处两边一起变。
10
15
  */
11
16
  export { linkdeskPluginLintConfig } from "./preset.js";
12
17
  export type { PluginLintOptions } from "./preset.js";
13
18
  export { runPluginLint, renderPluginLintReport } from "./lint.js";
14
19
  export type { PluginLintReport, LintLeg } from "./lint.js";
20
+ export { runPluginPrefixCheck, resolvePluginIdForCss } from "./checks/plugin-prefix.js";
21
+ export type { PluginPrefixReport, PrefixSite, PluginIdResolution, PluginIdSource } from "./checks/plugin-prefix.js";
15
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/eslint/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAClE,YAAY,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/eslint/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAClE,YAAY,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACxF,YAAY,EAAE,kBAAkB,EAAE,UAAU,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC"}
@@ -5,9 +5,15 @@
5
5
  * "lint": "linkdesk-plugin-sdk lint" // 两条腿全跑 + 打印报告(bin)
6
6
  * // 或编程:linkdeskPluginLintConfig() 展开进作者自配 eslint.config.js
7
7
  *
8
- * 全量门禁 = eslint 规则腿 + check 扫描腿(lint.ts 编排)。规则 id 与 disable 注释格式
9
- * 见 src/eslint/rules.ts 头注(双源注记)。这里不暴露内部 check 函数——bin lint 已聚合。
8
+ * 全量门禁 = eslint 规则腿 + 四条 check 扫描腿(lint.ts 编排)。规则 id 与 disable 注释格式
9
+ * 见 src/eslint/rules.ts 头注(双源注记)。除下面这一条**审计入口**外不暴露内部 check 函数——
10
+ * bin lint 已聚合。
11
+ *
12
+ * 🔴 E6#109h-b①:`runPluginPrefixCheck` 是**唯一一个对内 check 的具名导出**,专供壳仓只读审计工具
13
+ * `scripts/plugin-css-prefix-audit.mjs`(改名轮 ③–⑦ 生成「旧名 → 新名」映射、⑧ 全量复核)。
14
+ * **它不是第二条判据路径**:`lint.ts` 的腿用的是**同一个函数**——工具与腿同源,改一处两边一起变。
10
15
  */
11
16
  export { linkdeskPluginLintConfig } from "./preset.js";
12
17
  export { runPluginLint, renderPluginLintReport } from "./lint.js";
18
+ export { runPluginPrefixCheck, resolvePluginIdForCss } from "./checks/plugin-prefix.js";
13
19
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/eslint/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/eslint/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAElE,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -19,6 +19,10 @@ export interface PluginLintReport {
19
19
  legs: LintLeg[];
20
20
  totalCheckViolations: number;
21
21
  tsconfigUsed: string | null;
22
+ /** 本仓 pluginId(命名空间腿的前缀来源;取不到 ⇒ null 且该腿 fail-closed 报红) */
23
+ pluginId: string | null;
24
+ /** pluginId 走了「目录名兜底」时的提示行——**必须打印**(详案 15 §一:让作者知道门禁用的是目录名) */
25
+ pluginIdNote: string | null;
22
26
  }
23
27
  export declare function runPluginLint(root: string, options?: PluginLintOptions): Promise<PluginLintReport>;
24
28
  /** 打印报告(人机双通道的即时反馈环);返回进程退出码(真 error 才 1,WARN 永不 fail)。 */
@@ -1 +1 @@
1
- {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/eslint/lint.ts"],"names":[],"mappings":"AAcA,OAAO,EAA4B,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAK/E,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKvD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,cAAc,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA6D5G;AAED,2DAA2D;AAC3D,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAkCvE"}
1
+ {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/eslint/lint.ts"],"names":[],"mappings":"AAmBA,OAAO,EAA4B,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAM/E,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKvD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,cAAc,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,gEAAgE;IAChE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAmF5G;AAED,2DAA2D;AAC3D,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAqCvE"}
@@ -1,5 +1,10 @@
1
1
  /**
2
- * `runPluginLint()`——`npm run lint` 门禁编排(E6#54d):eslint 规则腿 + check 扫描腿双轨。
2
+ * `runPluginLint()`——`npm run lint` 门禁编排(E6#54d):eslint 规则腿 + 四条 check 扫描腿双轨。
3
+ *
4
+ * E6#109h-b①:`check-css-namespace` 腿升级为**双判据**——「裸定义类名/关键帧必须以本仓 `<pluginId>-`
5
+ * 开头」(`checks/plugin-prefix.ts`,拍板 Q1=(A),**不需要任何清单**)⊕「不得裸定义宿主保留名」
6
+ * (`checks/reserved-classes.ts`,随包清单)。两者**同一个 checkId / 同一条腿**,报点按 `文件:行`
7
+ * 去重(前缀优先)——详见该腿的组装处注释。
3
8
  *
4
9
  * 对标壳 check 同款双轨(07 §六·载体双轨):eslint(12 项注册规则,全 WARN)管 ts/tsx;
5
10
  * css-hardcode / font-scale / spacing-grid / css-namespace 四条移植脚本管整工程(eslint 到不了 .css,
@@ -17,6 +22,7 @@ import { runCssHardcodeCheck } from "./checks/css-hardcode.js";
17
22
  import { runFontScaleCheck } from "./checks/font-scale.js";
18
23
  import { runSpacingGridCheck } from "./checks/spacing-grid.js";
19
24
  import { runReservedClassCheck } from "./checks/reserved-classes.js";
25
+ import { runPluginPrefixCheck } from "./checks/plugin-prefix.js";
20
26
  import {} from "./checks/scan.js";
21
27
  /** 示例用的门禁 id(打印知情绕行格式);伪 id 与 check 脚本 CHECK_IDS 同源 */
22
28
  const LEG_HINT_ID = "linkdesk/no-hardcoded-hex";
@@ -62,12 +68,32 @@ export async function runPluginLint(root, options = {}) {
62
68
  const css = runCssHardcodeCheck(absRoot);
63
69
  const font = runFontScaleCheck(absRoot);
64
70
  const spacing = runSpacingGridCheck(absRoot);
65
- const namespace = runReservedClassCheck(absRoot);
71
+ /**
72
+ * 命名空间腿 = **前缀判据 ⊕ 宿主保留名判据**(E6#109h-b①,详案 15 §二选项 (A):并入现腿、同一个
73
+ * `CHECK_IDS.cssNamespace`、同一条 `check-css-namespace` 腿,不是两条腿)。
74
+ *
75
+ * 🔴 为什么要**去重**而不是简单相加:前缀判据(「裸定义必须以 `<pluginId>-` 开头」)在「裸定义」
76
+ * 这一轴上**完全覆盖**保留名判据(插件不可能再裸定义 `.badge`——它必须以 `<pluginId>-` 开头),
77
+ * 两条都报就成了一处命中报两次。**前缀优先**:保留名判据只补它独有的一格——**拿不到前缀**时
78
+ * (`plugin.json` 缺失/损坏 ⇒ 前缀判据 fail-closed)仍能逐点报出「你占了一个宿主名字」。
79
+ * 保留名清单本身不删:前缀腿的报点里会带上「且这是宿主保留名」这句措辞(详见两个 check 的头注)。
80
+ */
81
+ const prefix = runPluginPrefixCheck(absRoot);
82
+ const reserved = runReservedClassCheck(absRoot);
83
+ const prefixKeys = new Set(prefix.violations.map((v) => `${v.file}:${v.line}`));
84
+ const namespace = [
85
+ ...prefix.violations,
86
+ ...reserved.filter((v) => !prefixKeys.has(`${v.file}:${v.line}`)),
87
+ ];
66
88
  const legs = [
67
89
  { id: "linkdesk/no-hardcoded-hex(css + rgb/hsl 腿)", label: "check-css-hardcode", violations: css },
68
90
  { id: "linkdesk/no-hardcoded-font-size", label: "check-font-scale", violations: font },
69
91
  { id: "linkdesk/no-nonstandard-spacing", label: "check-spacing-grid", violations: spacing },
70
- { id: "linkdesk/no-reserved-class-name(宿主保留名裸定义)", label: "check-css-namespace", violations: namespace },
92
+ {
93
+ id: "linkdesk/no-reserved-class-name(裸定义类名/关键帧必须带本仓 <pluginId>- 前缀;宿主保留名同 id)",
94
+ label: "check-css-namespace",
95
+ violations: namespace,
96
+ },
71
97
  ];
72
98
  const totalCheckViolations = css.length + font.length + spacing.length + namespace.length;
73
99
  return {
@@ -76,6 +102,8 @@ export async function runPluginLint(root, options = {}) {
76
102
  legs,
77
103
  totalCheckViolations,
78
104
  tsconfigUsed: tsconfig ? tsconfig : null,
105
+ pluginId: prefix.pluginId,
106
+ pluginIdNote: prefix.pluginIdNote,
79
107
  };
80
108
  }
81
109
  /** 打印报告(人机双通道的即时反馈环);返回进程退出码(真 error 才 1,WARN 永不 fail)。 */
@@ -106,6 +134,9 @@ export function renderPluginLintReport(report) {
106
134
  lines.push(` ${v.file}:${v.line} ${v.message}`);
107
135
  }
108
136
  }
137
+ // 命名空间腿的前缀来源(E6#109h-b①)——目录名兜底时必须让作者看见(不许静默)
138
+ if (report.pluginIdNote)
139
+ lines.push(`\nℹ 命名空间腿的前缀来源:${report.pluginIdNote}`);
109
140
  lines.push(`\n门禁 = 警告不是封锁(07 §六·三档):未处理偏离可修可绕——知情绕行写标准注释\n` +
110
141
  ` // eslint-disable-next-line ${LEG_HINT_ID} -- 理由 (行级)\n` +
111
142
  ` /* eslint-disable ${LEG_HINT_ID} -- 内容画布 */ (文件级:内容/画布整文件豁免)\n` +
@@ -1 +1 @@
1
- {"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/eslint/lint.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/eslint/lint.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linkdesk/plugin-sdk",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
4
4
  "description": "@linkdesk/plugin-sdk——LinkDesk 插件作者 SDK(对标 @types/vscode):window.linkdesk.* 类型 + 一键 build(.linkdesk-plugin) + dev 宿主 + plugin.json 验证 + eslint 门禁(E6#54d)。作者 npm i 后零壳源码依赖。",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -13,8 +13,8 @@
13
13
  },
14
14
  "pluginId": {
15
15
  "type": "string",
16
- "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$",
17
- "description": "🔴 Plugin identity — immutable once published (mirrors VS Code's publisher.name). Everything keys off it: install directory {userData}/plugins/<pluginId>/, distribution file name <pluginId>.linkdesk-plugin, marketplace dedup key, uninstall tombstone key, and update reconciliation. Strongly recommended to declare it explicitly: when omitted it falls back to the project directory name, but repository names and local directory names are free-form — rename the directory and the identity changes with it, and none of the five consequences (two install directories side by side / tombstone mismatch / duplicate marketplace entries / silently broken update chain / plugin data appearing lost) reports an error. Character set: letters, digits, `.`, `_`, `-`; the first character must be a letter or a digit."
16
+ "pattern": "^(?!ldk-)[A-Za-z0-9][A-Za-z0-9._-]*$",
17
+ "description": "🔴 Plugin identity — immutable once published (mirrors VS Code's publisher.name). Everything keys off it: install directory {userData}/plugins/<pluginId>/, distribution file name <pluginId>.linkdesk-plugin, marketplace dedup key, uninstall tombstone key, and update reconciliation. Strongly recommended to declare it explicitly: when omitted it falls back to the project directory name, but repository names and local directory names are free-form — rename the directory and the identity changes with it, and none of the five consequences (two install directories side by side / tombstone mismatch / duplicate marketplace entries / silently broken update chain / plugin data appearing lost) reports an error. Character set: letters, digits, `.`, `_`, `-`; the first character must be a letter or a digit. It must not start with `ldk-`: that whole namespace belongs to the host and its shared components, and since your CSS class prefix is derived from this id (`<pluginId>-your-class`), an `ldk-` id would land in host territory by construction and void the plugin-prefix rule (SDK check-css-namespace leg)."
18
18
  },
19
19
  "type": {
20
20
  "type": "string",
@@ -3,32 +3,7 @@
3
3
  "version": 1,
4
4
  "classes": {
5
5
  "shared": [],
6
- "host": [
7
- {
8
- "name": "input",
9
- "why": "🔴 插件在用的输入框工具类(settings / serial-monitor 实测渲染 className=\"input\")"
10
- },
11
- {
12
- "name": "titlebar",
13
- "why": "标题栏容器"
14
- },
15
- {
16
- "name": "divider",
17
- "why": "通用分隔线"
18
- },
19
- {
20
- "name": "about",
21
- "why": "关于页正文容器"
22
- },
23
- {
24
- "name": "rn",
25
- "why": "发行说明容器"
26
- },
27
- {
28
- "name": "vta",
29
- "why": "视图过渡动画容器"
30
- }
31
- ]
6
+ "host": []
32
7
  },
33
8
  "keyframes": [
34
9
  {