electron-forge-maker-innosetup 0.3.1 → 1.0.0

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/dist/generator.js CHANGED
@@ -36,128 +36,193 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.InnoScriptGenerator = void 0;
37
37
  const path = __importStar(require("path"));
38
38
  const fs = __importStar(require("fs"));
39
+ const logger_1 = require("./logger");
39
40
  /**
40
- * 生成 Innosetup 脚本文件内容
41
+ * Inno Setup 脚本生成器
42
+ *
43
+ * 将配置对象转换为 Inno Setup 脚本文件(.iss)
41
44
  */
42
45
  class InnoScriptGenerator {
43
46
  /**
44
- * 生成脚本内容
47
+ * 生成完整的 ISS 脚本内容
48
+ *
49
+ * @param config - Inno Setup 配置对象
50
+ * @returns 完整的 ISS 脚本字符串(包含 UTF-8 BOM)
45
51
  */
46
52
  generate(config) {
53
+ (0, logger_1.logGenerator)("正在生成 ISS 脚本");
47
54
  const sections = [];
48
- // 生成 #define 指令
55
+ // 生成 #define 预处理器指令
49
56
  if (config.Defines && Object.keys(config.Defines).length > 0) {
50
- sections.push(this.generateDefinesSection(config.Defines));
57
+ sections.push(this.generateDefines(config.Defines));
51
58
  }
52
- // 生成 [Setup] 部分
53
- if (config.Setup) {
54
- sections.push(this.generateSetupSection(config.Setup));
59
+ // 按正确顺序生成各个节
60
+ sections.push(this.generateSetup(config.Setup));
61
+ if (config.Languages?.length) {
62
+ sections.push(this.generateSection("Languages", config.Languages, this.generateLanguage));
55
63
  }
56
- // 生成 [Languages] 部分
57
- if (config.Languages && config.Languages.length > 0) {
58
- sections.push(this.generateLanguagesSection(config.Languages));
64
+ if (config.Types?.length) {
65
+ sections.push(this.generateSection("Types", config.Types, this.generateType));
59
66
  }
60
- // 生成 [Types] 部分
61
- if (config.Types && config.Types.length > 0) {
62
- sections.push(this.generateTypesSection(config.Types));
67
+ if (config.Components?.length) {
68
+ sections.push(this.generateSection("Components", config.Components, this.generateComponent));
63
69
  }
64
- // 生成 [Components] 部分
65
- if (config.Components && config.Components.length > 0) {
66
- sections.push(this.generateComponentsSection(config.Components));
70
+ if (config.Tasks?.length) {
71
+ sections.push(this.generateSection("Tasks", config.Tasks, this.generateTask));
67
72
  }
68
- // 生成 [Tasks] 部分
69
- if (config.Tasks && config.Tasks.length > 0) {
70
- sections.push(this.generateTasksSection(config.Tasks));
73
+ if (config.Files?.length) {
74
+ sections.push(this.generateSection("Files", config.Files, this.generateFile));
71
75
  }
72
- // 生成 [Files] 部分
73
- if (config.Files && config.Files.length > 0) {
74
- sections.push(this.generateFilesSection(config.Files));
76
+ if (config.Dirs?.length) {
77
+ sections.push(this.generateSection("Dirs", config.Dirs, this.generateDir));
75
78
  }
76
- // 生成 [Dirs] 部分
77
- if (config.Dirs && config.Dirs.length > 0) {
78
- sections.push(this.generateDirsSection(config.Dirs));
79
+ if (config.Icons?.length) {
80
+ sections.push(this.generateSection("Icons", config.Icons, this.generateIcon));
79
81
  }
80
- // 生成 [Icons] 部分
81
- if (config.Icons && config.Icons.length > 0) {
82
- sections.push(this.generateIconsSection(config.Icons));
82
+ if (config.INI?.length) {
83
+ sections.push(this.generateSection("INI", config.INI, this.generateINIItem));
83
84
  }
84
- // 生成 [INI] 部分
85
- if (config.INI && config.INI.length > 0) {
86
- sections.push(this.generateINISection(config.INI));
85
+ if (config.InstallDelete?.length) {
86
+ sections.push(this.generateSection("InstallDelete", config.InstallDelete, this.generateDeleteItem));
87
87
  }
88
- // 生成 [InstallDelete] 部分
89
- if (config.InstallDelete && config.InstallDelete.length > 0) {
90
- sections.push(this.generateInstallDeleteSection(config.InstallDelete));
88
+ if (config.UninstallDelete?.length) {
89
+ sections.push(this.generateSection("UninstallDelete", config.UninstallDelete, this.generateDeleteItem));
91
90
  }
92
- // 生成 [UninstallDelete] 部分
93
- if (config.UninstallDelete && config.UninstallDelete.length > 0) {
94
- sections.push(this.generateUninstallDeleteSection(config.UninstallDelete));
91
+ if (config.Registry?.length) {
92
+ sections.push(this.generateSection("Registry", config.Registry, this.generateRegistryItem));
95
93
  }
96
- // 生成 [Registry] 部分
97
- if (config.Registry && config.Registry.length > 0) {
98
- sections.push(this.generateRegistrySection(config.Registry));
94
+ if (config.Run?.length) {
95
+ sections.push(this.generateSection("Run", config.Run, this.generateRunItem));
99
96
  }
100
- // 生成 [Run] 部分
101
- if (config.Run && config.Run.length > 0) {
102
- sections.push(this.generateRunSection(config.Run));
97
+ if (config.UninstallRun?.length) {
98
+ sections.push(this.generateSection("UninstallRun", config.UninstallRun, this.generateUninstallRunItem));
103
99
  }
104
- // 生成 [UninstallRun] 部分
105
- if (config.UninstallRun && config.UninstallRun.length > 0) {
106
- sections.push(this.generateUninstallRunSection(config.UninstallRun));
107
- }
108
- // 生成 [Messages] 部分
109
100
  if (config.Messages && Object.keys(config.Messages).length > 0) {
110
- sections.push(this.generateMessagesSection(config.Messages));
101
+ sections.push(this.generateMessagesSection("Messages", config.Messages));
111
102
  }
112
- // 生成 [CustomMessages] 部分
113
- if (config.CustomMessages &&
114
- Object.keys(config.CustomMessages).length > 0) {
115
- sections.push(this.generateCustomMessagesSection(config.CustomMessages));
103
+ if (config.CustomMessages && Object.keys(config.CustomMessages).length > 0) {
104
+ sections.push(this.generateMessagesSection("CustomMessages", config.CustomMessages));
116
105
  }
117
- // 生成 [Code] 部分
118
106
  if (config.Code) {
119
107
  sections.push(this.generateCodeSection(config.Code));
120
108
  }
121
- // 添加 UTF-8 BOM 标记,确保 Inno Setup 正确识别中文
109
+ // 添加 UTF-8 BOM 以正确支持中文字符
122
110
  return "\uFEFF" + sections.join("\n\n");
123
111
  }
124
112
  /**
125
- * 生成 #define 指令部分
113
+ * 将脚本内容保存到文件
114
+ *
115
+ * @param scriptContent - 脚本内容
116
+ * @param filePath - 目标文件路径
117
+ */
118
+ saveToFile(scriptContent, filePath) {
119
+ (0, logger_1.logGenerator)("保存脚本到: %s", filePath);
120
+ const dir = path.dirname(filePath);
121
+ if (!fs.existsSync(dir)) {
122
+ fs.mkdirSync(dir, { recursive: true });
123
+ }
124
+ // 使用 UTF-8 编码写入(BOM 已包含在 scriptContent 中)
125
+ fs.writeFileSync(filePath, scriptContent, "utf-8");
126
+ }
127
+ // ============================================================================
128
+ // 辅助方法
129
+ // ============================================================================
130
+ /**
131
+ * 转义字符串值中的引号
132
+ * Inno Setup 中引号需要双写来转义
133
+ *
134
+ * @param value - 原始字符串
135
+ * @returns 转义后的字符串
136
+ */
137
+ escapeValue(value) {
138
+ return value.replace(/"/g, '""');
139
+ }
140
+ /**
141
+ * 将参数格式化为 Name: "Value" 形式
142
+ *
143
+ * @param name - 参数名
144
+ * @param value - 参数值
145
+ * @returns 格式化后的字符串
146
+ */
147
+ formatParam(name, value) {
148
+ return `${name}: "${this.escapeValue(value)}"`;
149
+ }
150
+ /**
151
+ * 将参数格式化为 Name: Value 形式(不带引号)
152
+ * 用于 flags、types 等不需要引号的参数
153
+ *
154
+ * @param name - 参数名
155
+ * @param value - 参数值
156
+ * @returns 格式化后的字符串
157
+ */
158
+ formatParamRaw(name, value) {
159
+ return `${name}: ${value}`;
160
+ }
161
+ /**
162
+ * 生成包含多个条目的节
163
+ *
164
+ * @param name - 节名称
165
+ * @param items - 条目数组
166
+ * @param generator - 单个条目的生成函数
167
+ * @returns 完整的节内容
168
+ */
169
+ generateSection(name, items, generator) {
170
+ const lines = [`[${name}]`, ...items.map((item) => generator.call(this, item))];
171
+ return lines.join("\n");
172
+ }
173
+ // ============================================================================
174
+ // 节生成器
175
+ // ============================================================================
176
+ /**
177
+ * 生成 #define 预处理器指令
178
+ *
179
+ * @param defines - 预处理器常量定义
180
+ * @returns 完整的指令内容
126
181
  */
127
- generateDefinesSection(defines) {
182
+ generateDefines(defines) {
128
183
  const lines = [
129
- "; Script generated by the Inno Setup Script Wizard.",
130
- "; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!",
184
+ "; electron-forge-maker-innosetup 生成的脚本",
185
+ "; 请参阅 Inno Setup 文档了解如何创建脚本文件!",
131
186
  "",
132
187
  ];
133
188
  for (const [key, value] of Object.entries(defines)) {
134
189
  if (value !== undefined && value !== null) {
135
190
  const strValue = String(value);
136
- // 检查是否是表达式(包含函数调用、引用或拼接)
137
- const isExpression = strValue.includes("(") ||
138
- strValue.includes("+") ||
139
- (strValue.match(/^\w+$/) && !strValue.match(/^\d+$/));
191
+ // 检查值是否为表达式(包含函数调用或引用)
192
+ const isExpression = strValue.includes("(") || strValue.includes("+");
140
193
  if (typeof value === "string" && !isExpression) {
141
- // 普通字符串,添加引号
142
- lines.push(`#define ${key} "${value}"`);
143
- }
144
- else if (typeof value === "string" && isExpression) {
145
- // 表达式,不添加引号
146
- lines.push(`#define ${key} ${value}`);
194
+ lines.push(`#define ${key} "${this.escapeValue(strValue)}"`);
147
195
  }
148
196
  else {
149
- // 数字等其他类型
150
- lines.push(`#define ${key} ${value}`);
197
+ lines.push(`#define ${key} ${strValue}`);
151
198
  }
152
199
  }
153
200
  }
154
201
  return lines.join("\n");
155
202
  }
156
203
  /**
157
- * 生成 Setup 部分
204
+ * 生成 [Setup]
205
+ *
206
+ * @param setup - Setup 节配置
207
+ * @returns 完整的 Setup 节内容
158
208
  */
159
- generateSetupSection(setup) {
209
+ generateSetup(setup) {
160
210
  const lines = ["[Setup]"];
211
+ // 需要规范化路径分隔符的字段
212
+ const pathFields = new Set([
213
+ "DefaultDirName",
214
+ "DefaultGroupName",
215
+ "OutputDir",
216
+ "SetupIconFile",
217
+ "LicenseFile",
218
+ "InfoBeforeFile",
219
+ "InfoAfterFile",
220
+ "WizardImageFile",
221
+ "WizardSmallImageFile",
222
+ "UninstallDisplayIcon",
223
+ "UninstallFilesDir",
224
+ "AppReadmeFile",
225
+ ]);
161
226
  for (const [key, value] of Object.entries(setup)) {
162
227
  if (value !== undefined && value !== null) {
163
228
  if (typeof value === "boolean") {
@@ -167,396 +232,359 @@ class InnoScriptGenerator {
167
232
  lines.push(`${key}=${value}`);
168
233
  }
169
234
  else {
170
- // 检查值是否包含 {#...} 引用
171
- const stringValue = String(value);
172
- if (stringValue.includes("{#")) {
173
- // 如果包含常量引用,不添加额外引号
174
- lines.push(`${key}=${stringValue}`);
175
- }
176
- else {
177
- lines.push(`${key}=${stringValue}`);
178
- }
235
+ // 规范化路径分隔符
236
+ const normalizedValue = pathFields.has(key)
237
+ ? value.replace(/\//g, "\\")
238
+ : value;
239
+ lines.push(`${key}=${normalizedValue}`);
179
240
  }
180
241
  }
181
242
  }
182
243
  return lines.join("\n");
183
244
  }
184
245
  /**
185
- * 生成 Languages 部分
246
+ * 生成 Language 条目
247
+ *
248
+ * @param lang - 语言配置
249
+ * @returns 格式化的语言条目
186
250
  */
187
- generateLanguagesSection(languages) {
188
- const lines = ["[Languages]"];
189
- for (const lang of languages) {
190
- const parts = [`Name: "${lang.Name}"`];
191
- parts.push(`MessagesFile: "${lang.MessagesFile}"`);
192
- if (lang.LicenseFile)
193
- parts.push(`LicenseFile: "${lang.LicenseFile}"`);
194
- if (lang.InfoBeforeFile)
195
- parts.push(`InfoBeforeFile: "${lang.InfoBeforeFile}"`);
196
- if (lang.InfoAfterFile)
197
- parts.push(`InfoAfterFile: "${lang.InfoAfterFile}"`);
198
- lines.push(parts.join("; "));
199
- }
200
- return lines.join("\n");
201
- }
202
- /**
203
- * 生成 Types 部分
204
- */
205
- generateTypesSection(types) {
206
- const lines = ["[Types]"];
207
- for (const type of types) {
208
- const parts = [`Name: "${type.Name}"`];
209
- parts.push(`Description: "${type.Description}"`);
210
- if (type.Flags)
211
- parts.push(`Flags: ${type.Flags}`);
212
- lines.push(parts.join("; "));
213
- }
214
- return lines.join("\n");
251
+ generateLanguage(lang) {
252
+ const parts = [
253
+ this.formatParam("Name", lang.Name),
254
+ this.formatParam("MessagesFile", lang.MessagesFile),
255
+ ];
256
+ if (lang.LicenseFile)
257
+ parts.push(this.formatParam("LicenseFile", lang.LicenseFile));
258
+ if (lang.InfoBeforeFile)
259
+ parts.push(this.formatParam("InfoBeforeFile", lang.InfoBeforeFile));
260
+ if (lang.InfoAfterFile)
261
+ parts.push(this.formatParam("InfoAfterFile", lang.InfoAfterFile));
262
+ return parts.join("; ");
215
263
  }
216
264
  /**
217
- * 生成 Components 部分
265
+ * 生成 Task 条目
266
+ *
267
+ * @param task - 任务配置
268
+ * @returns 格式化的任务条目
218
269
  */
219
- generateComponentsSection(components) {
220
- const lines = ["[Components]"];
221
- for (const comp of components) {
222
- const parts = [`Name: "${comp.Name}"`];
223
- parts.push(`Description: "${comp.Description}"`);
224
- if (comp.Types)
225
- parts.push(`Types: ${comp.Types}`);
226
- if (comp.Flags)
227
- parts.push(`Flags: ${comp.Flags}`);
228
- if (comp.ExtraDiskSpaceRequired)
229
- parts.push(`ExtraDiskSpaceRequired: ${comp.ExtraDiskSpaceRequired}`);
230
- lines.push(parts.join("; "));
231
- }
232
- return lines.join("\n");
270
+ generateTask(task) {
271
+ const parts = [
272
+ this.formatParam("Name", task.Name),
273
+ this.formatParam("Description", task.Description),
274
+ ];
275
+ if (task.GroupDescription)
276
+ parts.push(this.formatParam("GroupDescription", task.GroupDescription));
277
+ if (task.Flags)
278
+ parts.push(this.formatParamRaw("Flags", task.Flags));
279
+ if (task.Components)
280
+ parts.push(this.formatParamRaw("Components", task.Components));
281
+ if (task.Check)
282
+ parts.push(this.formatParamRaw("Check", task.Check));
283
+ return parts.join("; ");
233
284
  }
234
285
  /**
235
- * 生成 Tasks 部分
286
+ * 生成 Type 条目
287
+ *
288
+ * @param type - 安装类型配置
289
+ * @returns 格式化的类型条目
236
290
  */
237
- generateTasksSection(tasks) {
238
- const lines = ["[Tasks]"];
239
- for (const task of tasks) {
240
- const parts = [`Name: "${task.Name}"`];
241
- parts.push(`Description: "${task.Description}"`);
242
- if (task.GroupDescription)
243
- parts.push(`GroupDescription: "${task.GroupDescription}"`);
244
- if (task.Flags)
245
- parts.push(`Flags: ${task.Flags}`);
246
- if (task.Components)
247
- parts.push(`Components: ${task.Components}`);
248
- if (task.Check)
249
- parts.push(`Check: ${task.Check}`);
250
- lines.push(parts.join("; "));
251
- }
252
- return lines.join("\n");
291
+ generateType(type) {
292
+ const parts = [
293
+ this.formatParam("Name", type.Name),
294
+ this.formatParam("Description", type.Description),
295
+ ];
296
+ if (type.Flags)
297
+ parts.push(this.formatParamRaw("Flags", type.Flags));
298
+ return parts.join("; ");
253
299
  }
254
300
  /**
255
- * 生成 Files 部分
301
+ * 生成 Component 条目
302
+ *
303
+ * @param comp - 组件配置
304
+ * @returns 格式化的组件条目
256
305
  */
257
- generateFilesSection(files) {
258
- const lines = ["[Files]"];
259
- for (const file of files) {
260
- const parts = [`Source: "${file.Source}"`];
261
- parts.push(`DestDir: "${file.DestDir}"`);
262
- if (file.DestName)
263
- parts.push(`DestName: "${file.DestName}"`);
264
- if (file.Flags)
265
- parts.push(`Flags: ${file.Flags}`);
266
- if (file.Permissions)
267
- parts.push(`Permissions: ${file.Permissions}`);
268
- if (file.Components)
269
- parts.push(`Components: ${file.Components}`);
270
- if (file.Tasks)
271
- parts.push(`Tasks: ${file.Tasks}`);
272
- if (file.Languages)
273
- parts.push(`Languages: ${file.Languages}`);
274
- if (file.Check)
275
- parts.push(`Check: ${file.Check}`);
276
- if (file.BeforeInstall)
277
- parts.push(`BeforeInstall: ${file.BeforeInstall}`);
278
- if (file.AfterInstall)
279
- parts.push(`AfterInstall: ${file.AfterInstall}`);
280
- if (file.Attribs)
281
- parts.push(`Attribs: ${file.Attribs}`);
282
- if (file.FontInstall)
283
- parts.push(`FontInstall: "${file.FontInstall}"`);
284
- lines.push(parts.join("; "));
285
- }
286
- return lines.join("\n");
306
+ generateComponent(comp) {
307
+ const parts = [
308
+ this.formatParam("Name", comp.Name),
309
+ this.formatParam("Description", comp.Description),
310
+ ];
311
+ if (comp.Types)
312
+ parts.push(this.formatParamRaw("Types", comp.Types));
313
+ if (comp.Flags)
314
+ parts.push(this.formatParamRaw("Flags", comp.Flags));
315
+ if (comp.ExtraDiskSpaceRequired !== undefined) {
316
+ parts.push(`ExtraDiskSpaceRequired: ${comp.ExtraDiskSpaceRequired}`);
317
+ }
318
+ return parts.join("; ");
287
319
  }
288
320
  /**
289
- * 生成 Dirs 部分
321
+ * 生成 File 条目
322
+ *
323
+ * @param file - 文件配置
324
+ * @returns 格式化的文件条目
290
325
  */
291
- generateDirsSection(dirs) {
292
- const lines = ["[Dirs]"];
293
- for (const dir of dirs) {
294
- const parts = [`Name: "${dir.Name}"`];
295
- if (dir.Permissions)
296
- parts.push(`Permissions: ${dir.Permissions}`);
297
- if (dir.Attribs)
298
- parts.push(`Attribs: ${dir.Attribs}`);
299
- if (dir.Flags)
300
- parts.push(`Flags: ${dir.Flags}`);
301
- if (dir.Components)
302
- parts.push(`Components: ${dir.Components}`);
303
- if (dir.Tasks)
304
- parts.push(`Tasks: ${dir.Tasks}`);
305
- if (dir.Check)
306
- parts.push(`Check: ${dir.Check}`);
307
- lines.push(parts.join("; "));
308
- }
309
- return lines.join("\n");
326
+ generateFile(file) {
327
+ // 规范化路径分隔符
328
+ const normalizedSource = file.Source.replace(/\//g, "\\");
329
+ const normalizedDestDir = file.DestDir.replace(/\//g, "\\");
330
+ const parts = [
331
+ this.formatParam("Source", normalizedSource),
332
+ this.formatParam("DestDir", normalizedDestDir),
333
+ ];
334
+ if (file.DestName)
335
+ parts.push(this.formatParam("DestName", file.DestName));
336
+ if (file.Flags)
337
+ parts.push(this.formatParamRaw("Flags", file.Flags));
338
+ if (file.Permissions)
339
+ parts.push(this.formatParamRaw("Permissions", file.Permissions));
340
+ if (file.Components)
341
+ parts.push(this.formatParamRaw("Components", file.Components));
342
+ if (file.Tasks)
343
+ parts.push(this.formatParamRaw("Tasks", file.Tasks));
344
+ if (file.Languages)
345
+ parts.push(this.formatParamRaw("Languages", file.Languages));
346
+ if (file.Check)
347
+ parts.push(this.formatParamRaw("Check", file.Check));
348
+ if (file.BeforeInstall)
349
+ parts.push(this.formatParamRaw("BeforeInstall", file.BeforeInstall));
350
+ if (file.AfterInstall)
351
+ parts.push(this.formatParamRaw("AfterInstall", file.AfterInstall));
352
+ if (file.Attribs)
353
+ parts.push(this.formatParamRaw("Attribs", file.Attribs));
354
+ if (file.FontInstall)
355
+ parts.push(this.formatParam("FontInstall", file.FontInstall));
356
+ return parts.join("; ");
310
357
  }
311
358
  /**
312
- * 生成 Icons 部分
359
+ * 生成 Dir 条目
360
+ *
361
+ * @param dir - 目录配置
362
+ * @returns 格式化的目录条目
313
363
  */
314
- generateIconsSection(icons) {
315
- const lines = ["[Icons]"];
316
- for (const icon of icons) {
317
- const parts = [`Name: "${icon.Name}"`];
318
- parts.push(`Filename: "${icon.Filename}"`);
319
- if (icon.Parameters)
320
- parts.push(`Parameters: "${icon.Parameters}"`);
321
- if (icon.WorkingDir)
322
- parts.push(`WorkingDir: "${icon.WorkingDir}"`);
323
- if (icon.HotKey)
324
- parts.push(`HotKey: "${icon.HotKey}"`);
325
- if (icon.Comment)
326
- parts.push(`Comment: "${icon.Comment}"`);
327
- if (icon.IconFilename)
328
- parts.push(`IconFilename: "${icon.IconFilename}"`);
329
- if (icon.IconIndex !== undefined)
330
- parts.push(`IconIndex: ${icon.IconIndex}`);
331
- if (icon.AppUserModelID)
332
- parts.push(`AppUserModelID: "${icon.AppUserModelID}"`);
333
- if (icon.Flags)
334
- parts.push(`Flags: ${icon.Flags}`);
335
- if (icon.Components)
336
- parts.push(`Components: ${icon.Components}`);
337
- if (icon.Tasks)
338
- parts.push(`Tasks: ${icon.Tasks}`);
339
- if (icon.Languages)
340
- parts.push(`Languages: ${icon.Languages}`);
341
- if (icon.Check)
342
- parts.push(`Check: ${icon.Check}`);
343
- lines.push(parts.join("; "));
344
- }
345
- return lines.join("\n");
364
+ generateDir(dir) {
365
+ // 规范化路径分隔符
366
+ const normalizedName = dir.Name.replace(/\//g, "\\");
367
+ const parts = [this.formatParam("Name", normalizedName)];
368
+ if (dir.Permissions)
369
+ parts.push(this.formatParamRaw("Permissions", dir.Permissions));
370
+ if (dir.Attribs)
371
+ parts.push(this.formatParamRaw("Attribs", dir.Attribs));
372
+ if (dir.Flags)
373
+ parts.push(this.formatParamRaw("Flags", dir.Flags));
374
+ if (dir.Components)
375
+ parts.push(this.formatParamRaw("Components", dir.Components));
376
+ if (dir.Tasks)
377
+ parts.push(this.formatParamRaw("Tasks", dir.Tasks));
378
+ if (dir.Check)
379
+ parts.push(this.formatParamRaw("Check", dir.Check));
380
+ return parts.join("; ");
346
381
  }
347
382
  /**
348
- * 生成 INI 部分
383
+ * 生成 Icon 条目
384
+ *
385
+ * @param icon - 图标配置
386
+ * @returns 格式化的图标条目
349
387
  */
350
- generateINISection(ini) {
351
- const lines = ["[INI]"];
352
- for (const item of ini) {
353
- const parts = [`Filename: "${item.Filename}"`];
354
- parts.push(`Section: "${item.Section}"`);
355
- if (item.Key)
356
- parts.push(`Key: "${item.Key}"`);
357
- if (item.String)
358
- parts.push(`String: "${item.String}"`);
359
- if (item.Flags)
360
- parts.push(`Flags: ${item.Flags}`);
361
- if (item.Components)
362
- parts.push(`Components: ${item.Components}`);
363
- if (item.Tasks)
364
- parts.push(`Tasks: ${item.Tasks}`);
365
- if (item.Check)
366
- parts.push(`Check: ${item.Check}`);
367
- lines.push(parts.join("; "));
368
- }
369
- return lines.join("\n");
388
+ generateIcon(icon) {
389
+ // 规范化路径分隔符:Inno Setup 要求使用 \
390
+ const normalizedName = icon.Name.replace(/\//g, "\\");
391
+ const normalizedFilename = icon.Filename.replace(/\//g, "\\");
392
+ const parts = [
393
+ this.formatParam("Name", normalizedName),
394
+ this.formatParam("Filename", normalizedFilename),
395
+ ];
396
+ if (icon.Parameters)
397
+ parts.push(this.formatParam("Parameters", icon.Parameters));
398
+ if (icon.WorkingDir)
399
+ parts.push(this.formatParam("WorkingDir", icon.WorkingDir.replace(/\//g, "\\")));
400
+ if (icon.HotKey)
401
+ parts.push(this.formatParam("HotKey", icon.HotKey));
402
+ if (icon.Comment)
403
+ parts.push(this.formatParam("Comment", icon.Comment));
404
+ if (icon.IconFilename)
405
+ parts.push(this.formatParam("IconFilename", icon.IconFilename.replace(/\//g, "\\")));
406
+ if (icon.IconIndex !== undefined)
407
+ parts.push(`IconIndex: ${icon.IconIndex}`);
408
+ if (icon.AppUserModelID)
409
+ parts.push(this.formatParam("AppUserModelID", icon.AppUserModelID));
410
+ if (icon.Flags)
411
+ parts.push(this.formatParamRaw("Flags", icon.Flags));
412
+ if (icon.Components)
413
+ parts.push(this.formatParamRaw("Components", icon.Components));
414
+ if (icon.Tasks)
415
+ parts.push(this.formatParamRaw("Tasks", icon.Tasks));
416
+ if (icon.Languages)
417
+ parts.push(this.formatParamRaw("Languages", icon.Languages));
418
+ if (icon.Check)
419
+ parts.push(this.formatParamRaw("Check", icon.Check));
420
+ return parts.join("; ");
370
421
  }
371
422
  /**
372
- * 生成 InstallDelete 部分
423
+ * 生成 INI 条目
424
+ *
425
+ * @param ini - INI 文件配置
426
+ * @returns 格式化的 INI 条目
373
427
  */
374
- generateInstallDeleteSection(items) {
375
- const lines = ["[InstallDelete]"];
376
- for (const item of items) {
377
- const parts = [`Type: ${item.Type}`];
378
- parts.push(`Name: "${item.Name}"`);
379
- if (item.Components)
380
- parts.push(`Components: ${item.Components}`);
381
- if (item.Tasks)
382
- parts.push(`Tasks: ${item.Tasks}`);
383
- if (item.Check)
384
- parts.push(`Check: ${item.Check}`);
385
- lines.push(parts.join("; "));
386
- }
387
- return lines.join("\n");
428
+ generateINIItem(ini) {
429
+ const parts = [
430
+ this.formatParam("Filename", ini.Filename),
431
+ this.formatParam("Section", ini.Section),
432
+ ];
433
+ if (ini.Key)
434
+ parts.push(this.formatParam("Key", ini.Key));
435
+ if (ini.String)
436
+ parts.push(this.formatParam("String", ini.String));
437
+ if (ini.Flags)
438
+ parts.push(this.formatParamRaw("Flags", ini.Flags));
439
+ if (ini.Components)
440
+ parts.push(this.formatParamRaw("Components", ini.Components));
441
+ if (ini.Tasks)
442
+ parts.push(this.formatParamRaw("Tasks", ini.Tasks));
443
+ if (ini.Check)
444
+ parts.push(this.formatParamRaw("Check", ini.Check));
445
+ return parts.join("; ");
388
446
  }
389
447
  /**
390
- * 生成 UninstallDelete 部分
448
+ * 生成 InstallDelete/UninstallDelete 条目
449
+ *
450
+ * @param item - 删除项配置
451
+ * @returns 格式化的删除条目
391
452
  */
392
- generateUninstallDeleteSection(items) {
393
- const lines = ["[UninstallDelete]"];
394
- for (const item of items) {
395
- const parts = [`Type: ${item.Type}`];
396
- parts.push(`Name: "${item.Name}"`);
397
- if (item.Components)
398
- parts.push(`Components: ${item.Components}`);
399
- if (item.Tasks)
400
- parts.push(`Tasks: ${item.Tasks}`);
401
- if (item.Check)
402
- parts.push(`Check: ${item.Check}`);
403
- lines.push(parts.join("; "));
404
- }
405
- return lines.join("\n");
453
+ generateDeleteItem(item) {
454
+ const parts = [this.formatParamRaw("Type", item.Type), this.formatParam("Name", item.Name)];
455
+ if (item.Components)
456
+ parts.push(this.formatParamRaw("Components", item.Components));
457
+ if (item.Tasks)
458
+ parts.push(this.formatParamRaw("Tasks", item.Tasks));
459
+ if (item.Check)
460
+ parts.push(this.formatParamRaw("Check", item.Check));
461
+ return parts.join("; ");
406
462
  }
407
463
  /**
408
- * 生成 Registry 部分
464
+ * 生成 Registry 条目
465
+ *
466
+ * @param reg - 注册表配置
467
+ * @returns 格式化的注册表条目
409
468
  */
410
- generateRegistrySection(items) {
411
- const lines = ["[Registry]"];
412
- for (const item of items) {
413
- const parts = [`Root: ${item.Root}`];
414
- // Subkey: 检查是否包含 {#...} 引用或函数调用
415
- const subkey = String(item.Subkey);
416
- if (subkey.includes("{#") || subkey.includes("StringChange(")) {
417
- // 如果包含常量引用或函数,不添加引号
418
- parts.push(`Subkey: "${subkey}"`);
469
+ generateRegistryItem(reg) {
470
+ // 规范化注册表子键路径分隔符
471
+ const normalizedSubkey = reg.Subkey.replace(/\//g, "\\");
472
+ const parts = [
473
+ this.formatParamRaw("Root", reg.Root),
474
+ this.formatParam("Subkey", normalizedSubkey),
475
+ ];
476
+ if (reg.ValueType)
477
+ parts.push(this.formatParamRaw("ValueType", reg.ValueType));
478
+ if (reg.ValueName !== undefined)
479
+ parts.push(this.formatParam("ValueName", reg.ValueName));
480
+ if (reg.ValueData !== undefined) {
481
+ if (typeof reg.ValueData === "string") {
482
+ // 规范化值数据中的路径分隔符
483
+ parts.push(this.formatParam("ValueData", reg.ValueData.replace(/\//g, "\\")));
419
484
  }
420
485
  else {
421
- parts.push(`Subkey: "${subkey}"`);
422
- }
423
- if (item.ValueType)
424
- parts.push(`ValueType: ${item.ValueType}`);
425
- // ValueName: 检查是否包含引用或函数调用
426
- if (item.ValueName !== undefined) {
427
- const valueName = String(item.ValueName);
428
- if (valueName.includes("{#") || valueName.includes("StringChange(")) {
429
- // 如果包含常量引用或函数,不添加引号
430
- parts.push(`ValueName: "${valueName}"`);
431
- }
432
- else {
433
- parts.push(`ValueName: "${valueName}"`);
434
- }
435
- }
436
- if (item.ValueData !== undefined) {
437
- if (typeof item.ValueData === "string") {
438
- const valueData = item.ValueData;
439
- // 直接使用原始值,不需要额外转义
440
- // Inno Setup 中的引号转义应该由用户自己处理
441
- parts.push(`ValueData: "${valueData}"`);
442
- }
443
- else {
444
- parts.push(`ValueData: ${item.ValueData}`);
445
- }
486
+ parts.push(`ValueData: ${reg.ValueData}`);
446
487
  }
447
- if (item.Permissions)
448
- parts.push(`Permissions: ${item.Permissions}`);
449
- if (item.Flags)
450
- parts.push(`Flags: ${item.Flags}`);
451
- if (item.Components)
452
- parts.push(`Components: ${item.Components}`);
453
- if (item.Tasks)
454
- parts.push(`Tasks: ${item.Tasks}`);
455
- if (item.Check)
456
- parts.push(`Check: ${item.Check}`);
457
- lines.push(parts.join("; "));
458
488
  }
459
- return lines.join("\n");
489
+ if (reg.Permissions)
490
+ parts.push(this.formatParamRaw("Permissions", reg.Permissions));
491
+ if (reg.Flags)
492
+ parts.push(this.formatParamRaw("Flags", reg.Flags));
493
+ if (reg.Components)
494
+ parts.push(this.formatParamRaw("Components", reg.Components));
495
+ if (reg.Tasks)
496
+ parts.push(this.formatParamRaw("Tasks", reg.Tasks));
497
+ if (reg.Check)
498
+ parts.push(this.formatParamRaw("Check", reg.Check));
499
+ return parts.join("; ");
460
500
  }
461
501
  /**
462
- * 生成 Run 部分
502
+ * 生成 Run 条目
503
+ *
504
+ * @param run - 运行配置
505
+ * @returns 格式化的运行条目
463
506
  */
464
- generateRunSection(items) {
465
- const lines = ["[Run]"];
466
- for (const item of items) {
467
- const parts = [`Filename: "${item.Filename}"`];
468
- if (item.Parameters)
469
- parts.push(`Parameters: "${item.Parameters}"`);
470
- if (item.WorkingDir)
471
- parts.push(`WorkingDir: "${item.WorkingDir}"`);
472
- if (item.StatusMsg)
473
- parts.push(`StatusMsg: "${item.StatusMsg}"`);
474
- if (item.Description)
475
- parts.push(`Description: "${item.Description}"`);
476
- if (item.Flags)
477
- parts.push(`Flags: ${item.Flags}`);
478
- if (item.RunOnceId)
479
- parts.push(`RunOnceId: "${item.RunOnceId}"`);
480
- if (item.Verb)
481
- parts.push(`Verb: "${item.Verb}"`);
482
- if (item.Components)
483
- parts.push(`Components: ${item.Components}`);
484
- if (item.Tasks)
485
- parts.push(`Tasks: ${item.Tasks}`);
486
- if (item.Languages)
487
- parts.push(`Languages: ${item.Languages}`);
488
- if (item.Check)
489
- parts.push(`Check: ${item.Check}`);
490
- lines.push(parts.join("; "));
491
- }
492
- return lines.join("\n");
507
+ generateRunItem(run) {
508
+ // 规范化路径分隔符
509
+ const normalizedFilename = run.Filename.replace(/\//g, "\\");
510
+ const parts = [this.formatParam("Filename", normalizedFilename)];
511
+ if (run.Parameters)
512
+ parts.push(this.formatParam("Parameters", run.Parameters));
513
+ if (run.WorkingDir)
514
+ parts.push(this.formatParam("WorkingDir", run.WorkingDir.replace(/\//g, "\\")));
515
+ if (run.StatusMsg)
516
+ parts.push(this.formatParam("StatusMsg", run.StatusMsg));
517
+ if (run.Description)
518
+ parts.push(this.formatParam("Description", run.Description));
519
+ if (run.Flags)
520
+ parts.push(this.formatParamRaw("Flags", run.Flags));
521
+ if (run.RunOnceId)
522
+ parts.push(this.formatParam("RunOnceId", run.RunOnceId));
523
+ if (run.Verb)
524
+ parts.push(this.formatParam("Verb", run.Verb));
525
+ if (run.Components)
526
+ parts.push(this.formatParamRaw("Components", run.Components));
527
+ if (run.Tasks)
528
+ parts.push(this.formatParamRaw("Tasks", run.Tasks));
529
+ if (run.Languages)
530
+ parts.push(this.formatParamRaw("Languages", run.Languages));
531
+ if (run.Check)
532
+ parts.push(this.formatParamRaw("Check", run.Check));
533
+ return parts.join("; ");
493
534
  }
494
535
  /**
495
- * 生成 UninstallRun 部分
536
+ * 生成 UninstallRun 条目
537
+ *
538
+ * @param run - 卸载运行配置
539
+ * @returns 格式化的卸载运行条目
496
540
  */
497
- generateUninstallRunSection(items) {
498
- const lines = ["[UninstallRun]"];
499
- for (const item of items) {
500
- const parts = [`Filename: "${item.Filename}"`];
501
- if (item.Parameters)
502
- parts.push(`Parameters: "${item.Parameters}"`);
503
- if (item.WorkingDir)
504
- parts.push(`WorkingDir: "${item.WorkingDir}"`);
505
- if (item.StatusMsg)
506
- parts.push(`StatusMsg: "${item.StatusMsg}"`);
507
- if (item.Description)
508
- parts.push(`Description: "${item.Description}"`);
509
- if (item.Flags)
510
- parts.push(`Flags: ${item.Flags}`);
511
- if (item.RunOnceId)
512
- parts.push(`RunOnceId: "${item.RunOnceId}"`);
513
- if (item.Components)
514
- parts.push(`Components: ${item.Components}`);
515
- if (item.Tasks)
516
- parts.push(`Tasks: ${item.Tasks}`);
517
- if (item.Check)
518
- parts.push(`Check: ${item.Check}`);
519
- lines.push(parts.join("; "));
520
- }
521
- return lines.join("\n");
541
+ generateUninstallRunItem(run) {
542
+ // 规范化路径分隔符
543
+ const normalizedFilename = run.Filename.replace(/\//g, "\\");
544
+ const parts = [this.formatParam("Filename", normalizedFilename)];
545
+ if (run.Parameters)
546
+ parts.push(this.formatParam("Parameters", run.Parameters));
547
+ if (run.WorkingDir)
548
+ parts.push(this.formatParam("WorkingDir", run.WorkingDir.replace(/\//g, "\\")));
549
+ if (run.StatusMsg)
550
+ parts.push(this.formatParam("StatusMsg", run.StatusMsg));
551
+ if (run.Description)
552
+ parts.push(this.formatParam("Description", run.Description));
553
+ if (run.Flags)
554
+ parts.push(this.formatParamRaw("Flags", run.Flags));
555
+ if (run.RunOnceId)
556
+ parts.push(this.formatParam("RunOnceId", run.RunOnceId));
557
+ if (run.Components)
558
+ parts.push(this.formatParamRaw("Components", run.Components));
559
+ if (run.Tasks)
560
+ parts.push(this.formatParamRaw("Tasks", run.Tasks));
561
+ if (run.Check)
562
+ parts.push(this.formatParamRaw("Check", run.Check));
563
+ return parts.join("; ");
522
564
  }
523
565
  /**
524
- * 生成 Messages 部分
566
+ * 生成 Messages/CustomMessages
567
+ *
568
+ * @param name - 节名称
569
+ * @param messages - 消息定义
570
+ * @returns 完整的消息节内容
525
571
  */
526
- generateMessagesSection(messages) {
527
- const lines = ["[Messages]"];
572
+ generateMessagesSection(name, messages) {
573
+ const lines = [`[${name}]`];
528
574
  for (const [key, value] of Object.entries(messages)) {
529
575
  lines.push(`${key}=${value}`);
530
576
  }
531
577
  return lines.join("\n");
532
578
  }
533
579
  /**
534
- * 生成 CustomMessages 部分
535
- */
536
- generateCustomMessagesSection(messages) {
537
- const lines = ["[CustomMessages]"];
538
- for (const [key, value] of Object.entries(messages)) {
539
- lines.push(`${key}=${value}`);
540
- }
541
- return lines.join("\n");
542
- }
543
- /**
544
- * 生成 Code 部分
580
+ * 生成 Code
581
+ *
582
+ * @param code - Pascal 脚本代码
583
+ * @returns 完整的 Code 节内容
545
584
  */
546
585
  generateCodeSection(code) {
547
586
  return `[Code]\n${code}`;
548
587
  }
549
- /**
550
- * 将脚本保存到文件
551
- * 注意:使用 UTF-8 编码保存,并在文件开头添加 BOM 标记
552
- */
553
- saveToFile(scriptContent, filePath) {
554
- const dir = path.dirname(filePath);
555
- if (!fs.existsSync(dir)) {
556
- fs.mkdirSync(dir, { recursive: true });
557
- }
558
- // 使用 UTF-8 编码保存,scriptContent 已经包含 BOM
559
- fs.writeFileSync(filePath, scriptContent, "utf-8");
560
- }
561
588
  }
562
589
  exports.InnoScriptGenerator = InnoScriptGenerator;
590
+ //# sourceMappingURL=generator.js.map