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.
- package/LICENSE +20 -20
- package/README.md +19 -19
- package/package.json +6 -6
- package/src/commands/build.js +71 -71
- package/src/commands/dev.js +121 -121
- package/src/commands/doctor.js +54 -54
- package/src/commands/init.js +866 -866
- package/src/commands/package.js +68 -68
- package/src/index.js +195 -195
- package/src/lib/context.js +66 -66
- package/src/lib/framework.js +57 -57
- package/src/lib/logger.js +11 -11
- package/src/lib/output.js +234 -234
- package/src/lib/process.js +303 -303
- package/src/lib/project.js +493 -493
- package/src/lib/toolchain.js +62 -62
- package/src/lib/ui.js +244 -244
- package/templates/basic/README.md +15 -15
- package/templates/basic/frontend/README.md +73 -73
- package/templates/basic/frontend/eslint.config.js +23 -23
- package/templates/basic/frontend/index.html +13 -13
- package/templates/basic/frontend/package.json +31 -31
- package/templates/basic/frontend/public/icons.svg +24 -24
- package/templates/basic/frontend/src/App.css +216 -216
- package/templates/basic/frontend/src/App.tsx +77 -77
- package/templates/basic/frontend/src/assets/vite.svg +1 -1
- package/templates/basic/frontend/src/index.css +111 -111
- package/templates/basic/frontend/src/lib/reset.ts +1 -1
- package/templates/basic/frontend/src/main.tsx +10 -10
- package/templates/basic/frontend/tsconfig.app.json +28 -28
- package/templates/basic/frontend/tsconfig.json +7 -7
- package/templates/basic/frontend/tsconfig.node.json +26 -26
- package/templates/basic/frontend/vite.config.ts +16 -16
- package/templates/basic/reset.config.json +58 -58
package/src/lib/project.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "node:fs"
|
|
2
|
-
import { createRequire } from "node:module"
|
|
3
|
-
import path from "node:path"
|
|
4
|
-
import { fileURLToPath } from "node:url"
|
|
5
|
-
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs"
|
|
2
|
+
import { createRequire } from "node:module"
|
|
3
|
+
import path from "node:path"
|
|
4
|
+
import { fileURLToPath } from "node:url"
|
|
5
|
+
|
|
6
6
|
const require = createRequire(import.meta.url)
|
|
7
7
|
|
|
8
8
|
const runtimePackageDescriptors = [
|
|
@@ -31,166 +31,166 @@ const runtimePackageDescriptors = [
|
|
|
31
31
|
binarySegments: ["dist", "win32-x64", "reset-framework.exe"]
|
|
32
32
|
}
|
|
33
33
|
]
|
|
34
|
-
|
|
35
|
-
function requireString(object, key, scope) {
|
|
36
|
-
if (typeof object?.[key] !== "string" || object[key].trim() === "") {
|
|
37
|
-
throw new Error(`Missing or invalid string field '${scope}.${key}'`)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return object[key]
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function optionalString(object, key, fallback) {
|
|
44
|
-
if (object == null || !(key in object)) {
|
|
45
|
-
return fallback
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (typeof object[key] !== "string" || object[key].trim() === "") {
|
|
49
|
-
throw new Error(`Missing or invalid string field '${key}'`)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return object[key]
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function optionalObject(object, key) {
|
|
56
|
-
if (object == null || !(key in object)) {
|
|
57
|
-
return {}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (typeof object[key] !== "object" || object[key] === null || Array.isArray(object[key])) {
|
|
61
|
-
throw new Error(`Missing or invalid object field '${key}'`)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return object[key]
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function sanitizeName(value) {
|
|
68
|
-
return value
|
|
69
|
-
.toLowerCase()
|
|
70
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
71
|
-
.replace(/^-+|-+$/g, "") || "reset-app"
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function normalizeFrontendDir(value) {
|
|
75
|
-
const trimmed = value.trim()
|
|
76
|
-
|
|
77
|
-
if (trimmed === "." || trimmed === "./") {
|
|
78
|
-
return "."
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (path.isAbsolute(trimmed)) {
|
|
82
|
-
throw new Error("project.frontendDir must be a relative path")
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const normalized = path.normalize(trimmed).replace(/\\/g, "/").replace(/\/+$/g, "")
|
|
86
|
-
|
|
87
|
-
if (normalized === "" || normalized === ".") {
|
|
88
|
-
return "."
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (normalized.startsWith("../")) {
|
|
92
|
-
throw new Error("project.frontendDir cannot point outside the app root")
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return normalized
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function normalizeStyling(value) {
|
|
99
|
-
if (value === "css" || value === "tailwindcss") {
|
|
100
|
-
return value
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
throw new Error("project.styling must be either 'css' or 'tailwindcss'")
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function normalizeProtocolScheme(value) {
|
|
107
|
-
if (typeof value !== "string" || value.trim() === "") {
|
|
108
|
-
throw new Error("protocols.schemes[].scheme must be a non-empty string")
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const normalized = value.trim().toLowerCase()
|
|
112
|
-
if (!/^[a-z][a-z0-9+.-]*$/.test(normalized)) {
|
|
113
|
-
throw new Error(
|
|
114
|
-
"protocols.schemes[].scheme must start with a letter and only contain letters, numbers, '+', '-', and '.'"
|
|
115
|
-
)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return normalized
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function normalizeProtocolRole(value) {
|
|
122
|
-
if (value === "Editor" || value === "Viewer" || value === "Shell" || value === "None") {
|
|
123
|
-
return value
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
throw new Error("protocols.schemes[].role must be one of Editor, Viewer, Shell, None")
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function toTitleCase(value) {
|
|
130
|
-
return value
|
|
131
|
-
.split(/[^a-zA-Z0-9]+/)
|
|
132
|
-
.filter(Boolean)
|
|
133
|
-
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
|
134
|
-
.join(" ") || "Reset App"
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function readJsonFile(filePath) {
|
|
138
|
-
return JSON.parse(readFileSync(filePath, "utf8"))
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function fileExists(filePath) {
|
|
142
|
-
return existsSync(filePath)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function getFrameworkBuildType(mode) {
|
|
146
|
-
return mode === "release" ? "Release" : "Debug"
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function resolveExistingCandidate(candidates) {
|
|
150
|
-
return candidates.find((candidate) => existsSync(candidate)) ?? null
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function isPathInside(parentDir, candidatePath) {
|
|
154
|
-
const relative = path.relative(parentDir, candidatePath)
|
|
155
|
-
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative)
|
|
156
|
-
}
|
|
157
|
-
|
|
34
|
+
|
|
35
|
+
function requireString(object, key, scope) {
|
|
36
|
+
if (typeof object?.[key] !== "string" || object[key].trim() === "") {
|
|
37
|
+
throw new Error(`Missing or invalid string field '${scope}.${key}'`)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return object[key]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function optionalString(object, key, fallback) {
|
|
44
|
+
if (object == null || !(key in object)) {
|
|
45
|
+
return fallback
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (typeof object[key] !== "string" || object[key].trim() === "") {
|
|
49
|
+
throw new Error(`Missing or invalid string field '${key}'`)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return object[key]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function optionalObject(object, key) {
|
|
56
|
+
if (object == null || !(key in object)) {
|
|
57
|
+
return {}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (typeof object[key] !== "object" || object[key] === null || Array.isArray(object[key])) {
|
|
61
|
+
throw new Error(`Missing or invalid object field '${key}'`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return object[key]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function sanitizeName(value) {
|
|
68
|
+
return value
|
|
69
|
+
.toLowerCase()
|
|
70
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
71
|
+
.replace(/^-+|-+$/g, "") || "reset-app"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function normalizeFrontendDir(value) {
|
|
75
|
+
const trimmed = value.trim()
|
|
76
|
+
|
|
77
|
+
if (trimmed === "." || trimmed === "./") {
|
|
78
|
+
return "."
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (path.isAbsolute(trimmed)) {
|
|
82
|
+
throw new Error("project.frontendDir must be a relative path")
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const normalized = path.normalize(trimmed).replace(/\\/g, "/").replace(/\/+$/g, "")
|
|
86
|
+
|
|
87
|
+
if (normalized === "" || normalized === ".") {
|
|
88
|
+
return "."
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (normalized.startsWith("../")) {
|
|
92
|
+
throw new Error("project.frontendDir cannot point outside the app root")
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return normalized
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function normalizeStyling(value) {
|
|
99
|
+
if (value === "css" || value === "tailwindcss") {
|
|
100
|
+
return value
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
throw new Error("project.styling must be either 'css' or 'tailwindcss'")
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function normalizeProtocolScheme(value) {
|
|
107
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
108
|
+
throw new Error("protocols.schemes[].scheme must be a non-empty string")
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const normalized = value.trim().toLowerCase()
|
|
112
|
+
if (!/^[a-z][a-z0-9+.-]*$/.test(normalized)) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
"protocols.schemes[].scheme must start with a letter and only contain letters, numbers, '+', '-', and '.'"
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return normalized
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function normalizeProtocolRole(value) {
|
|
122
|
+
if (value === "Editor" || value === "Viewer" || value === "Shell" || value === "None") {
|
|
123
|
+
return value
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
throw new Error("protocols.schemes[].role must be one of Editor, Viewer, Shell, None")
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function toTitleCase(value) {
|
|
130
|
+
return value
|
|
131
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
132
|
+
.filter(Boolean)
|
|
133
|
+
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
|
134
|
+
.join(" ") || "Reset App"
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function readJsonFile(filePath) {
|
|
138
|
+
return JSON.parse(readFileSync(filePath, "utf8"))
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function fileExists(filePath) {
|
|
142
|
+
return existsSync(filePath)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function getFrameworkBuildType(mode) {
|
|
146
|
+
return mode === "release" ? "Release" : "Debug"
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function resolveExistingCandidate(candidates) {
|
|
150
|
+
return candidates.find((candidate) => existsSync(candidate)) ?? null
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function isPathInside(parentDir, candidatePath) {
|
|
154
|
+
const relative = path.relative(parentDir, candidatePath)
|
|
155
|
+
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
158
|
function resolvePackageInfo(packageName, fallbackRoot) {
|
|
159
159
|
try {
|
|
160
|
-
const packageJsonPath = require.resolve(`${packageName}/package.json`)
|
|
161
|
-
const packageRoot = path.dirname(packageJsonPath)
|
|
162
|
-
const manifest = readJsonFile(packageJsonPath)
|
|
163
|
-
|
|
164
|
-
return {
|
|
165
|
-
packageName: manifest.name ?? packageName,
|
|
166
|
-
packageRoot,
|
|
167
|
-
packageJsonPath,
|
|
168
|
-
version: manifest.version ?? "0.0.0",
|
|
169
|
-
localFallback: false
|
|
170
|
-
}
|
|
171
|
-
} catch {
|
|
172
|
-
const packageJsonPath = path.join(fallbackRoot, "package.json")
|
|
173
|
-
const manifest = readJsonFile(packageJsonPath)
|
|
174
|
-
|
|
175
|
-
return {
|
|
176
|
-
packageName: manifest.name ?? packageName,
|
|
177
|
-
packageRoot: fallbackRoot,
|
|
178
|
-
packageJsonPath,
|
|
179
|
-
version: manifest.version ?? "0.0.0",
|
|
180
|
-
localFallback: true
|
|
181
|
-
}
|
|
160
|
+
const packageJsonPath = require.resolve(`${packageName}/package.json`)
|
|
161
|
+
const packageRoot = path.dirname(packageJsonPath)
|
|
162
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
packageName: manifest.name ?? packageName,
|
|
166
|
+
packageRoot,
|
|
167
|
+
packageJsonPath,
|
|
168
|
+
version: manifest.version ?? "0.0.0",
|
|
169
|
+
localFallback: false
|
|
170
|
+
}
|
|
171
|
+
} catch {
|
|
172
|
+
const packageJsonPath = path.join(fallbackRoot, "package.json")
|
|
173
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
packageName: manifest.name ?? packageName,
|
|
177
|
+
packageRoot: fallbackRoot,
|
|
178
|
+
packageJsonPath,
|
|
179
|
+
version: manifest.version ?? "0.0.0",
|
|
180
|
+
localFallback: true
|
|
181
|
+
}
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
function resolveWorkspacePackageInfo(packageName, workspaceRoot, fallbackInfo) {
|
|
186
|
-
const packageJsonPath = path.join(workspaceRoot, "package.json")
|
|
187
|
-
|
|
188
|
-
if (!existsSync(packageJsonPath)) {
|
|
189
|
-
return fallbackInfo
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const manifest = readJsonFile(packageJsonPath)
|
|
193
|
-
|
|
186
|
+
const packageJsonPath = path.join(workspaceRoot, "package.json")
|
|
187
|
+
|
|
188
|
+
if (!existsSync(packageJsonPath)) {
|
|
189
|
+
return fallbackInfo
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
193
|
+
|
|
194
194
|
return {
|
|
195
195
|
packageName: manifest.name ?? packageName,
|
|
196
196
|
packageRoot: workspaceRoot,
|
|
@@ -325,7 +325,7 @@ export function resolveFrameworkPaths() {
|
|
|
325
325
|
"@reset-framework/sdk",
|
|
326
326
|
path.join(packagesDir, "sdk"),
|
|
327
327
|
resolvePackageInfo("@reset-framework/sdk", path.join(packagesDir, "sdk"))
|
|
328
|
-
)
|
|
328
|
+
)
|
|
329
329
|
const schemaPackage = resolveWorkspacePackageInfo(
|
|
330
330
|
"@reset-framework/schema",
|
|
331
331
|
path.join(packagesDir, "schema"),
|
|
@@ -361,58 +361,58 @@ export function resolveFrameworkPaths() {
|
|
|
361
361
|
templatesDir: path.join(cliDir, "templates")
|
|
362
362
|
}
|
|
363
363
|
}
|
|
364
|
-
|
|
364
|
+
|
|
365
365
|
export function resolveFrameworkBuildPaths(appPaths) {
|
|
366
|
-
const frameworkCacheRoot = path.join(appPaths.appRoot, ".reset", "framework")
|
|
367
|
-
const isWindows = process.platform === "win32"
|
|
368
|
-
const devRuntimeRoot = path.join(frameworkCacheRoot, "build", "dev", "runtime")
|
|
369
|
-
const releaseRuntimeRoot = path.join(frameworkCacheRoot, "build", "release", "runtime")
|
|
370
|
-
const devAppBinaryCandidates = isWindows
|
|
371
|
-
? [
|
|
372
|
-
path.join(devRuntimeRoot, getFrameworkBuildType("dev"), "reset-framework.exe"),
|
|
373
|
-
path.join(devRuntimeRoot, "reset-framework.exe")
|
|
374
|
-
]
|
|
375
|
-
: [
|
|
376
|
-
path.join(
|
|
377
|
-
frameworkCacheRoot,
|
|
378
|
-
"build",
|
|
379
|
-
"dev",
|
|
380
|
-
"runtime",
|
|
381
|
-
"reset-framework.app",
|
|
382
|
-
"Contents",
|
|
383
|
-
"MacOS",
|
|
384
|
-
"reset-framework"
|
|
385
|
-
)
|
|
386
|
-
]
|
|
387
|
-
const releaseAppBinaryCandidates = isWindows
|
|
388
|
-
? [
|
|
389
|
-
path.join(releaseRuntimeRoot, getFrameworkBuildType("release"), "reset-framework.exe"),
|
|
390
|
-
path.join(releaseRuntimeRoot, "reset-framework.exe")
|
|
391
|
-
]
|
|
392
|
-
: [
|
|
393
|
-
path.join(
|
|
394
|
-
frameworkCacheRoot,
|
|
395
|
-
"build",
|
|
396
|
-
"release",
|
|
397
|
-
"runtime",
|
|
398
|
-
"reset-framework.app"
|
|
399
|
-
)
|
|
400
|
-
]
|
|
401
|
-
|
|
402
|
-
return {
|
|
403
|
-
frameworkCacheRoot,
|
|
404
|
-
devBuildDir: path.join(frameworkCacheRoot, "build", "dev"),
|
|
405
|
-
releaseBuildDir: path.join(frameworkCacheRoot, "build", "release"),
|
|
406
|
-
devRuntimeOutputCandidates: isWindows
|
|
407
|
-
? [path.join(devRuntimeRoot, getFrameworkBuildType("dev")), devRuntimeRoot]
|
|
408
|
-
: [path.join(frameworkCacheRoot, "build", "dev", "runtime", "reset-framework.app")],
|
|
409
|
-
releaseRuntimeOutputCandidates: isWindows
|
|
410
|
-
? [path.join(releaseRuntimeRoot, getFrameworkBuildType("release")), releaseRuntimeRoot]
|
|
411
|
-
: [path.join(frameworkCacheRoot, "build", "release", "runtime", "reset-framework.app")],
|
|
412
|
-
devAppBinaryCandidates,
|
|
413
|
-
releaseAppBinaryCandidates,
|
|
414
|
-
devAppBinary: devAppBinaryCandidates[0],
|
|
415
|
-
releaseAppTemplate: releaseAppBinaryCandidates[0]
|
|
366
|
+
const frameworkCacheRoot = path.join(appPaths.appRoot, ".reset", "framework")
|
|
367
|
+
const isWindows = process.platform === "win32"
|
|
368
|
+
const devRuntimeRoot = path.join(frameworkCacheRoot, "build", "dev", "runtime")
|
|
369
|
+
const releaseRuntimeRoot = path.join(frameworkCacheRoot, "build", "release", "runtime")
|
|
370
|
+
const devAppBinaryCandidates = isWindows
|
|
371
|
+
? [
|
|
372
|
+
path.join(devRuntimeRoot, getFrameworkBuildType("dev"), "reset-framework.exe"),
|
|
373
|
+
path.join(devRuntimeRoot, "reset-framework.exe")
|
|
374
|
+
]
|
|
375
|
+
: [
|
|
376
|
+
path.join(
|
|
377
|
+
frameworkCacheRoot,
|
|
378
|
+
"build",
|
|
379
|
+
"dev",
|
|
380
|
+
"runtime",
|
|
381
|
+
"reset-framework.app",
|
|
382
|
+
"Contents",
|
|
383
|
+
"MacOS",
|
|
384
|
+
"reset-framework"
|
|
385
|
+
)
|
|
386
|
+
]
|
|
387
|
+
const releaseAppBinaryCandidates = isWindows
|
|
388
|
+
? [
|
|
389
|
+
path.join(releaseRuntimeRoot, getFrameworkBuildType("release"), "reset-framework.exe"),
|
|
390
|
+
path.join(releaseRuntimeRoot, "reset-framework.exe")
|
|
391
|
+
]
|
|
392
|
+
: [
|
|
393
|
+
path.join(
|
|
394
|
+
frameworkCacheRoot,
|
|
395
|
+
"build",
|
|
396
|
+
"release",
|
|
397
|
+
"runtime",
|
|
398
|
+
"reset-framework.app"
|
|
399
|
+
)
|
|
400
|
+
]
|
|
401
|
+
|
|
402
|
+
return {
|
|
403
|
+
frameworkCacheRoot,
|
|
404
|
+
devBuildDir: path.join(frameworkCacheRoot, "build", "dev"),
|
|
405
|
+
releaseBuildDir: path.join(frameworkCacheRoot, "build", "release"),
|
|
406
|
+
devRuntimeOutputCandidates: isWindows
|
|
407
|
+
? [path.join(devRuntimeRoot, getFrameworkBuildType("dev")), devRuntimeRoot]
|
|
408
|
+
: [path.join(frameworkCacheRoot, "build", "dev", "runtime", "reset-framework.app")],
|
|
409
|
+
releaseRuntimeOutputCandidates: isWindows
|
|
410
|
+
? [path.join(releaseRuntimeRoot, getFrameworkBuildType("release")), releaseRuntimeRoot]
|
|
411
|
+
: [path.join(frameworkCacheRoot, "build", "release", "runtime", "reset-framework.app")],
|
|
412
|
+
devAppBinaryCandidates,
|
|
413
|
+
releaseAppBinaryCandidates,
|
|
414
|
+
devAppBinary: devAppBinaryCandidates[0],
|
|
415
|
+
releaseAppTemplate: releaseAppBinaryCandidates[0]
|
|
416
416
|
}
|
|
417
417
|
}
|
|
418
418
|
|
|
@@ -497,15 +497,15 @@ export function resolveFrameworkRuntimeBinary(frameworkPaths, frameworkBuildPath
|
|
|
497
497
|
mode === "release"
|
|
498
498
|
? (frameworkBuildPaths.releaseAppBinaryCandidates ?? [frameworkBuildPaths.releaseAppTemplate])
|
|
499
499
|
: (frameworkBuildPaths.devAppBinaryCandidates ?? [frameworkBuildPaths.devAppBinary])
|
|
500
|
-
const existing = resolveExistingCandidate(candidates)
|
|
501
|
-
|
|
502
|
-
if (existing) {
|
|
503
|
-
return existing
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
if (mustExist) {
|
|
507
|
-
throw new Error(`Missing built runtime executable. Looked in: ${candidates.join(", ")}`)
|
|
508
|
-
}
|
|
500
|
+
const existing = resolveExistingCandidate(candidates)
|
|
501
|
+
|
|
502
|
+
if (existing) {
|
|
503
|
+
return existing
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (mustExist) {
|
|
507
|
+
throw new Error(`Missing built runtime executable. Looked in: ${candidates.join(", ")}`)
|
|
508
|
+
}
|
|
509
509
|
|
|
510
510
|
return candidates[0]
|
|
511
511
|
}
|
|
@@ -530,45 +530,45 @@ export function resolveFrameworkRuntimeOutputDir(frameworkPaths, frameworkBuildP
|
|
|
530
530
|
mode === "release"
|
|
531
531
|
? (frameworkBuildPaths.releaseRuntimeOutputCandidates ?? [])
|
|
532
532
|
: (frameworkBuildPaths.devRuntimeOutputCandidates ?? [])
|
|
533
|
-
const existing = resolveExistingCandidate(candidates)
|
|
534
|
-
|
|
535
|
-
if (existing) {
|
|
536
|
-
return existing
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
if (candidates.length > 0) {
|
|
540
|
-
if (mustExist) {
|
|
541
|
-
throw new Error(`Missing built runtime output directory. Looked in: ${candidates.join(", ")}`)
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
return candidates[0]
|
|
545
|
-
}
|
|
546
|
-
|
|
533
|
+
const existing = resolveExistingCandidate(candidates)
|
|
534
|
+
|
|
535
|
+
if (existing) {
|
|
536
|
+
return existing
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (candidates.length > 0) {
|
|
540
|
+
if (mustExist) {
|
|
541
|
+
throw new Error(`Missing built runtime output directory. Looked in: ${candidates.join(", ")}`)
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
return candidates[0]
|
|
545
|
+
}
|
|
546
|
+
|
|
547
547
|
return path.dirname(resolveFrameworkRuntimeBinary(frameworkPaths, frameworkBuildPaths, mode, options))
|
|
548
548
|
}
|
|
549
|
-
|
|
550
|
-
export function resolveAppPaths(appRoot) {
|
|
551
|
-
return {
|
|
552
|
-
appRoot,
|
|
553
|
-
appPackageJsonPath: path.join(appRoot, "package.json"),
|
|
554
|
-
frontendDir: path.join(appRoot, "frontend"),
|
|
555
|
-
resetConfigPath: path.join(appRoot, "reset.config.json"),
|
|
556
|
-
legacyResetConfigPath: path.join(appRoot, "frontend", "reset.config.json")
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
export function resolveConfigPath(appPaths) {
|
|
561
|
-
if (existsSync(appPaths.resetConfigPath)) {
|
|
562
|
-
return appPaths.resetConfigPath
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
if (existsSync(appPaths.legacyResetConfigPath)) {
|
|
566
|
-
return appPaths.legacyResetConfigPath
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
return appPaths.resetConfigPath
|
|
570
|
-
}
|
|
571
|
-
|
|
549
|
+
|
|
550
|
+
export function resolveAppPaths(appRoot) {
|
|
551
|
+
return {
|
|
552
|
+
appRoot,
|
|
553
|
+
appPackageJsonPath: path.join(appRoot, "package.json"),
|
|
554
|
+
frontendDir: path.join(appRoot, "frontend"),
|
|
555
|
+
resetConfigPath: path.join(appRoot, "reset.config.json"),
|
|
556
|
+
legacyResetConfigPath: path.join(appRoot, "frontend", "reset.config.json")
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
export function resolveConfigPath(appPaths) {
|
|
561
|
+
if (existsSync(appPaths.resetConfigPath)) {
|
|
562
|
+
return appPaths.resetConfigPath
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (existsSync(appPaths.legacyResetConfigPath)) {
|
|
566
|
+
return appPaths.legacyResetConfigPath
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return appPaths.resetConfigPath
|
|
570
|
+
}
|
|
571
|
+
|
|
572
572
|
export function getFrameworkChecks(frameworkPaths) {
|
|
573
573
|
return [
|
|
574
574
|
["sdk", frameworkPaths.sdkPackage.packageJsonPath],
|
|
@@ -657,239 +657,239 @@ export function assertFrameworkSourceInstall(frameworkPaths) {
|
|
|
657
657
|
export function getAppChecks(appPaths) {
|
|
658
658
|
return [["config", resolveConfigPath(appPaths)]]
|
|
659
659
|
}
|
|
660
|
-
|
|
661
|
-
export function assertAppProject(appPaths, config) {
|
|
662
|
-
const checks = [...getAppChecks(appPaths)]
|
|
663
|
-
|
|
664
|
-
if (config) {
|
|
665
|
-
checks.unshift(["frontend", resolveFrontendDir(appPaths, config)])
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
const missing = checks
|
|
669
|
-
.filter(([, filePath]) => !existsSync(filePath))
|
|
670
|
-
.map(([label]) => label)
|
|
671
|
-
|
|
672
|
-
if (missing.length > 0) {
|
|
673
|
-
throw new Error(
|
|
674
|
-
`Current directory does not look like a Reset app. Missing: ${missing.join(", ")}`
|
|
675
|
-
)
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
export function validateResetConfig(rawConfig) {
|
|
680
|
-
const frontend = optionalObject(rawConfig, "frontend")
|
|
681
|
-
const build = optionalObject(rawConfig, "build")
|
|
682
|
-
const project = optionalObject(rawConfig, "project")
|
|
683
|
-
const security = optionalObject(rawConfig, "security")
|
|
684
|
-
const protocols = optionalObject(rawConfig, "protocols")
|
|
685
|
-
const windowConfig = optionalObject(rawConfig, "window")
|
|
686
|
-
const rawProtocolSchemes = Array.isArray(protocols.schemes) ? protocols.schemes : []
|
|
687
|
-
const seenProtocolSchemes = new Set()
|
|
688
|
-
|
|
689
|
-
return {
|
|
690
|
-
...rawConfig,
|
|
691
|
-
name: sanitizeName(requireString(rawConfig, "name", "config")),
|
|
692
|
-
productName: requireString(rawConfig, "productName", "config"),
|
|
693
|
-
appId: requireString(rawConfig, "appId", "config"),
|
|
694
|
-
version: requireString(rawConfig, "version", "config"),
|
|
695
|
-
window: {
|
|
696
|
-
title: optionalString(windowConfig, "title", "Reset App")
|
|
697
|
-
},
|
|
698
|
-
frontend: {
|
|
699
|
-
devUrl: requireString(frontend, "devUrl", "frontend"),
|
|
700
|
-
distDir: optionalString(frontend, "distDir", "dist"),
|
|
701
|
-
entryHtml: optionalString(frontend, "entryHtml", "index.html")
|
|
702
|
-
},
|
|
703
|
-
project: {
|
|
704
|
-
frontendDir: normalizeFrontendDir(optionalString(project, "frontendDir", "frontend")),
|
|
705
|
-
styling: normalizeStyling(optionalString(project, "styling", "css"))
|
|
706
|
-
},
|
|
707
|
-
build: {
|
|
708
|
-
outputDir: optionalString(build, "outputDir", ".reset/build")
|
|
709
|
-
},
|
|
710
|
-
security: {
|
|
711
|
-
permissions: Array.isArray(security.permissions)
|
|
712
|
-
? security.permissions.map((value) => {
|
|
713
|
-
if (typeof value !== "string" || value.trim() === "") {
|
|
714
|
-
throw new Error("Missing or invalid string field 'security.permissions'")
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
return value
|
|
718
|
-
})
|
|
719
|
-
: []
|
|
720
|
-
},
|
|
721
|
-
protocols: {
|
|
722
|
-
schemes: rawProtocolSchemes.map((entry) => {
|
|
723
|
-
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
724
|
-
throw new Error("protocols.schemes entries must be objects")
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
const scheme = normalizeProtocolScheme(entry.scheme)
|
|
728
|
-
if (seenProtocolSchemes.has(scheme)) {
|
|
729
|
-
throw new Error(`Duplicate protocol scheme '${scheme}'`)
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
seenProtocolSchemes.add(scheme)
|
|
733
|
-
|
|
734
|
-
return {
|
|
735
|
-
scheme,
|
|
736
|
-
name:
|
|
737
|
-
typeof entry.name === "string" && entry.name.trim() !== ""
|
|
738
|
-
? entry.name
|
|
739
|
-
: scheme,
|
|
740
|
-
role:
|
|
741
|
-
entry.role === undefined
|
|
742
|
-
? "Viewer"
|
|
743
|
-
: normalizeProtocolRole(entry.role)
|
|
744
|
-
}
|
|
745
|
-
})
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
export function loadResetConfig(appPaths) {
|
|
751
|
-
const configPath = resolveConfigPath(appPaths)
|
|
752
|
-
const raw = readFileSync(configPath, "utf8")
|
|
753
|
-
|
|
754
|
-
try {
|
|
755
|
-
return validateResetConfig(JSON.parse(raw))
|
|
756
|
-
} catch (error) {
|
|
757
|
-
if (error instanceof SyntaxError) {
|
|
758
|
-
throw new Error(`Invalid JSON in ${configPath}: ${error.message}`)
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
throw error
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
export function resolveAppOutputPaths(appPaths, config) {
|
|
766
|
-
const outputRoot = path.resolve(appPaths.appRoot, config.build.outputDir)
|
|
767
|
-
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
768
|
-
const isWindows = process.platform === "win32"
|
|
769
|
-
const appBundleName = isWindows ? config.productName : `${config.productName}.app`
|
|
770
|
-
const platformDir = path.join(outputRoot, isWindows ? "windows" : "macos")
|
|
771
|
-
const appBundlePath = path.join(platformDir, appBundleName)
|
|
772
|
-
const resourcesDir = isWindows
|
|
773
|
-
? path.join(appBundlePath, "resources")
|
|
774
|
-
: path.join(appBundlePath, "Contents", "Resources")
|
|
775
|
-
const packagesDir = path.join(outputRoot, "packages")
|
|
776
|
-
|
|
777
|
-
return {
|
|
778
|
-
outputRoot,
|
|
779
|
-
macosDir: isWindows ? undefined : platformDir,
|
|
780
|
-
windowsDir: isWindows ? platformDir : undefined,
|
|
781
|
-
appBundlePath,
|
|
782
|
-
appExecutablePath: isWindows
|
|
783
|
-
? path.join(appBundlePath, `${config.productName}.exe`)
|
|
784
|
-
: undefined,
|
|
785
|
-
resourcesDir,
|
|
786
|
-
bundledConfigPath: path.join(resourcesDir, "reset.config.json"),
|
|
787
|
-
bundledFrontendDir: path.join(resourcesDir, config.frontend.distDir),
|
|
788
|
-
frontendDistDir: path.resolve(frontendDir, config.frontend.distDir),
|
|
789
|
-
frontendEntryFile: path.resolve(
|
|
790
|
-
frontendDir,
|
|
791
|
-
config.frontend.distDir,
|
|
792
|
-
config.frontend.entryHtml
|
|
793
|
-
),
|
|
794
|
-
packagesDir,
|
|
795
|
-
zipPath: path.join(packagesDir, `${config.name}-${isWindows ? "windows" : "macos"}.zip`)
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
export function resolveFrontendDir(appPaths, config) {
|
|
800
|
-
return path.resolve(appPaths.appRoot, config.project.frontendDir)
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
export function resolveDevServerOptions(config) {
|
|
804
|
-
const url = new URL(config.frontend.devUrl)
|
|
805
|
-
|
|
806
|
-
return {
|
|
807
|
-
host: url.hostname,
|
|
808
|
-
port: url.port || "5173",
|
|
809
|
-
url: url.toString()
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
export function makeAppMetadata(appName) {
|
|
814
|
-
const name = sanitizeName(appName)
|
|
815
|
-
const productName = toTitleCase(appName)
|
|
816
|
-
|
|
817
|
-
return {
|
|
818
|
-
name,
|
|
819
|
-
productName,
|
|
820
|
-
appId: `com.example.${name}`,
|
|
821
|
-
title: productName
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
export function resolveSdkDependencySpec(frameworkPaths) {
|
|
826
|
-
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.sdkPackage.localFallback) {
|
|
827
|
-
return `file:${frameworkPaths.sdkPackage.packageRoot}`
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
return `^${frameworkPaths.sdkPackage.version}`
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
export function resolveCliDependencySpec(frameworkPaths) {
|
|
834
|
-
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.cliPackage.localFallback) {
|
|
835
|
-
return `file:${frameworkPaths.cliPackage.packageRoot}`
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
return `^${frameworkPaths.cliPackage.version}`
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
function detectPackageManagerFromManifest(packageJsonPath) {
|
|
842
|
-
if (!fileExists(packageJsonPath)) {
|
|
843
|
-
return null
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
const manifest = readJsonFile(packageJsonPath)
|
|
847
|
-
const raw = typeof manifest.packageManager === "string" ? manifest.packageManager.trim() : ""
|
|
848
|
-
if (raw === "") {
|
|
849
|
-
return null
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
const [name] = raw.split("@")
|
|
853
|
-
if (name === "npm" || name === "pnpm" || name === "yarn" || name === "bun") {
|
|
854
|
-
return name
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
return null
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
function detectPackageManagerFromLocks(directory) {
|
|
861
|
-
if (!fileExists(directory)) {
|
|
862
|
-
return null
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
if (fileExists(path.join(directory, "bun.lock")) || fileExists(path.join(directory, "bun.lockb"))) {
|
|
866
|
-
return "bun"
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
if (fileExists(path.join(directory, "pnpm-lock.yaml"))) {
|
|
870
|
-
return "pnpm"
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
if (fileExists(path.join(directory, "yarn.lock"))) {
|
|
874
|
-
return "yarn"
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
if (fileExists(path.join(directory, "package-lock.json"))) {
|
|
878
|
-
return "npm"
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
return null
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
export function resolveAppPackageManager(appPaths, config) {
|
|
885
|
-
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
886
|
-
const frontendPackageJsonPath = path.join(frontendDir, "package.json")
|
|
887
|
-
|
|
888
|
-
return (
|
|
889
|
-
detectPackageManagerFromManifest(appPaths.appPackageJsonPath) ??
|
|
890
|
-
detectPackageManagerFromManifest(frontendPackageJsonPath) ??
|
|
891
|
-
detectPackageManagerFromLocks(appPaths.appRoot) ??
|
|
892
|
-
detectPackageManagerFromLocks(frontendDir) ??
|
|
893
|
-
"npm"
|
|
894
|
-
)
|
|
895
|
-
}
|
|
660
|
+
|
|
661
|
+
export function assertAppProject(appPaths, config) {
|
|
662
|
+
const checks = [...getAppChecks(appPaths)]
|
|
663
|
+
|
|
664
|
+
if (config) {
|
|
665
|
+
checks.unshift(["frontend", resolveFrontendDir(appPaths, config)])
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
const missing = checks
|
|
669
|
+
.filter(([, filePath]) => !existsSync(filePath))
|
|
670
|
+
.map(([label]) => label)
|
|
671
|
+
|
|
672
|
+
if (missing.length > 0) {
|
|
673
|
+
throw new Error(
|
|
674
|
+
`Current directory does not look like a Reset app. Missing: ${missing.join(", ")}`
|
|
675
|
+
)
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
export function validateResetConfig(rawConfig) {
|
|
680
|
+
const frontend = optionalObject(rawConfig, "frontend")
|
|
681
|
+
const build = optionalObject(rawConfig, "build")
|
|
682
|
+
const project = optionalObject(rawConfig, "project")
|
|
683
|
+
const security = optionalObject(rawConfig, "security")
|
|
684
|
+
const protocols = optionalObject(rawConfig, "protocols")
|
|
685
|
+
const windowConfig = optionalObject(rawConfig, "window")
|
|
686
|
+
const rawProtocolSchemes = Array.isArray(protocols.schemes) ? protocols.schemes : []
|
|
687
|
+
const seenProtocolSchemes = new Set()
|
|
688
|
+
|
|
689
|
+
return {
|
|
690
|
+
...rawConfig,
|
|
691
|
+
name: sanitizeName(requireString(rawConfig, "name", "config")),
|
|
692
|
+
productName: requireString(rawConfig, "productName", "config"),
|
|
693
|
+
appId: requireString(rawConfig, "appId", "config"),
|
|
694
|
+
version: requireString(rawConfig, "version", "config"),
|
|
695
|
+
window: {
|
|
696
|
+
title: optionalString(windowConfig, "title", "Reset App")
|
|
697
|
+
},
|
|
698
|
+
frontend: {
|
|
699
|
+
devUrl: requireString(frontend, "devUrl", "frontend"),
|
|
700
|
+
distDir: optionalString(frontend, "distDir", "dist"),
|
|
701
|
+
entryHtml: optionalString(frontend, "entryHtml", "index.html")
|
|
702
|
+
},
|
|
703
|
+
project: {
|
|
704
|
+
frontendDir: normalizeFrontendDir(optionalString(project, "frontendDir", "frontend")),
|
|
705
|
+
styling: normalizeStyling(optionalString(project, "styling", "css"))
|
|
706
|
+
},
|
|
707
|
+
build: {
|
|
708
|
+
outputDir: optionalString(build, "outputDir", ".reset/build")
|
|
709
|
+
},
|
|
710
|
+
security: {
|
|
711
|
+
permissions: Array.isArray(security.permissions)
|
|
712
|
+
? security.permissions.map((value) => {
|
|
713
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
714
|
+
throw new Error("Missing or invalid string field 'security.permissions'")
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
return value
|
|
718
|
+
})
|
|
719
|
+
: []
|
|
720
|
+
},
|
|
721
|
+
protocols: {
|
|
722
|
+
schemes: rawProtocolSchemes.map((entry) => {
|
|
723
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
724
|
+
throw new Error("protocols.schemes entries must be objects")
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
const scheme = normalizeProtocolScheme(entry.scheme)
|
|
728
|
+
if (seenProtocolSchemes.has(scheme)) {
|
|
729
|
+
throw new Error(`Duplicate protocol scheme '${scheme}'`)
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
seenProtocolSchemes.add(scheme)
|
|
733
|
+
|
|
734
|
+
return {
|
|
735
|
+
scheme,
|
|
736
|
+
name:
|
|
737
|
+
typeof entry.name === "string" && entry.name.trim() !== ""
|
|
738
|
+
? entry.name
|
|
739
|
+
: scheme,
|
|
740
|
+
role:
|
|
741
|
+
entry.role === undefined
|
|
742
|
+
? "Viewer"
|
|
743
|
+
: normalizeProtocolRole(entry.role)
|
|
744
|
+
}
|
|
745
|
+
})
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
export function loadResetConfig(appPaths) {
|
|
751
|
+
const configPath = resolveConfigPath(appPaths)
|
|
752
|
+
const raw = readFileSync(configPath, "utf8")
|
|
753
|
+
|
|
754
|
+
try {
|
|
755
|
+
return validateResetConfig(JSON.parse(raw))
|
|
756
|
+
} catch (error) {
|
|
757
|
+
if (error instanceof SyntaxError) {
|
|
758
|
+
throw new Error(`Invalid JSON in ${configPath}: ${error.message}`)
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
throw error
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
export function resolveAppOutputPaths(appPaths, config) {
|
|
766
|
+
const outputRoot = path.resolve(appPaths.appRoot, config.build.outputDir)
|
|
767
|
+
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
768
|
+
const isWindows = process.platform === "win32"
|
|
769
|
+
const appBundleName = isWindows ? config.productName : `${config.productName}.app`
|
|
770
|
+
const platformDir = path.join(outputRoot, isWindows ? "windows" : "macos")
|
|
771
|
+
const appBundlePath = path.join(platformDir, appBundleName)
|
|
772
|
+
const resourcesDir = isWindows
|
|
773
|
+
? path.join(appBundlePath, "resources")
|
|
774
|
+
: path.join(appBundlePath, "Contents", "Resources")
|
|
775
|
+
const packagesDir = path.join(outputRoot, "packages")
|
|
776
|
+
|
|
777
|
+
return {
|
|
778
|
+
outputRoot,
|
|
779
|
+
macosDir: isWindows ? undefined : platformDir,
|
|
780
|
+
windowsDir: isWindows ? platformDir : undefined,
|
|
781
|
+
appBundlePath,
|
|
782
|
+
appExecutablePath: isWindows
|
|
783
|
+
? path.join(appBundlePath, `${config.productName}.exe`)
|
|
784
|
+
: undefined,
|
|
785
|
+
resourcesDir,
|
|
786
|
+
bundledConfigPath: path.join(resourcesDir, "reset.config.json"),
|
|
787
|
+
bundledFrontendDir: path.join(resourcesDir, config.frontend.distDir),
|
|
788
|
+
frontendDistDir: path.resolve(frontendDir, config.frontend.distDir),
|
|
789
|
+
frontendEntryFile: path.resolve(
|
|
790
|
+
frontendDir,
|
|
791
|
+
config.frontend.distDir,
|
|
792
|
+
config.frontend.entryHtml
|
|
793
|
+
),
|
|
794
|
+
packagesDir,
|
|
795
|
+
zipPath: path.join(packagesDir, `${config.name}-${isWindows ? "windows" : "macos"}.zip`)
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
export function resolveFrontendDir(appPaths, config) {
|
|
800
|
+
return path.resolve(appPaths.appRoot, config.project.frontendDir)
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
export function resolveDevServerOptions(config) {
|
|
804
|
+
const url = new URL(config.frontend.devUrl)
|
|
805
|
+
|
|
806
|
+
return {
|
|
807
|
+
host: url.hostname,
|
|
808
|
+
port: url.port || "5173",
|
|
809
|
+
url: url.toString()
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
export function makeAppMetadata(appName) {
|
|
814
|
+
const name = sanitizeName(appName)
|
|
815
|
+
const productName = toTitleCase(appName)
|
|
816
|
+
|
|
817
|
+
return {
|
|
818
|
+
name,
|
|
819
|
+
productName,
|
|
820
|
+
appId: `com.example.${name}`,
|
|
821
|
+
title: productName
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
export function resolveSdkDependencySpec(frameworkPaths) {
|
|
826
|
+
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.sdkPackage.localFallback) {
|
|
827
|
+
return `file:${frameworkPaths.sdkPackage.packageRoot}`
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
return `^${frameworkPaths.sdkPackage.version}`
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
export function resolveCliDependencySpec(frameworkPaths) {
|
|
834
|
+
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.cliPackage.localFallback) {
|
|
835
|
+
return `file:${frameworkPaths.cliPackage.packageRoot}`
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
return `^${frameworkPaths.cliPackage.version}`
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
function detectPackageManagerFromManifest(packageJsonPath) {
|
|
842
|
+
if (!fileExists(packageJsonPath)) {
|
|
843
|
+
return null
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
847
|
+
const raw = typeof manifest.packageManager === "string" ? manifest.packageManager.trim() : ""
|
|
848
|
+
if (raw === "") {
|
|
849
|
+
return null
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
const [name] = raw.split("@")
|
|
853
|
+
if (name === "npm" || name === "pnpm" || name === "yarn" || name === "bun") {
|
|
854
|
+
return name
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
return null
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
function detectPackageManagerFromLocks(directory) {
|
|
861
|
+
if (!fileExists(directory)) {
|
|
862
|
+
return null
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
if (fileExists(path.join(directory, "bun.lock")) || fileExists(path.join(directory, "bun.lockb"))) {
|
|
866
|
+
return "bun"
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
if (fileExists(path.join(directory, "pnpm-lock.yaml"))) {
|
|
870
|
+
return "pnpm"
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
if (fileExists(path.join(directory, "yarn.lock"))) {
|
|
874
|
+
return "yarn"
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
if (fileExists(path.join(directory, "package-lock.json"))) {
|
|
878
|
+
return "npm"
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
return null
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
export function resolveAppPackageManager(appPaths, config) {
|
|
885
|
+
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
886
|
+
const frontendPackageJsonPath = path.join(frontendDir, "package.json")
|
|
887
|
+
|
|
888
|
+
return (
|
|
889
|
+
detectPackageManagerFromManifest(appPaths.appPackageJsonPath) ??
|
|
890
|
+
detectPackageManagerFromManifest(frontendPackageJsonPath) ??
|
|
891
|
+
detectPackageManagerFromLocks(appPaths.appRoot) ??
|
|
892
|
+
detectPackageManagerFromLocks(frontendDir) ??
|
|
893
|
+
"npm"
|
|
894
|
+
)
|
|
895
|
+
}
|