juice-email-cli 2.1.14 → 2.1.15

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/context-menu.js +71 -37
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juice-email-cli",
3
- "version": "2.1.14",
3
+ "version": "2.1.15",
4
4
  "description": "CLI tool to generate email-client-compatible HTML with juice (CSS inlining) + Mustache templating + minification",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -10,13 +10,16 @@
10
10
  * - 不依赖 CommandStore(HKCU CommandStore 在某些 Windows 版本下不被正确解析)
11
11
  * - ExtendedSubCommandsKey 指向 Classes 根下的相对路径,子命令内联存储
12
12
  *
13
- * 菜单结构(所有文件类型统一):
14
- * .html / .htm / .yaml / .yml
13
+ * 菜单结构(按文件类型区分):
14
+ * .html / .htm:
15
15
  * 📧 用 juice 生成邮件 HTML
16
16
  * ├── 📄 作为模板,生成邮件 HTML → juice -f(后台执行)
17
17
  * ├── 🧩 作为片段,拼接邮件 HTML → juice -s(交互选择模板)
18
- * ├── ⚙️ 作为配置,拼接邮件 HTML → juice -c(交互选择品牌/模板/片段)
19
18
  * └── 📂 打开 PowerShell (可选)
19
+ *
20
+ * .yaml / .yml:
21
+ * 📧 用 juice 生成邮件 HTML
22
+ * └── ⚙️ 作为配置,拼接邮件 HTML → juice -c(交互选择品牌/模板/片段)
20
23
  */
21
24
 
22
25
  const { spawnSync } = require('child_process');
@@ -95,9 +98,9 @@ const SUBCMDS = {
95
98
 
96
99
  const PARENT_KEY_NAME = 'JuiceEmail';
97
100
 
98
- // ExtendedSubCommandsKey 指向此路径(相对于 HKCU\Software\Classes)
99
- // 解析结果:HKCU\Software\Classes\JuiceEmail.SubCommands
100
- const SUB_CMDS_CONTAINER = 'JuiceEmail.SubCommands';
101
+ // ExtendedSubCommandsKey 指向的容器路径(相对于 HKCU\Software\Classes)
102
+ const SUB_CMDS_CONTAINER_HTML = 'JuiceEmail.SubCommands';
103
+ const SUB_CMDS_CONTAINER_YAML = 'JuiceEmail.SubCommands.Yaml';
101
104
 
102
105
  // ─── 旧版残留清理 ─────────────────────────────────────────────────────────────
103
106
 
@@ -178,28 +181,35 @@ function resolvePwsh() {
178
181
  return null;
179
182
  }
180
183
 
181
- // ─── 注册子命令到共享容器 ────────────────────────────────────────────────────
182
-
183
- function registerSubCommands(containerPath, nodePath, scriptPath, iconPath, pwshPath) {
184
- // generate(非交互,无需终端)
185
- const genKey = `${containerPath}\\shell\\${SUBCMDS.generate}`;
186
- regAdd(genKey, 'MUIVerb', 'REG_SZ', '📄 作为模板,生成邮件 HTML');
187
- regAdd(genKey, 'Icon', 'REG_SZ', iconPath);
188
- regAdd(`${genKey}\\command`, '', 'REG_SZ', `"${nodePath}" "${scriptPath}" -f %1`);
184
+ // ─── 注册子命令到容器 ────────────────────────────────────────────────────────
189
185
 
190
- // snippet(交互,需要终端)
191
- const snipKey = `${containerPath}\\shell\\${SUBCMDS.snippet}`;
192
- regAdd(snipKey, 'MUIVerb', 'REG_SZ', '🧩 作为片段,拼接邮件 HTML');
193
- regAdd(snipKey, 'Icon', 'REG_SZ', iconPath);
194
- regAdd(`${snipKey}\\command`, '', 'REG_SZ', wrapInteractive(nodePath, scriptPath, '-s %1'));
195
-
196
- // config(交互,需要终端)
197
- const cfgKey = `${containerPath}\\shell\\${SUBCMDS.config}`;
198
- regAdd(cfgKey, 'MUIVerb', 'REG_SZ', '⚙️ 作为配置,拼接邮件 HTML');
199
- regAdd(cfgKey, 'Icon', 'REG_SZ', iconPath);
200
- regAdd(`${cfgKey}\\command`, '', 'REG_SZ', wrapInteractive(nodePath, scriptPath, '-c %1'));
186
+ /**
187
+ * 向指定容器注册子命令
188
+ * @param {string} containerPath - 容器完整注册表路径
189
+ * @param {'html'|'yaml'} kind - 子命令集合类型
190
+ */
191
+ function registerSubCommands(containerPath, kind, nodePath, scriptPath, iconPath, pwshPath) {
192
+ if (kind === 'html') {
193
+ // HTML:作为模板生成
194
+ const genKey = `${containerPath}\\shell\\${SUBCMDS.generate}`;
195
+ regAdd(genKey, 'MUIVerb', 'REG_SZ', '📄 作为模板,生成邮件 HTML');
196
+ regAdd(genKey, 'Icon', 'REG_SZ', iconPath);
197
+ regAdd(`${genKey}\\command`, '', 'REG_SZ', `"${nodePath}" "${scriptPath}" -f %1`);
198
+
199
+ // HTML:作为片段拼接
200
+ const snipKey = `${containerPath}\\shell\\${SUBCMDS.snippet}`;
201
+ regAdd(snipKey, 'MUIVerb', 'REG_SZ', '🧩 作为片段,拼接邮件 HTML');
202
+ regAdd(snipKey, 'Icon', 'REG_SZ', iconPath);
203
+ regAdd(`${snipKey}\\command`, '', 'REG_SZ', wrapInteractive(nodePath, scriptPath, '-s %1'));
204
+ } else {
205
+ // YAML:作为配置拼接
206
+ const cfgKey = `${containerPath}\\shell\\${SUBCMDS.config}`;
207
+ regAdd(cfgKey, 'MUIVerb', 'REG_SZ', '⚙️ 作为配置,拼接邮件 HTML');
208
+ regAdd(cfgKey, 'Icon', 'REG_SZ', iconPath);
209
+ regAdd(`${cfgKey}\\command`, '', 'REG_SZ', wrapInteractive(nodePath, scriptPath, '-c %1'));
210
+ }
201
211
 
202
- // pwsh(可选)
212
+ // pwsh — 始终显示(可选)
203
213
  if (pwshPath) {
204
214
  const pwshKey = `${containerPath}\\shell\\${SUBCMDS.pwsh}`;
205
215
  regAdd(pwshKey, 'MUIVerb', 'REG_SZ', '📂 打开 PowerShell');
@@ -230,17 +240,32 @@ async function registerContextMenu() {
230
240
 
231
241
  let ok = true;
232
242
 
233
- // 子命令注册一次到共享容器(所有文件类型共用)
234
- const containerPath = `${HKCU_SHELL}\\${SUB_CMDS_CONTAINER}`;
235
- registerSubCommands(containerPath, nodePath, scriptPath, iconPath, pwshPath);
243
+ // 先删除旧容器再重建,避免注册残留旧子命令(如旧版 HTML 容器的 WithConfig)
244
+ regDelete(`${HKCU_SHELL}\\${SUB_CMDS_CONTAINER_HTML}`);
245
+ regDelete(`${HKCU_SHELL}\\${SUB_CMDS_CONTAINER_YAML}`);
236
246
 
237
- // 为每种文件类型注册父菜单,通过 ExtendedSubCommandsKey 引用共享容器
238
- const allRoots = [...HTML_ROOTS, ...YAML_ROOTS];
239
- for (const root of allRoots) {
247
+ // HTML 容器:generate + snippet + pwsh
248
+ const htmlContainer = `${HKCU_SHELL}\\${SUB_CMDS_CONTAINER_HTML}`;
249
+ registerSubCommands(htmlContainer, 'html', nodePath, scriptPath, iconPath, pwshPath);
250
+
251
+ // YAML 容器:config + pwsh
252
+ const yamlContainer = `${HKCU_SHELL}\\${SUB_CMDS_CONTAINER_YAML}`;
253
+ registerSubCommands(yamlContainer, 'yaml', nodePath, scriptPath, iconPath, pwshPath);
254
+
255
+ // .html / .htm → 引用 HTML 容器
256
+ for (const root of HTML_ROOTS) {
240
257
  const parentKey = `${root}\\${PARENT_KEY_NAME}`;
241
258
  ok = regAdd(parentKey, 'MUIVerb', 'REG_SZ', '📧 用 juice 生成邮件 HTML') && ok;
242
259
  regAdd(parentKey, 'Icon', 'REG_SZ', iconPath);
243
- regAdd(parentKey, 'ExtendedSubCommandsKey', 'REG_SZ', SUB_CMDS_CONTAINER);
260
+ regAdd(parentKey, 'ExtendedSubCommandsKey', 'REG_SZ', SUB_CMDS_CONTAINER_HTML);
261
+ }
262
+
263
+ // .yaml / .yml → 引用 YAML 容器
264
+ for (const root of YAML_ROOTS) {
265
+ const parentKey = `${root}\\${PARENT_KEY_NAME}`;
266
+ ok = regAdd(parentKey, 'MUIVerb', 'REG_SZ', '📧 用 juice 生成邮件 HTML') && ok;
267
+ regAdd(parentKey, 'Icon', 'REG_SZ', iconPath);
268
+ regAdd(parentKey, 'ExtendedSubCommandsKey', 'REG_SZ', SUB_CMDS_CONTAINER_YAML);
244
269
  }
245
270
 
246
271
  if (!ok) {
@@ -250,12 +275,17 @@ async function registerContextMenu() {
250
275
  console.log(
251
276
  '\n' +
252
277
  chalk.green(' ✔ 右键菜单注册完成!') + '\n\n' +
253
- ` ${chalk.bold('.html / .htm / .yaml / .yml')} 文件右键:\n` +
278
+ ` ${chalk.bold('.html / .htm')} 文件右键:\n` +
254
279
  ` ${chalk.bold('📧 用 juice 生成邮件 HTML')}\n` +
255
280
  ` ├── 📄 作为模板,生成邮件 HTML → juice -f(后台执行)\n` +
256
281
  ` ├── 🧩 作为片段,拼接邮件 HTML → juice -s(交互选择模板)\n` +
257
- ` ├── ⚙️ 作为配置,拼接邮件 HTML → juice -c(交互选择品牌/模板/片段)\n` +
258
282
  (pwshPath ? ` └── 📂 打开 PowerShell\n` : '') +
283
+ `\n ${chalk.bold('.yaml / .yml')} 文件右键:\n` +
284
+ ` ${chalk.bold('📧 用 juice 生成邮件 HTML')}\n` +
285
+ (pwshPath
286
+ ? ` ├── ⚙️ 作为配置,拼接邮件 HTML → juice -c(交互选择品牌/模板/片段)\n` +
287
+ ` └── 📂 打开 PowerShell\n`
288
+ : ` └── ⚙️ 作为配置,拼接邮件 HTML → juice -c(交互选择品牌/模板/片段)\n`) +
259
289
  '\n' +
260
290
  chalk.gray(' 注意:如菜单未出现,请重启文件资源管理器(explorer.exe)。\n')
261
291
  );
@@ -279,8 +309,12 @@ async function unregisterContextMenu() {
279
309
  if (regDelete(`${root}\\${PARENT_KEY_NAME}`)) removed++;
280
310
  }
281
311
 
282
- // 清理共享子命令容器
283
- if (regDelete(`${HKCU_SHELL}\\${SUB_CMDS_CONTAINER}`)) removed++;
312
+ // 清理两个子命令容器
313
+ if (regDelete(`${HKCU_SHELL}\\${SUB_CMDS_CONTAINER_HTML}`)) removed++;
314
+ if (regDelete(`${HKCU_SHELL}\\${SUB_CMDS_CONTAINER_YAML}`)) removed++;
315
+
316
+ // 清理旧版共享容器(v2.1.14 之前只有一个容器)
317
+ regDelete(`${HKCU_SHELL}\\JuiceEmail.SubCommands`);
284
318
 
285
319
  // 清理旧版残留(HKLM 父菜单 + CommandStore)
286
320
  cleanLegacyHklmParents();