reset-framework-cli 1.2.0 → 1.2.1

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 (34) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +19 -19
  3. package/package.json +6 -6
  4. package/src/commands/build.js +71 -71
  5. package/src/commands/dev.js +121 -121
  6. package/src/commands/doctor.js +54 -54
  7. package/src/commands/init.js +866 -866
  8. package/src/commands/package.js +68 -68
  9. package/src/index.js +195 -195
  10. package/src/lib/context.js +66 -66
  11. package/src/lib/framework.js +57 -57
  12. package/src/lib/logger.js +11 -11
  13. package/src/lib/output.js +234 -234
  14. package/src/lib/process.js +303 -303
  15. package/src/lib/project.js +493 -493
  16. package/src/lib/toolchain.js +62 -62
  17. package/src/lib/ui.js +244 -244
  18. package/templates/basic/README.md +15 -15
  19. package/templates/basic/frontend/README.md +73 -73
  20. package/templates/basic/frontend/eslint.config.js +23 -23
  21. package/templates/basic/frontend/index.html +13 -13
  22. package/templates/basic/frontend/package.json +31 -31
  23. package/templates/basic/frontend/public/icons.svg +24 -24
  24. package/templates/basic/frontend/src/App.css +216 -216
  25. package/templates/basic/frontend/src/App.tsx +77 -77
  26. package/templates/basic/frontend/src/assets/vite.svg +1 -1
  27. package/templates/basic/frontend/src/index.css +111 -111
  28. package/templates/basic/frontend/src/lib/reset.ts +1 -1
  29. package/templates/basic/frontend/src/main.tsx +10 -10
  30. package/templates/basic/frontend/tsconfig.app.json +28 -28
  31. package/templates/basic/frontend/tsconfig.json +7 -7
  32. package/templates/basic/frontend/tsconfig.node.json +26 -26
  33. package/templates/basic/frontend/vite.config.ts +16 -16
  34. package/templates/basic/reset.config.json +58 -58
@@ -6,13 +6,13 @@ import path from "node:path"
6
6
  import { assertFrameworkSourceInstall, resolveFrameworkRuntimeStrategy } from "./project.js"
7
7
  import { runCommand } from "./process.js"
8
8
  import { ensureVcpkgToolchain } from "./toolchain.js"
9
-
10
- function getBuildDirectory(frameworkBuildPaths, mode) {
11
- return mode === "release"
12
- ? frameworkBuildPaths.releaseBuildDir
13
- : frameworkBuildPaths.devBuildDir
14
- }
15
-
9
+
10
+ function getBuildDirectory(frameworkBuildPaths, mode) {
11
+ return mode === "release"
12
+ ? frameworkBuildPaths.releaseBuildDir
13
+ : frameworkBuildPaths.devBuildDir
14
+ }
15
+
16
16
  function getBuildType(mode) {
17
17
  return mode === "release" ? "Release" : "Debug"
18
18
  }
@@ -132,18 +132,18 @@ async function resolveCmakeGenerator() {
132
132
  typeof process.env.CMAKE_GENERATOR === "string" && process.env.CMAKE_GENERATOR.trim() !== ""
133
133
  ? process.env.CMAKE_GENERATOR.trim()
134
134
  : null
135
-
136
- if (envGenerator) {
137
- return {
138
- name: envGenerator,
139
- configureArgs: process.platform === "win32" &&
140
- !process.env.CMAKE_GENERATOR_PLATFORM &&
141
- envGenerator.startsWith("Visual Studio ")
142
- ? ["-G", envGenerator, "-A", "x64"]
143
- : ["-G", envGenerator],
144
- buildArgs: envGenerator.startsWith("Visual Studio ")
145
- ? ["--config"]
146
- : [],
135
+
136
+ if (envGenerator) {
137
+ return {
138
+ name: envGenerator,
139
+ configureArgs: process.platform === "win32" &&
140
+ !process.env.CMAKE_GENERATOR_PLATFORM &&
141
+ envGenerator.startsWith("Visual Studio ")
142
+ ? ["-G", envGenerator, "-A", "x64"]
143
+ : ["-G", envGenerator],
144
+ buildArgs: envGenerator.startsWith("Visual Studio ")
145
+ ? ["--config"]
146
+ : [],
147
147
  multiConfig: envGenerator.startsWith("Visual Studio ")
148
148
  }
149
149
  }
@@ -170,22 +170,22 @@ async function resolveCmakeGenerator() {
170
170
  configureArgs: ["-G", "Ninja"],
171
171
  buildArgs: [],
172
172
  multiConfig: false
173
- }
174
- }
175
-
173
+ }
174
+ }
175
+
176
176
  async function ensureCompatibleCmakeBuild(buildDir, frameworkRoot, generatorName) {
177
177
  const cachePath = path.join(buildDir, "CMakeCache.txt")
178
178
  if (!existsSync(cachePath)) {
179
179
  return
180
180
  }
181
-
182
- let cache
183
- try {
184
- cache = await readFile(cachePath, "utf8")
185
- } catch {
186
- return
187
- }
188
-
181
+
182
+ let cache
183
+ try {
184
+ cache = await readFile(cachePath, "utf8")
185
+ } catch {
186
+ return
187
+ }
188
+
189
189
  const cachedRootValue = readCmakeCacheValue(cache, "CMAKE_HOME_DIRECTORY")
190
190
  const cachedGenerator = readCmakeCacheValue(cache, "CMAKE_GENERATOR")
191
191
  if (!cachedRootValue) {
@@ -202,7 +202,7 @@ async function ensureCompatibleCmakeBuild(buildDir, frameworkRoot, generatorName
202
202
  await rm(buildDir, { recursive: true, force: true })
203
203
  }
204
204
  }
205
-
205
+
206
206
  export async function configureFrameworkBuild(frameworkPaths, frameworkBuildPaths, mode, options = {}) {
207
207
  const { dryRun = false, cwd } = options
208
208
  assertFrameworkSourceInstall(frameworkPaths)
@@ -212,27 +212,27 @@ export async function configureFrameworkBuild(frameworkPaths, frameworkBuildPath
212
212
  if (!dryRun) {
213
213
  await ensureCompatibleCmakeBuild(buildDir, frameworkPaths.frameworkRoot, generator.name)
214
214
  }
215
- const configureArgs = [
216
- "-S",
217
- frameworkPaths.frameworkRoot,
218
- "-B",
219
- buildDir,
220
- ...generator.configureArgs,
221
- `-DCMAKE_BUILD_TYPE=${getBuildType(mode)}`,
222
- "-DCMAKE_CXX_STANDARD=20",
223
- "-DCMAKE_CXX_STANDARD_REQUIRED=ON",
224
- "-DCMAKE_CXX_EXTENSIONS=OFF",
225
- "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
226
- `-DCMAKE_TOOLCHAIN_FILE=${toolchainFile}`
227
- ]
228
-
229
- try {
230
- await runCommand("cmake", configureArgs, {
231
- cwd,
232
- dryRun
233
- })
234
- } catch (error) {
235
- throw error
215
+ const configureArgs = [
216
+ "-S",
217
+ frameworkPaths.frameworkRoot,
218
+ "-B",
219
+ buildDir,
220
+ ...generator.configureArgs,
221
+ `-DCMAKE_BUILD_TYPE=${getBuildType(mode)}`,
222
+ "-DCMAKE_CXX_STANDARD=20",
223
+ "-DCMAKE_CXX_STANDARD_REQUIRED=ON",
224
+ "-DCMAKE_CXX_EXTENSIONS=OFF",
225
+ "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
226
+ `-DCMAKE_TOOLCHAIN_FILE=${toolchainFile}`
227
+ ]
228
+
229
+ try {
230
+ await runCommand("cmake", configureArgs, {
231
+ cwd,
232
+ dryRun
233
+ })
234
+ } catch (error) {
235
+ throw error
236
236
  }
237
237
  }
238
238
 
@@ -240,11 +240,11 @@ async function buildFrameworkRuntimeFromSource(frameworkPaths, frameworkBuildPat
240
240
  const { dryRun = false, cwd } = options
241
241
  const buildDir = getBuildDirectory(frameworkBuildPaths, mode)
242
242
  const generator = await resolveCmakeGenerator()
243
-
244
- await configureFrameworkBuild(frameworkPaths, frameworkBuildPaths, mode, {
245
- cwd,
246
- dryRun
247
- })
243
+
244
+ await configureFrameworkBuild(frameworkPaths, frameworkBuildPaths, mode, {
245
+ cwd,
246
+ dryRun
247
+ })
248
248
 
249
249
  await runCommand("cmake", ["--build", buildDir, ...generator.buildArgs, ...(generator.multiConfig ? [getBuildType(mode)] : [])], {
250
250
  cwd,
package/src/lib/logger.js CHANGED
@@ -1,11 +1,11 @@
1
- export const logger = {
2
- info(message) {
3
- console.log(message)
4
- },
5
- warn(message) {
6
- console.warn(message)
7
- },
8
- error(message) {
9
- console.error(message)
10
- }
11
- }
1
+ export const logger = {
2
+ info(message) {
3
+ console.log(message)
4
+ },
5
+ warn(message) {
6
+ console.warn(message)
7
+ },
8
+ error(message) {
9
+ console.error(message)
10
+ }
11
+ }
package/src/lib/output.js CHANGED
@@ -1,122 +1,122 @@
1
- import path from "node:path"
2
- import { cp, mkdir, readdir, rm, writeFile } from "node:fs/promises"
3
- import { existsSync } from "node:fs"
4
-
5
- import { logger } from "./logger.js"
6
- import { runCommand } from "./process.js"
7
- import {
8
- resolveFrameworkRuntimeBinary,
9
- resolveFrameworkRuntimeOutputDir
10
- } from "./project.js"
11
-
12
- function escapePlistString(value) {
13
- return value
14
- .replaceAll("&", "&")
15
- .replaceAll("<", "&lt;")
16
- .replaceAll(">", "&gt;")
17
- }
18
-
19
- function serializePlistValue(value, indentLevel = 1) {
20
- const indent = " ".repeat(indentLevel)
21
-
22
- if (Array.isArray(value)) {
23
- if (value.length === 0) {
24
- return `${indent}<array/>\n`
25
- }
26
-
27
- return (
28
- `${indent}<array>\n` +
29
- value.map((entry) => serializePlistValue(entry, indentLevel + 1)).join("") +
30
- `${indent}</array>\n`
31
- )
32
- }
33
-
34
- if (typeof value === "object" && value !== null) {
35
- const entries = Object.entries(value)
36
- if (entries.length === 0) {
37
- return `${indent}<dict/>\n`
38
- }
39
-
40
- return (
41
- `${indent}<dict>\n` +
42
- entries
43
- .map(
44
- ([key, entryValue]) =>
45
- `${" ".repeat(indentLevel + 1)}<key>${escapePlistString(key)}</key>\n${serializePlistValue(entryValue, indentLevel + 1)}`
46
- )
47
- .join("") +
48
- `${indent}</dict>\n`
49
- )
50
- }
51
-
52
- if (typeof value === "boolean") {
53
- return `${indent}<${value ? "true" : "false"}/>\n`
54
- }
55
-
56
- if (typeof value === "number") {
57
- return `${indent}<integer>${value}</integer>\n`
58
- }
59
-
60
- return `${indent}<string>${escapePlistString(String(value))}</string>\n`
61
- }
62
-
63
- function buildMacOSInfoPlist(config) {
64
- const urlTypes = Array.isArray(config.protocols?.schemes)
65
- ? config.protocols.schemes.map((schemeConfig) => ({
66
- CFBundleTypeRole: schemeConfig.role ?? "Viewer",
67
- CFBundleURLName:
68
- typeof schemeConfig.name === "string" && schemeConfig.name.trim() !== ""
69
- ? schemeConfig.name
70
- : `${config.appId}.${schemeConfig.scheme}`,
71
- CFBundleURLSchemes: [schemeConfig.scheme]
72
- }))
73
- : []
74
-
75
- const plist = {
76
- CFBundleDevelopmentRegion: "English",
77
- CFBundleDisplayName: config.productName,
78
- CFBundleExecutable: "reset-framework",
79
- CFBundleIdentifier: config.appId,
80
- CFBundleInfoDictionaryVersion: "6.0",
81
- CFBundleName: config.productName,
82
- CFBundlePackageType: "APPL",
83
- CFBundleShortVersionString: config.version,
84
- CFBundleVersion: config.version,
85
- CSResourcesFileMapped: true
86
- }
87
-
88
- if (urlTypes.length > 0) {
89
- plist.CFBundleURLTypes = urlTypes
90
- }
91
-
92
- return (
93
- `<?xml version="1.0" encoding="UTF-8"?>\n` +
94
- `<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n` +
95
- `<plist version="1.0">\n` +
96
- serializePlistValue(plist, 0) +
97
- `</plist>\n`
98
- )
99
- }
100
-
101
- function shouldCopyWindowsRuntimeArtifact(entryName) {
102
- const extension = path.extname(entryName).toLowerCase()
103
-
104
- return [
105
- ".bin",
106
- ".dat",
107
- ".dll",
108
- ".exe",
109
- ".json",
110
- ".manifest",
111
- ".pak",
112
- ".pri"
113
- ].includes(extension)
114
- }
115
-
116
- function escapePowerShellLiteral(value) {
117
- return String(value).replaceAll("'", "''")
118
- }
119
-
1
+ import path from "node:path"
2
+ import { cp, mkdir, readdir, rm, writeFile } from "node:fs/promises"
3
+ import { existsSync } from "node:fs"
4
+
5
+ import { logger } from "./logger.js"
6
+ import { runCommand } from "./process.js"
7
+ import {
8
+ resolveFrameworkRuntimeBinary,
9
+ resolveFrameworkRuntimeOutputDir
10
+ } from "./project.js"
11
+
12
+ function escapePlistString(value) {
13
+ return value
14
+ .replaceAll("&", "&amp;")
15
+ .replaceAll("<", "&lt;")
16
+ .replaceAll(">", "&gt;")
17
+ }
18
+
19
+ function serializePlistValue(value, indentLevel = 1) {
20
+ const indent = " ".repeat(indentLevel)
21
+
22
+ if (Array.isArray(value)) {
23
+ if (value.length === 0) {
24
+ return `${indent}<array/>\n`
25
+ }
26
+
27
+ return (
28
+ `${indent}<array>\n` +
29
+ value.map((entry) => serializePlistValue(entry, indentLevel + 1)).join("") +
30
+ `${indent}</array>\n`
31
+ )
32
+ }
33
+
34
+ if (typeof value === "object" && value !== null) {
35
+ const entries = Object.entries(value)
36
+ if (entries.length === 0) {
37
+ return `${indent}<dict/>\n`
38
+ }
39
+
40
+ return (
41
+ `${indent}<dict>\n` +
42
+ entries
43
+ .map(
44
+ ([key, entryValue]) =>
45
+ `${" ".repeat(indentLevel + 1)}<key>${escapePlistString(key)}</key>\n${serializePlistValue(entryValue, indentLevel + 1)}`
46
+ )
47
+ .join("") +
48
+ `${indent}</dict>\n`
49
+ )
50
+ }
51
+
52
+ if (typeof value === "boolean") {
53
+ return `${indent}<${value ? "true" : "false"}/>\n`
54
+ }
55
+
56
+ if (typeof value === "number") {
57
+ return `${indent}<integer>${value}</integer>\n`
58
+ }
59
+
60
+ return `${indent}<string>${escapePlistString(String(value))}</string>\n`
61
+ }
62
+
63
+ function buildMacOSInfoPlist(config) {
64
+ const urlTypes = Array.isArray(config.protocols?.schemes)
65
+ ? config.protocols.schemes.map((schemeConfig) => ({
66
+ CFBundleTypeRole: schemeConfig.role ?? "Viewer",
67
+ CFBundleURLName:
68
+ typeof schemeConfig.name === "string" && schemeConfig.name.trim() !== ""
69
+ ? schemeConfig.name
70
+ : `${config.appId}.${schemeConfig.scheme}`,
71
+ CFBundleURLSchemes: [schemeConfig.scheme]
72
+ }))
73
+ : []
74
+
75
+ const plist = {
76
+ CFBundleDevelopmentRegion: "English",
77
+ CFBundleDisplayName: config.productName,
78
+ CFBundleExecutable: "reset-framework",
79
+ CFBundleIdentifier: config.appId,
80
+ CFBundleInfoDictionaryVersion: "6.0",
81
+ CFBundleName: config.productName,
82
+ CFBundlePackageType: "APPL",
83
+ CFBundleShortVersionString: config.version,
84
+ CFBundleVersion: config.version,
85
+ CSResourcesFileMapped: true
86
+ }
87
+
88
+ if (urlTypes.length > 0) {
89
+ plist.CFBundleURLTypes = urlTypes
90
+ }
91
+
92
+ return (
93
+ `<?xml version="1.0" encoding="UTF-8"?>\n` +
94
+ `<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n` +
95
+ `<plist version="1.0">\n` +
96
+ serializePlistValue(plist, 0) +
97
+ `</plist>\n`
98
+ )
99
+ }
100
+
101
+ function shouldCopyWindowsRuntimeArtifact(entryName) {
102
+ const extension = path.extname(entryName).toLowerCase()
103
+
104
+ return [
105
+ ".bin",
106
+ ".dat",
107
+ ".dll",
108
+ ".exe",
109
+ ".json",
110
+ ".manifest",
111
+ ".pak",
112
+ ".pri"
113
+ ].includes(extension)
114
+ }
115
+
116
+ function escapePowerShellLiteral(value) {
117
+ return String(value).replaceAll("'", "''")
118
+ }
119
+
120
120
  export async function stageMacOSAppBundle(frameworkPaths, frameworkBuildPaths, config, options = {}) {
121
121
  const { dryRun = false, outputPaths, configPath, preferSource = false } = options
122
122
  const runtimeSourceBundle = resolveFrameworkRuntimeOutputDir(frameworkPaths, frameworkBuildPaths, "release", {
@@ -131,9 +131,9 @@ export async function stageMacOSAppBundle(frameworkPaths, frameworkBuildPaths, c
131
131
  if (!existsSync(outputPaths.frontendEntryFile) && !dryRun) {
132
132
  throw new Error(
133
133
  `Missing frontend build output at ${outputPaths.frontendEntryFile}. Run the frontend build first.`
134
- )
135
- }
136
-
134
+ )
135
+ }
136
+
137
137
  logger.info(`Staging app bundle into ${outputPaths.appBundlePath}`)
138
138
 
139
139
  if (dryRun) {
@@ -141,25 +141,25 @@ export async function stageMacOSAppBundle(frameworkPaths, frameworkBuildPaths, c
141
141
  logger.info(`- copy ${configPath} -> ${outputPaths.bundledConfigPath}`)
142
142
  logger.info(`- copy ${outputPaths.frontendDistDir} -> ${outputPaths.bundledFrontendDir}`)
143
143
  return outputPaths
144
- }
145
-
144
+ }
145
+
146
146
  await mkdir(outputPaths.macosDir, { recursive: true })
147
147
  await rm(outputPaths.appBundlePath, { recursive: true, force: true })
148
148
  await cp(runtimeSourceBundle, outputPaths.appBundlePath, { recursive: true })
149
-
150
- await mkdir(outputPaths.resourcesDir, { recursive: true })
151
- await cp(configPath, outputPaths.bundledConfigPath, { force: true })
152
- await rm(outputPaths.bundledFrontendDir, { recursive: true, force: true })
153
- await cp(outputPaths.frontendDistDir, outputPaths.bundledFrontendDir, { recursive: true })
154
- await writeFile(
155
- path.join(outputPaths.appBundlePath, "Contents", "Info.plist"),
156
- buildMacOSInfoPlist(config),
157
- "utf8"
158
- )
159
-
160
- return outputPaths
161
- }
162
-
149
+
150
+ await mkdir(outputPaths.resourcesDir, { recursive: true })
151
+ await cp(configPath, outputPaths.bundledConfigPath, { force: true })
152
+ await rm(outputPaths.bundledFrontendDir, { recursive: true, force: true })
153
+ await cp(outputPaths.frontendDistDir, outputPaths.bundledFrontendDir, { recursive: true })
154
+ await writeFile(
155
+ path.join(outputPaths.appBundlePath, "Contents", "Info.plist"),
156
+ buildMacOSInfoPlist(config),
157
+ "utf8"
158
+ )
159
+
160
+ return outputPaths
161
+ }
162
+
163
163
  export async function stageWindowsAppBundle(frameworkPaths, frameworkBuildPaths, config, options = {}) {
164
164
  const { dryRun = false, outputPaths, configPath, preferSource = false } = options
165
165
  const runtimeSourceBinary = resolveFrameworkRuntimeBinary(frameworkPaths, frameworkBuildPaths, "release", {
@@ -170,99 +170,99 @@ export async function stageWindowsAppBundle(frameworkPaths, frameworkBuildPaths,
170
170
  mustExist: !dryRun,
171
171
  preferSource
172
172
  })
173
-
174
- if (!outputPaths) {
175
- throw new Error("stageWindowsAppBundle requires resolved output paths")
176
- }
177
-
178
- if (!existsSync(outputPaths.frontendEntryFile) && !dryRun) {
179
- throw new Error(
180
- `Missing frontend build output at ${outputPaths.frontendEntryFile}. Run the frontend build first.`
181
- )
182
- }
183
-
184
- logger.info(`Staging Windows app into ${outputPaths.appBundlePath}`)
185
-
186
- if (dryRun) {
187
- logger.info(`- copy ${runtimeSourceDir} -> ${outputPaths.appBundlePath}`)
188
- logger.info(`- rename ${runtimeSourceBinary} -> ${outputPaths.appExecutablePath}`)
189
- logger.info(`- copy ${configPath} -> ${outputPaths.bundledConfigPath}`)
190
- logger.info(`- copy ${outputPaths.frontendDistDir} -> ${outputPaths.bundledFrontendDir}`)
191
- return outputPaths
192
- }
193
-
194
- await mkdir(outputPaths.windowsDir, { recursive: true })
195
- await rm(outputPaths.appBundlePath, { recursive: true, force: true })
196
- await mkdir(outputPaths.appBundlePath, { recursive: true })
197
- const runtimeEntries = await readdir(runtimeSourceDir, { withFileTypes: true })
198
- const runtimeBinaryName = path.basename(runtimeSourceBinary)
199
-
200
- for (const entry of runtimeEntries) {
201
- if (!entry.isDirectory() && !shouldCopyWindowsRuntimeArtifact(entry.name)) {
202
- continue
203
- }
204
-
205
- const sourcePath = path.join(runtimeSourceDir, entry.name)
206
- const targetPath =
207
- entry.name.toLowerCase() === runtimeBinaryName.toLowerCase()
208
- ? outputPaths.appExecutablePath
209
- : path.join(outputPaths.appBundlePath, entry.name)
210
-
211
- await cp(sourcePath, targetPath, { recursive: true, force: true })
212
- }
213
-
214
- await mkdir(outputPaths.resourcesDir, { recursive: true })
215
- await cp(configPath, outputPaths.bundledConfigPath, { force: true })
216
- await rm(outputPaths.bundledFrontendDir, { recursive: true, force: true })
217
- await cp(outputPaths.frontendDistDir, outputPaths.bundledFrontendDir, { recursive: true })
218
-
219
- return outputPaths
220
- }
221
-
222
- export async function createMacOSZipArchive(outputPaths, options = {}) {
223
- const { dryRun = false } = options
224
-
225
- logger.info(`Packaging ${outputPaths.appBundlePath} -> ${outputPaths.zipPath}`)
226
-
227
- if (process.platform !== "darwin") {
228
- throw new Error("Packaging is only implemented for macOS right now")
229
- }
230
-
231
- if (!dryRun) {
232
- await mkdir(outputPaths.packagesDir, { recursive: true })
233
- }
234
-
235
- await runCommand(
236
- "ditto",
237
- ["-c", "-k", "--sequesterRsrc", "--keepParent", outputPaths.appBundlePath, outputPaths.zipPath],
238
- { dryRun }
239
- )
240
- }
241
-
242
- export async function createWindowsZipArchive(outputPaths, options = {}) {
243
- const { dryRun = false } = options
244
-
245
- logger.info(`Packaging ${outputPaths.appBundlePath} -> ${outputPaths.zipPath}`)
246
-
247
- if (process.platform !== "win32") {
248
- throw new Error("Packaging is only implemented for Windows and macOS right now")
249
- }
250
-
251
- if (!dryRun) {
252
- await mkdir(outputPaths.packagesDir, { recursive: true })
253
- await rm(outputPaths.zipPath, { force: true })
254
- }
255
-
256
- const literalSourcePath = escapePowerShellLiteral(outputPaths.appBundlePath)
257
- const literalDestinationPath = escapePowerShellLiteral(outputPaths.zipPath)
258
- const archiveCommand = [
259
- "$ErrorActionPreference = 'Stop'",
260
- `Compress-Archive -LiteralPath '${literalSourcePath}' -DestinationPath '${literalDestinationPath}' -CompressionLevel Optimal`
261
- ].join("; ")
262
-
263
- await runCommand(
264
- "powershell.exe",
265
- ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", archiveCommand],
266
- { dryRun }
267
- )
268
- }
173
+
174
+ if (!outputPaths) {
175
+ throw new Error("stageWindowsAppBundle requires resolved output paths")
176
+ }
177
+
178
+ if (!existsSync(outputPaths.frontendEntryFile) && !dryRun) {
179
+ throw new Error(
180
+ `Missing frontend build output at ${outputPaths.frontendEntryFile}. Run the frontend build first.`
181
+ )
182
+ }
183
+
184
+ logger.info(`Staging Windows app into ${outputPaths.appBundlePath}`)
185
+
186
+ if (dryRun) {
187
+ logger.info(`- copy ${runtimeSourceDir} -> ${outputPaths.appBundlePath}`)
188
+ logger.info(`- rename ${runtimeSourceBinary} -> ${outputPaths.appExecutablePath}`)
189
+ logger.info(`- copy ${configPath} -> ${outputPaths.bundledConfigPath}`)
190
+ logger.info(`- copy ${outputPaths.frontendDistDir} -> ${outputPaths.bundledFrontendDir}`)
191
+ return outputPaths
192
+ }
193
+
194
+ await mkdir(outputPaths.windowsDir, { recursive: true })
195
+ await rm(outputPaths.appBundlePath, { recursive: true, force: true })
196
+ await mkdir(outputPaths.appBundlePath, { recursive: true })
197
+ const runtimeEntries = await readdir(runtimeSourceDir, { withFileTypes: true })
198
+ const runtimeBinaryName = path.basename(runtimeSourceBinary)
199
+
200
+ for (const entry of runtimeEntries) {
201
+ if (!entry.isDirectory() && !shouldCopyWindowsRuntimeArtifact(entry.name)) {
202
+ continue
203
+ }
204
+
205
+ const sourcePath = path.join(runtimeSourceDir, entry.name)
206
+ const targetPath =
207
+ entry.name.toLowerCase() === runtimeBinaryName.toLowerCase()
208
+ ? outputPaths.appExecutablePath
209
+ : path.join(outputPaths.appBundlePath, entry.name)
210
+
211
+ await cp(sourcePath, targetPath, { recursive: true, force: true })
212
+ }
213
+
214
+ await mkdir(outputPaths.resourcesDir, { recursive: true })
215
+ await cp(configPath, outputPaths.bundledConfigPath, { force: true })
216
+ await rm(outputPaths.bundledFrontendDir, { recursive: true, force: true })
217
+ await cp(outputPaths.frontendDistDir, outputPaths.bundledFrontendDir, { recursive: true })
218
+
219
+ return outputPaths
220
+ }
221
+
222
+ export async function createMacOSZipArchive(outputPaths, options = {}) {
223
+ const { dryRun = false } = options
224
+
225
+ logger.info(`Packaging ${outputPaths.appBundlePath} -> ${outputPaths.zipPath}`)
226
+
227
+ if (process.platform !== "darwin") {
228
+ throw new Error("Packaging is only implemented for macOS right now")
229
+ }
230
+
231
+ if (!dryRun) {
232
+ await mkdir(outputPaths.packagesDir, { recursive: true })
233
+ }
234
+
235
+ await runCommand(
236
+ "ditto",
237
+ ["-c", "-k", "--sequesterRsrc", "--keepParent", outputPaths.appBundlePath, outputPaths.zipPath],
238
+ { dryRun }
239
+ )
240
+ }
241
+
242
+ export async function createWindowsZipArchive(outputPaths, options = {}) {
243
+ const { dryRun = false } = options
244
+
245
+ logger.info(`Packaging ${outputPaths.appBundlePath} -> ${outputPaths.zipPath}`)
246
+
247
+ if (process.platform !== "win32") {
248
+ throw new Error("Packaging is only implemented for Windows and macOS right now")
249
+ }
250
+
251
+ if (!dryRun) {
252
+ await mkdir(outputPaths.packagesDir, { recursive: true })
253
+ await rm(outputPaths.zipPath, { force: true })
254
+ }
255
+
256
+ const literalSourcePath = escapePowerShellLiteral(outputPaths.appBundlePath)
257
+ const literalDestinationPath = escapePowerShellLiteral(outputPaths.zipPath)
258
+ const archiveCommand = [
259
+ "$ErrorActionPreference = 'Stop'",
260
+ `Compress-Archive -LiteralPath '${literalSourcePath}' -DestinationPath '${literalDestinationPath}' -CompressionLevel Optimal`
261
+ ].join("; ")
262
+
263
+ await runCommand(
264
+ "powershell.exe",
265
+ ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", archiveCommand],
266
+ { dryRun }
267
+ )
268
+ }