create-linkdesk-plugin 0.1.6 → 0.1.8
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.
- package/README.md +0 -1
- package/index.js +1 -1
- package/package.json +1 -1
- package/template/.github/workflows/ci.yml +1 -1
- package/template/scripts/ci-verify.mjs +13 -13
- package/template/src/index.tsx +2 -2
- package/template/vitest.config.ts +2 -2
- package/template/vitest.setup.ts +3 -3
package/README.md
CHANGED
package/index.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* {{date}} 注入 CHANGELOG.md 的初始段标题——格式必须是 `## v<版本>(YYYY-MM-DD)`,
|
|
14
14
|
* 那是市场「更改日志」页签切段的解析依据(见 docs/02-Electron架构/.../插件规范化层/02)。
|
|
15
15
|
*
|
|
16
|
-
* 🔴
|
|
16
|
+
* 🔴 建仓三语义——照抄 `cargo new`,**不是「一律 git init」**:
|
|
17
17
|
* ① 目标目录**已在某个 git 仓内** ⇒ 不 init(防嵌套仓——在容器目录里生成插件正是这种情形)
|
|
18
18
|
* ② 不在任何 git 仓内 ⇒ `git init -b main`
|
|
19
19
|
* ③ `--no-git` ⇒ 不建仓(逃生口,对标 `cargo new --vcs none`)
|
package/package.json
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* ci-verify
|
|
3
|
+
* ci-verify——插件仓自检门禁。挂 `npm run verify`,由 `.github/workflows/ci.yml` 调起。
|
|
4
4
|
*
|
|
5
5
|
* ── 为什么有它 ──
|
|
6
|
-
*
|
|
6
|
+
* 插件源码搬出壳仓之后,壳仓的 `npm run check` **够不着它们了**(那份门禁只覆盖壳仓)。
|
|
7
7
|
* 搬走的一共六类检查:编译图 / eslint(含 linkdesk/* 自定义规则)/ vitest / 体量 / i18n / 主题审计。
|
|
8
8
|
* 本脚本 + ci.yml + vitest 配置 = 给插件仓装回来的那一份,否则「独立」就是拿「质量真空」换的。
|
|
9
9
|
*
|
|
10
10
|
* ── 五段(每段独立判红;**没有对象也要说话**,不许静默绿)──
|
|
11
11
|
* ① lint 严格腿 —— `@linkdesk/plugin-sdk` 的 eslint 规则腿 + css/font-scale/spacing 三条扫描腿。
|
|
12
|
-
* 🔴 SDK 的 `npm run lint` 是 **WARN 级、永不 fail
|
|
12
|
+
* 🔴 SDK 的 `npm run lint` 是 **WARN 级、永不 fail**(三档制:警告不是封锁,
|
|
13
13
|
* 作者本地不被拦——那是刻意的)。CI 要的是**拦截**,所以本段把同一份报告按
|
|
14
14
|
* 「零偏离」判定。**这是「lint 会红」的唯一来源**,别把这段删了换成 `npm run lint`。
|
|
15
15
|
* ② 跨插件 import —— 壳仓 `linkdesk/no-cross-plugin-import` 的**仓外形态**:插件源码不得引用别的插件
|
|
16
16
|
* 仓库/包(相对路径越出本仓根,或裸包名形如 `linkdesk-plugin-*` / `@linkdesk/plugin-*`),
|
|
17
17
|
* package.json 也不得依赖别的插件包。共享代码只经 `@linkdesk/ui`,插件间通信走
|
|
18
18
|
* `window.linkdesk.*`。⚠️ 这条规则**不在** SDK preset 里(preset 只注册 8 条 linkdesk
|
|
19
|
-
* 规则、且全 WARN)——故必须自带(「补进 preset
|
|
19
|
+
* 规则、且全 WARN)——故必须自带(「补进 preset」目前仍是缺口)。
|
|
20
20
|
* ③ 字典完整性 —— `contributes.i18n` / `contributes.languages` 声明的字典:文件在、可解析、
|
|
21
21
|
* 每个值都是**非空字符串**。另打印「本仓 `t()` key 的自有字典覆盖度」为**黄灯**。
|
|
22
|
-
* ④ 声明自洽 ——
|
|
22
|
+
* ④ 声明自洽 —— 声明必须落在**真实存在的文件**上(壳侧读的是随包种子 /
|
|
23
23
|
* 冻结快照,插件仓该有「直接吃自己源码」的那条):`entry` / `icon` / `views[].render`
|
|
24
24
|
* 文件在;`contributes.themes` / `iconThemes` 的数据文件在且过各自的 schema;
|
|
25
25
|
* 主题 recipe 引用的 `linkdesk://<id>/…` 资产在(且 id 就是本插件);floatingPanel
|
|
26
26
|
* 三向自洽(viewId ↔ views[].id ↔ render)。
|
|
27
27
|
* ⑤ 目录条目形态 —— **发布产物** `marketplace.json` 里出现的图标字段(`icon` / `marketIcon`)必须是
|
|
28
|
-
* 绝对 URL + 来源标 `"url"
|
|
28
|
+
* 绝对 URL + 来源标 `"url"`。理由:目录条目是**未装用户**看图时的唯一数据源,
|
|
29
29
|
* 而包内相对路径(`resources/icon.svg`)在未装态恒 404(`linkdesk://` 只在本地已装的
|
|
30
|
-
* 插件根里找文件)。`publish`
|
|
30
|
+
* 插件根里找文件)。`publish` 会自动 URL 化;本段是那条纪律的机械兜底——
|
|
31
31
|
* 它看不见「谁是图标栏插件」(不看插件类型,只看字段形态,硬约束 10 零 ID 知识)。
|
|
32
32
|
*
|
|
33
33
|
* ── 为什么 ③ 的覆盖度只能黄灯(不是漏做)──
|
|
@@ -70,7 +70,7 @@ const isSourceFile = (p) =>
|
|
|
70
70
|
|
|
71
71
|
const sourceFiles = listFiles(join(ROOT, "src")).filter(isSourceFile);
|
|
72
72
|
|
|
73
|
-
line("插件仓自检(ci-verify
|
|
73
|
+
line("插件仓自检(ci-verify)");
|
|
74
74
|
line("────────────────────────────────────────────────────────────");
|
|
75
75
|
|
|
76
76
|
// ── 读 manifest(JSONC——脚手架允许注释,与 SDK validatePluginJson 同一个解析器)──
|
|
@@ -136,7 +136,7 @@ const strictEslintRows = allRows.filter((r) => !RULE_NOT_FOUND_RE.test(r.message
|
|
|
136
136
|
/** 判红的三样:真 eslint 偏离 + css 硬编码腿(硬约束 1 的 .css 半边,eslint 到不了 .css)+ 见下 ②③④⑤ */
|
|
137
137
|
const cssLegViolations = legCount("check-css-hardcode");
|
|
138
138
|
const strictLintViolations = strictEslintRows.length + cssLegViolations;
|
|
139
|
-
/** 只报告不拦的两条腿:字号度量与 4px
|
|
139
|
+
/** 只报告不拦的两条腿:字号度量与 4px 节奏——属「审美校准」,存量偏离多且修它们要动插件源码 */
|
|
140
140
|
const advisoryLintViolations = legCount("check-font-scale") + legCount("check-spacing-grid");
|
|
141
141
|
|
|
142
142
|
if (lintNoObject) {
|
|
@@ -163,7 +163,7 @@ if (advisoryLintViolations > 0) {
|
|
|
163
163
|
line(
|
|
164
164
|
` ⚠ 附加腿(**报告不拦**):font-scale ${legCount("check-font-scale")} 处 / ` +
|
|
165
165
|
`spacing-grid ${legCount("check-spacing-grid")} 处——字号度量与 4px 节奏属审美校准档` +
|
|
166
|
-
|
|
166
|
+
`,逐条见上方报告;确属有意的用标准 disable 注释写明理由。`,
|
|
167
167
|
);
|
|
168
168
|
}
|
|
169
169
|
|
|
@@ -432,7 +432,7 @@ if (!manifest) {
|
|
|
432
432
|
}
|
|
433
433
|
if (themeAssetRefs.size > 0) ok.push(`${themeAssetRefs.size} 处 linkdesk:// 资产引用`);
|
|
434
434
|
|
|
435
|
-
/* ⑤
|
|
435
|
+
/* ⑤ 目录条目的图标字段必须是**未装态可解析**的形态(绝对 URL)。
|
|
436
436
|
*
|
|
437
437
|
* 为什么这条能是纯字段断言、不需要知道「谁是图标栏插件」:无论哪种插件,**未装用户**看市场行时
|
|
438
438
|
* 目录条目是唯一数据源,而包内相对路径(`resources/icon.svg`)在未装态恒 404——「目录里存相对路径」
|
|
@@ -469,7 +469,7 @@ if (!manifest) {
|
|
|
469
469
|
} else {
|
|
470
470
|
catProblems.push(
|
|
471
471
|
`${key} = ${JSON.stringify(v)} 是**包内相对路径**——目录条目是未装用户的唯一图源,` +
|
|
472
|
-
`相对路径在未装态恒 404。跑 \`npm run publish\` 让 SDK 自动转绝对 URL
|
|
472
|
+
`相对路径在未装态恒 404。跑 \`npm run publish\` 让 SDK 自动转绝对 URL。`,
|
|
473
473
|
);
|
|
474
474
|
}
|
|
475
475
|
}
|
|
@@ -520,7 +520,7 @@ if (!manifest) {
|
|
|
520
520
|
line(`✅ ④ 声明自洽:${ok.length > 0 ? ok.join("、") + "——全部兑现。" : "本仓无声明对象(无 entry/views/themes)。"}`);
|
|
521
521
|
}
|
|
522
522
|
|
|
523
|
-
// pluginId 缺声明——schema
|
|
523
|
+
// pluginId 缺声明——schema 兜底打黄灯,这里同款提示
|
|
524
524
|
if (!manifest.pluginId) {
|
|
525
525
|
line(
|
|
526
526
|
` ⚠ plugin.json 未显式声明 pluginId——身份现按目录名 "${pluginId}" 兜底。发布后身份不可变,` +
|
package/template/src/index.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* {{displayName}}——LinkDesk 插件主视图(由 create-linkdesk-plugin 生成)。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 视图插件契约(作者文档 01-plugin-api-contract.md):壳以 { isActive, tabId?, sourceId? }
|
|
5
5
|
* 渲染本文件 default 导出的组件:
|
|
6
6
|
* - isActive 本标签当前是否聚焦。keep-alive 下非聚焦标签仍在渲染,isActive 只用于
|
|
7
7
|
* gate「聚焦才跑」的副作用(如自动保存),切勿用它整块 blank 掉内容。
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - sourceId 上下文数据(文件路径 / 数据源等),编辑器类插件用它定位内容。
|
|
10
10
|
*
|
|
11
11
|
* 样式:LinkDesk 主题色一律走 CSS 变量 var(--xxx)(见 index.css 示例),禁硬编码 hex。
|
|
12
|
-
* 文案:用 t() 读——key 就是中文原文,英文译文放 i18n/en.json
|
|
12
|
+
* 文案:用 t() 读——key 就是中文原文,英文译文放 i18n/en.json(见作者文档 05-ui-conventions.md)。
|
|
13
13
|
* 壳已 external react/react-dom/react-i18next/i18next——构建不会打进包,插件工程无需 npm i 它们。
|
|
14
14
|
*/
|
|
15
15
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineConfig } from "vitest/config";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* 插件工程测试环境。
|
|
5
5
|
*
|
|
6
6
|
* 🔴 这份配置**逐项对齐壳仓 `vitest.config.ts`**:`globals` / `environment: "jsdom"` /
|
|
7
7
|
* `setupFiles` 三条是**静默生效**的配置——缺了会报错(那还算好),配错了则是「本地绿、CI 红」,
|
|
@@ -16,7 +16,7 @@ import { defineConfig } from "vitest/config";
|
|
|
16
16
|
* `@linkdesk/ui` 解析到**同仓源码**,CSS 由 Vite 顺手处理;插件仓解析到**已发布的 dist**,
|
|
17
17
|
* 而 `dist/index.js` 里有 `import "./index.css"` —— Node 的外部依赖加载器读不了 `.css`,
|
|
18
18
|
* 于是凡经 `@linkdesk/ui` 的测试全部倒在
|
|
19
|
-
* `TypeError: Unknown file extension ".css"
|
|
19
|
+
* `TypeError: Unknown file extension ".css"`(实测:marketplace 6 个文件 / 12 例)。
|
|
20
20
|
* 把 `@linkdesk/ui` 交给 Vite 内联处理后即恢复。**别删这一条**——删了只会在有 UI 组件的
|
|
21
21
|
* 仓里以「莫名其妙的环境错」重现。
|
|
22
22
|
*
|
package/template/vitest.setup.ts
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* 测试跑在 Node.js/jsdom,没有 Electron preload 注入的 window.linkdesk。
|
|
4
4
|
* 迁移到 linkdesk.* API 后,插件代码直接依赖它——测试环境需提供最小 mock。
|
|
5
5
|
*
|
|
6
|
-
* 🔴
|
|
6
|
+
* 🔴 **本文件是壳仓 `vitest.setup.ts` 的逐字副本**(除本头注五条)。
|
|
7
7
|
* 它不是「配置」,是插件测试的**运行时地基**——下半部的六个命名空间与 `__ldkConfigStore`
|
|
8
8
|
* 少了任何一个,凡碰 `window.linkdesk` 的测试都会报错、或更糟:静默走错分支。
|
|
9
9
|
* 改壳仓那份时把这里一起改(两处同源)。「由 @linkdesk/plugin-sdk 提供共享版本、
|
|
10
|
-
* 本文件改成一行 re-export
|
|
10
|
+
* 本文件改成一行 re-export」是可预见的收敛方向——那时这五条注记一并删掉。
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
// path 纯函数——直接实现,不走 IPC
|
|
@@ -31,7 +31,7 @@ const pathMock = {
|
|
|
31
31
|
},
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
//
|
|
34
|
+
// 测试全局窄类型 cast——替代 (globalThis as any)(__ldkConfigStore 由本文件声明、测试文件消费)
|
|
35
35
|
type TestGlobal = { window?: Window; __ldkConfigStore?: Map<string, unknown> };
|
|
36
36
|
const _g = globalThis as TestGlobal;
|
|
37
37
|
|