reset-framework-cli 1.1.2 → 1.1.5
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 +47 -47
- package/package.json +4 -4
- package/src/commands/build.js +114 -113
- package/src/commands/dev.js +148 -144
- package/src/commands/doctor.js +89 -89
- package/src/commands/init.js +838 -903
- package/src/commands/package.js +49 -44
- package/src/index.js +213 -213
- package/src/lib/context.js +66 -66
- package/src/lib/framework.js +150 -28
- package/src/lib/logger.js +11 -11
- package/src/lib/output.js +214 -106
- package/src/lib/process.js +253 -156
- package/src/lib/project.js +559 -475
- 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 -138
- package/templates/basic/frontend/src/App.tsx +77 -76
- 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,112 +1,112 @@
|
|
|
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
|
-
const require = createRequire(import.meta.url)
|
|
7
|
-
|
|
8
|
-
function requireString(object, key, scope) {
|
|
9
|
-
if (typeof object?.[key] !== "string" || object[key].trim() === "") {
|
|
10
|
-
throw new Error(`Missing or invalid string field '${scope}.${key}'`)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return object[key]
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function optionalString(object, key, fallback) {
|
|
17
|
-
if (object == null || !(key in object)) {
|
|
18
|
-
return fallback
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (typeof object[key] !== "string" || object[key].trim() === "") {
|
|
22
|
-
throw new Error(`Missing or invalid string field '${key}'`)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return object[key]
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function optionalObject(object, key) {
|
|
29
|
-
if (object == null || !(key in object)) {
|
|
30
|
-
return {}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (typeof object[key] !== "object" || object[key] === null || Array.isArray(object[key])) {
|
|
34
|
-
throw new Error(`Missing or invalid object field '${key}'`)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return object[key]
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function sanitizeName(value) {
|
|
41
|
-
return value
|
|
42
|
-
.toLowerCase()
|
|
43
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
44
|
-
.replace(/^-+|-+$/g, "") || "reset-app"
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function normalizeFrontendDir(value) {
|
|
48
|
-
const trimmed = value.trim()
|
|
49
|
-
|
|
50
|
-
if (trimmed === "." || trimmed === "./") {
|
|
51
|
-
return "."
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (path.isAbsolute(trimmed)) {
|
|
55
|
-
throw new Error("project.frontendDir must be a relative path")
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const normalized = path.normalize(trimmed).replace(/\\/g, "/").replace(/\/+$/g, "")
|
|
59
|
-
|
|
60
|
-
if (normalized === "" || normalized === ".") {
|
|
61
|
-
return "."
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (normalized.startsWith("../")) {
|
|
65
|
-
throw new Error("project.frontendDir cannot point outside the app root")
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return normalized
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function normalizeStyling(value) {
|
|
72
|
-
if (value === "css" || value === "tailwindcss") {
|
|
73
|
-
return value
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
throw new Error("project.styling must be either 'css' or 'tailwindcss'")
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function normalizeProtocolScheme(value) {
|
|
80
|
-
if (typeof value !== "string" || value.trim() === "") {
|
|
81
|
-
throw new Error("protocols.schemes[].scheme must be a non-empty string")
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const normalized = value.trim().toLowerCase()
|
|
85
|
-
if (!/^[a-z][a-z0-9+.-]*$/.test(normalized)) {
|
|
86
|
-
throw new Error(
|
|
87
|
-
"protocols.schemes[].scheme must start with a letter and only contain letters, numbers, '+', '-', and '.'"
|
|
88
|
-
)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return normalized
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function normalizeProtocolRole(value) {
|
|
95
|
-
if (value === "Editor" || value === "Viewer" || value === "Shell" || value === "None") {
|
|
96
|
-
return value
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
throw new Error("protocols.schemes[].role must be one of Editor, Viewer, Shell, None")
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function toTitleCase(value) {
|
|
103
|
-
return value
|
|
104
|
-
.split(/[^a-zA-Z0-9]+/)
|
|
105
|
-
.filter(Boolean)
|
|
106
|
-
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
|
107
|
-
.join(" ") || "Reset App"
|
|
108
|
-
}
|
|
109
|
-
|
|
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
|
+
const require = createRequire(import.meta.url)
|
|
7
|
+
|
|
8
|
+
function requireString(object, key, scope) {
|
|
9
|
+
if (typeof object?.[key] !== "string" || object[key].trim() === "") {
|
|
10
|
+
throw new Error(`Missing or invalid string field '${scope}.${key}'`)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return object[key]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function optionalString(object, key, fallback) {
|
|
17
|
+
if (object == null || !(key in object)) {
|
|
18
|
+
return fallback
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (typeof object[key] !== "string" || object[key].trim() === "") {
|
|
22
|
+
throw new Error(`Missing or invalid string field '${key}'`)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return object[key]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function optionalObject(object, key) {
|
|
29
|
+
if (object == null || !(key in object)) {
|
|
30
|
+
return {}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (typeof object[key] !== "object" || object[key] === null || Array.isArray(object[key])) {
|
|
34
|
+
throw new Error(`Missing or invalid object field '${key}'`)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return object[key]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function sanitizeName(value) {
|
|
41
|
+
return value
|
|
42
|
+
.toLowerCase()
|
|
43
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
44
|
+
.replace(/^-+|-+$/g, "") || "reset-app"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function normalizeFrontendDir(value) {
|
|
48
|
+
const trimmed = value.trim()
|
|
49
|
+
|
|
50
|
+
if (trimmed === "." || trimmed === "./") {
|
|
51
|
+
return "."
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (path.isAbsolute(trimmed)) {
|
|
55
|
+
throw new Error("project.frontendDir must be a relative path")
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const normalized = path.normalize(trimmed).replace(/\\/g, "/").replace(/\/+$/g, "")
|
|
59
|
+
|
|
60
|
+
if (normalized === "" || normalized === ".") {
|
|
61
|
+
return "."
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (normalized.startsWith("../")) {
|
|
65
|
+
throw new Error("project.frontendDir cannot point outside the app root")
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return normalized
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function normalizeStyling(value) {
|
|
72
|
+
if (value === "css" || value === "tailwindcss") {
|
|
73
|
+
return value
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
throw new Error("project.styling must be either 'css' or 'tailwindcss'")
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function normalizeProtocolScheme(value) {
|
|
80
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
81
|
+
throw new Error("protocols.schemes[].scheme must be a non-empty string")
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const normalized = value.trim().toLowerCase()
|
|
85
|
+
if (!/^[a-z][a-z0-9+.-]*$/.test(normalized)) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
"protocols.schemes[].scheme must start with a letter and only contain letters, numbers, '+', '-', and '.'"
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return normalized
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function normalizeProtocolRole(value) {
|
|
95
|
+
if (value === "Editor" || value === "Viewer" || value === "Shell" || value === "None") {
|
|
96
|
+
return value
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
throw new Error("protocols.schemes[].role must be one of Editor, Viewer, Shell, None")
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function toTitleCase(value) {
|
|
103
|
+
return value
|
|
104
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
105
|
+
.filter(Boolean)
|
|
106
|
+
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
|
107
|
+
.join(" ") || "Reset App"
|
|
108
|
+
}
|
|
109
|
+
|
|
110
110
|
function readJsonFile(filePath) {
|
|
111
111
|
return JSON.parse(readFileSync(filePath, "utf8"))
|
|
112
112
|
}
|
|
@@ -115,406 +115,490 @@ function fileExists(filePath) {
|
|
|
115
115
|
return existsSync(filePath)
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
function
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
)
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
"@reset-framework/
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
118
|
+
function getFrameworkBuildType(mode) {
|
|
119
|
+
return mode === "release" ? "Release" : "Debug"
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function resolveExistingCandidate(candidates) {
|
|
123
|
+
return candidates.find((candidate) => existsSync(candidate)) ?? null
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function isPathInside(parentDir, candidatePath) {
|
|
127
|
+
const relative = path.relative(parentDir, candidatePath)
|
|
128
|
+
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function resolvePackageInfo(packageName, fallbackRoot) {
|
|
132
|
+
try {
|
|
133
|
+
const packageJsonPath = require.resolve(`${packageName}/package.json`)
|
|
134
|
+
const packageRoot = path.dirname(packageJsonPath)
|
|
135
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
packageName: manifest.name ?? packageName,
|
|
139
|
+
packageRoot,
|
|
140
|
+
packageJsonPath,
|
|
141
|
+
version: manifest.version ?? "0.0.0",
|
|
142
|
+
localFallback: false
|
|
143
|
+
}
|
|
144
|
+
} catch {
|
|
145
|
+
const packageJsonPath = path.join(fallbackRoot, "package.json")
|
|
146
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
packageName: manifest.name ?? packageName,
|
|
150
|
+
packageRoot: fallbackRoot,
|
|
151
|
+
packageJsonPath,
|
|
152
|
+
version: manifest.version ?? "0.0.0",
|
|
153
|
+
localFallback: true
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function resolveWorkspacePackageInfo(packageName, workspaceRoot, fallbackInfo) {
|
|
159
|
+
const packageJsonPath = path.join(workspaceRoot, "package.json")
|
|
160
|
+
|
|
161
|
+
if (!existsSync(packageJsonPath)) {
|
|
162
|
+
return fallbackInfo
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
packageName: manifest.name ?? packageName,
|
|
169
|
+
packageRoot: workspaceRoot,
|
|
170
|
+
packageJsonPath,
|
|
171
|
+
version: manifest.version ?? fallbackInfo.version,
|
|
172
|
+
localFallback: true
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function resolveFrameworkPaths() {
|
|
177
|
+
const moduleDir = path.dirname(fileURLToPath(import.meta.url))
|
|
178
|
+
const cliDir = path.resolve(moduleDir, "../..")
|
|
179
|
+
const packagesDir = path.resolve(cliDir, "..")
|
|
180
|
+
const cliPackageJsonPath = path.join(cliDir, "package.json")
|
|
181
|
+
const cliManifest = readJsonFile(cliPackageJsonPath)
|
|
182
|
+
const nativePackage = resolveWorkspacePackageInfo(
|
|
183
|
+
"@reset-framework/native",
|
|
184
|
+
path.join(packagesDir, "native"),
|
|
185
|
+
resolvePackageInfo("@reset-framework/native", path.join(packagesDir, "native"))
|
|
186
|
+
)
|
|
187
|
+
const sdkPackage = resolveWorkspacePackageInfo(
|
|
188
|
+
"@reset-framework/sdk",
|
|
189
|
+
path.join(packagesDir, "sdk"),
|
|
190
|
+
resolvePackageInfo("@reset-framework/sdk", path.join(packagesDir, "sdk"))
|
|
191
|
+
)
|
|
192
|
+
const schemaPackage = resolveWorkspacePackageInfo(
|
|
193
|
+
"@reset-framework/schema",
|
|
194
|
+
path.join(packagesDir, "schema"),
|
|
195
|
+
resolvePackageInfo("@reset-framework/schema", path.join(packagesDir, "schema"))
|
|
196
|
+
)
|
|
197
|
+
const isWorkspaceLayout = [nativePackage, sdkPackage, schemaPackage].every((pkg) =>
|
|
198
|
+
isPathInside(packagesDir, pkg.packageRoot)
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
cliDir,
|
|
203
|
+
cliPackage: {
|
|
204
|
+
packageName: cliManifest.name,
|
|
205
|
+
packageRoot: cliDir,
|
|
206
|
+
packageJsonPath: cliPackageJsonPath,
|
|
207
|
+
version: cliManifest.version ?? "0.0.0",
|
|
208
|
+
localFallback: true
|
|
209
|
+
},
|
|
210
|
+
packagesDir,
|
|
211
|
+
frameworkRoot: nativePackage.packageRoot,
|
|
212
|
+
frameworkPackage: nativePackage,
|
|
213
|
+
isWorkspaceLayout,
|
|
214
|
+
sdkPackage,
|
|
215
|
+
schemaPackage,
|
|
216
|
+
runtimeDir: path.join(nativePackage.packageRoot, "runtime"),
|
|
217
|
+
rootCMakePath: path.join(nativePackage.packageRoot, "CMakeLists.txt"),
|
|
218
|
+
cmakePresetsPath: path.join(nativePackage.packageRoot, "CMakePresets.json"),
|
|
219
|
+
vcpkgManifestPath: path.join(nativePackage.packageRoot, "vcpkg.json"),
|
|
220
|
+
templatesDir: path.join(cliDir, "templates"),
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
216
224
|
export function resolveFrameworkBuildPaths(appPaths) {
|
|
217
225
|
const frameworkCacheRoot = path.join(appPaths.appRoot, ".reset", "framework")
|
|
226
|
+
const isWindows = process.platform === "win32"
|
|
227
|
+
const devRuntimeRoot = path.join(frameworkCacheRoot, "build", "dev", "runtime")
|
|
228
|
+
const releaseRuntimeRoot = path.join(frameworkCacheRoot, "build", "release", "runtime")
|
|
229
|
+
const devAppBinaryCandidates = isWindows
|
|
230
|
+
? [
|
|
231
|
+
path.join(devRuntimeRoot, getFrameworkBuildType("dev"), "reset-framework.exe"),
|
|
232
|
+
path.join(devRuntimeRoot, "reset-framework.exe")
|
|
233
|
+
]
|
|
234
|
+
: [
|
|
235
|
+
path.join(
|
|
236
|
+
frameworkCacheRoot,
|
|
237
|
+
"build",
|
|
238
|
+
"dev",
|
|
239
|
+
"runtime",
|
|
240
|
+
"reset-framework.app",
|
|
241
|
+
"Contents",
|
|
242
|
+
"MacOS",
|
|
243
|
+
"reset-framework"
|
|
244
|
+
)
|
|
245
|
+
]
|
|
246
|
+
const releaseAppBinaryCandidates = isWindows
|
|
247
|
+
? [
|
|
248
|
+
path.join(releaseRuntimeRoot, getFrameworkBuildType("release"), "reset-framework.exe"),
|
|
249
|
+
path.join(releaseRuntimeRoot, "reset-framework.exe")
|
|
250
|
+
]
|
|
251
|
+
: [
|
|
252
|
+
path.join(
|
|
253
|
+
frameworkCacheRoot,
|
|
254
|
+
"build",
|
|
255
|
+
"release",
|
|
256
|
+
"runtime",
|
|
257
|
+
"reset-framework.app"
|
|
258
|
+
)
|
|
259
|
+
]
|
|
218
260
|
|
|
219
261
|
return {
|
|
220
262
|
frameworkCacheRoot,
|
|
221
263
|
devBuildDir: path.join(frameworkCacheRoot, "build", "dev"),
|
|
222
264
|
releaseBuildDir: path.join(frameworkCacheRoot, "build", "release"),
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
"build",
|
|
226
|
-
|
|
227
|
-
"
|
|
228
|
-
"reset-framework.app",
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
releaseAppTemplate: path.join(
|
|
234
|
-
frameworkCacheRoot,
|
|
235
|
-
"build",
|
|
236
|
-
"release",
|
|
237
|
-
"runtime",
|
|
238
|
-
"reset-framework.app"
|
|
239
|
-
)
|
|
265
|
+
devRuntimeOutputCandidates: isWindows
|
|
266
|
+
? [path.join(devRuntimeRoot, getFrameworkBuildType("dev")), devRuntimeRoot]
|
|
267
|
+
: [path.join(frameworkCacheRoot, "build", "dev", "runtime", "reset-framework.app")],
|
|
268
|
+
releaseRuntimeOutputCandidates: isWindows
|
|
269
|
+
? [path.join(releaseRuntimeRoot, getFrameworkBuildType("release")), releaseRuntimeRoot]
|
|
270
|
+
: [path.join(frameworkCacheRoot, "build", "release", "runtime", "reset-framework.app")],
|
|
271
|
+
devAppBinaryCandidates,
|
|
272
|
+
releaseAppBinaryCandidates,
|
|
273
|
+
devAppBinary: devAppBinaryCandidates[0],
|
|
274
|
+
releaseAppTemplate: releaseAppBinaryCandidates[0]
|
|
240
275
|
}
|
|
241
276
|
}
|
|
242
277
|
|
|
243
|
-
export function
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
251
|
-
}
|
|
278
|
+
export function resolveFrameworkRuntimeBinary(frameworkBuildPaths, mode, options = {}) {
|
|
279
|
+
const { mustExist = false } = options
|
|
280
|
+
const candidates =
|
|
281
|
+
mode === "release"
|
|
282
|
+
? (frameworkBuildPaths.releaseAppBinaryCandidates ?? [frameworkBuildPaths.releaseAppTemplate])
|
|
283
|
+
: (frameworkBuildPaths.devAppBinaryCandidates ?? [frameworkBuildPaths.devAppBinary])
|
|
284
|
+
const existing = resolveExistingCandidate(candidates)
|
|
252
285
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
return appPaths.resetConfigPath
|
|
286
|
+
if (existing) {
|
|
287
|
+
return existing
|
|
256
288
|
}
|
|
257
289
|
|
|
258
|
-
if (
|
|
259
|
-
|
|
290
|
+
if (mustExist) {
|
|
291
|
+
throw new Error(`Missing built runtime executable. Looked in: ${candidates.join(", ")}`)
|
|
260
292
|
}
|
|
261
293
|
|
|
262
|
-
return
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
export function getFrameworkChecks(frameworkPaths) {
|
|
266
|
-
return [
|
|
267
|
-
["native", frameworkPaths.frameworkPackage.packageJsonPath],
|
|
268
|
-
["sdk", frameworkPaths.sdkPackage.packageJsonPath],
|
|
269
|
-
["schema", frameworkPaths.schemaPackage.packageJsonPath],
|
|
270
|
-
["cmake", frameworkPaths.rootCMakePath],
|
|
271
|
-
["runtime", frameworkPaths.runtimeDir],
|
|
272
|
-
["vcpkg", frameworkPaths.vcpkgManifestPath],
|
|
273
|
-
["templates", frameworkPaths.templatesDir]
|
|
274
|
-
]
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
export function getAppChecks(appPaths) {
|
|
278
|
-
return [["config", resolveConfigPath(appPaths)]]
|
|
294
|
+
return candidates[0]
|
|
279
295
|
}
|
|
280
296
|
|
|
281
|
-
export function
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
297
|
+
export function resolveFrameworkRuntimeOutputDir(frameworkBuildPaths, mode, options = {}) {
|
|
298
|
+
const { mustExist = false } = options
|
|
299
|
+
const candidates =
|
|
300
|
+
mode === "release"
|
|
301
|
+
? (frameworkBuildPaths.releaseRuntimeOutputCandidates ?? [])
|
|
302
|
+
: (frameworkBuildPaths.devRuntimeOutputCandidates ?? [])
|
|
303
|
+
const existing = resolveExistingCandidate(candidates)
|
|
285
304
|
|
|
286
|
-
if (
|
|
287
|
-
|
|
288
|
-
`Reset CLI installation is incomplete. Missing: ${missing.join(", ")}`
|
|
289
|
-
)
|
|
305
|
+
if (existing) {
|
|
306
|
+
return existing
|
|
290
307
|
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
export function assertAppProject(appPaths, config) {
|
|
294
|
-
const checks = [...getAppChecks(appPaths)]
|
|
295
|
-
|
|
296
|
-
if (config) {
|
|
297
|
-
checks.unshift(["frontend", resolveFrontendDir(appPaths, config)])
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
const missing = checks
|
|
301
|
-
.filter(([, filePath]) => !existsSync(filePath))
|
|
302
|
-
.map(([label]) => label)
|
|
303
|
-
|
|
304
|
-
if (missing.length > 0) {
|
|
305
|
-
throw new Error(
|
|
306
|
-
`Current directory does not look like a Reset app. Missing: ${missing.join(", ")}`
|
|
307
|
-
)
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
export function validateResetConfig(rawConfig) {
|
|
312
|
-
const frontend = optionalObject(rawConfig, "frontend")
|
|
313
|
-
const build = optionalObject(rawConfig, "build")
|
|
314
|
-
const project = optionalObject(rawConfig, "project")
|
|
315
|
-
const security = optionalObject(rawConfig, "security")
|
|
316
|
-
const protocols = optionalObject(rawConfig, "protocols")
|
|
317
|
-
const windowConfig = optionalObject(rawConfig, "window")
|
|
318
|
-
const rawProtocolSchemes = Array.isArray(protocols.schemes) ? protocols.schemes : []
|
|
319
|
-
const seenProtocolSchemes = new Set()
|
|
320
|
-
|
|
321
|
-
return {
|
|
322
|
-
...rawConfig,
|
|
323
|
-
name: sanitizeName(requireString(rawConfig, "name", "config")),
|
|
324
|
-
productName: requireString(rawConfig, "productName", "config"),
|
|
325
|
-
appId: requireString(rawConfig, "appId", "config"),
|
|
326
|
-
version: requireString(rawConfig, "version", "config"),
|
|
327
|
-
window: {
|
|
328
|
-
title: optionalString(windowConfig, "title", "Reset App")
|
|
329
|
-
},
|
|
330
|
-
frontend: {
|
|
331
|
-
devUrl: requireString(frontend, "devUrl", "frontend"),
|
|
332
|
-
distDir: optionalString(frontend, "distDir", "dist"),
|
|
333
|
-
entryHtml: optionalString(frontend, "entryHtml", "index.html")
|
|
334
|
-
},
|
|
335
|
-
project: {
|
|
336
|
-
frontendDir: normalizeFrontendDir(optionalString(project, "frontendDir", "frontend")),
|
|
337
|
-
styling: normalizeStyling(optionalString(project, "styling", "css"))
|
|
338
|
-
},
|
|
339
|
-
build: {
|
|
340
|
-
outputDir: optionalString(build, "outputDir", ".reset/build")
|
|
341
|
-
},
|
|
342
|
-
security: {
|
|
343
|
-
permissions: Array.isArray(security.permissions)
|
|
344
|
-
? security.permissions.map((value) => {
|
|
345
|
-
if (typeof value !== "string" || value.trim() === "") {
|
|
346
|
-
throw new Error("Missing or invalid string field 'security.permissions'")
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
return value
|
|
350
|
-
})
|
|
351
|
-
: []
|
|
352
|
-
},
|
|
353
|
-
protocols: {
|
|
354
|
-
schemes: rawProtocolSchemes.map((entry) => {
|
|
355
|
-
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
356
|
-
throw new Error("protocols.schemes entries must be objects")
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
const scheme = normalizeProtocolScheme(entry.scheme)
|
|
360
|
-
if (seenProtocolSchemes.has(scheme)) {
|
|
361
|
-
throw new Error(`Duplicate protocol scheme '${scheme}'`)
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
seenProtocolSchemes.add(scheme)
|
|
365
308
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
typeof entry.name === "string" && entry.name.trim() !== ""
|
|
370
|
-
? entry.name
|
|
371
|
-
: scheme,
|
|
372
|
-
role:
|
|
373
|
-
entry.role === undefined
|
|
374
|
-
? "Viewer"
|
|
375
|
-
: normalizeProtocolRole(entry.role)
|
|
376
|
-
}
|
|
377
|
-
})
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
export function loadResetConfig(appPaths) {
|
|
383
|
-
const configPath = resolveConfigPath(appPaths)
|
|
384
|
-
const raw = readFileSync(configPath, "utf8")
|
|
385
|
-
|
|
386
|
-
try {
|
|
387
|
-
return validateResetConfig(JSON.parse(raw))
|
|
388
|
-
} catch (error) {
|
|
389
|
-
if (error instanceof SyntaxError) {
|
|
390
|
-
throw new Error(`Invalid JSON in ${configPath}: ${error.message}`)
|
|
309
|
+
if (candidates.length > 0) {
|
|
310
|
+
if (mustExist) {
|
|
311
|
+
throw new Error(`Missing built runtime output directory. Looked in: ${candidates.join(", ")}`)
|
|
391
312
|
}
|
|
392
313
|
|
|
393
|
-
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
|
|
314
|
+
return candidates[0]
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return path.dirname(resolveFrameworkRuntimeBinary(frameworkBuildPaths, mode, options))
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export function resolveAppPaths(appRoot) {
|
|
321
|
+
return {
|
|
322
|
+
appRoot,
|
|
323
|
+
appPackageJsonPath: path.join(appRoot, "package.json"),
|
|
324
|
+
frontendDir: path.join(appRoot, "frontend"),
|
|
325
|
+
resetConfigPath: path.join(appRoot, "reset.config.json"),
|
|
326
|
+
legacyResetConfigPath: path.join(appRoot, "frontend", "reset.config.json")
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export function resolveConfigPath(appPaths) {
|
|
331
|
+
if (existsSync(appPaths.resetConfigPath)) {
|
|
332
|
+
return appPaths.resetConfigPath
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (existsSync(appPaths.legacyResetConfigPath)) {
|
|
336
|
+
return appPaths.legacyResetConfigPath
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return appPaths.resetConfigPath
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export function getFrameworkChecks(frameworkPaths) {
|
|
343
|
+
return [
|
|
344
|
+
["native", frameworkPaths.frameworkPackage.packageJsonPath],
|
|
345
|
+
["sdk", frameworkPaths.sdkPackage.packageJsonPath],
|
|
346
|
+
["schema", frameworkPaths.schemaPackage.packageJsonPath],
|
|
347
|
+
["cmake", frameworkPaths.rootCMakePath],
|
|
348
|
+
["runtime", frameworkPaths.runtimeDir],
|
|
349
|
+
["vcpkg", frameworkPaths.vcpkgManifestPath],
|
|
350
|
+
["templates", frameworkPaths.templatesDir]
|
|
351
|
+
]
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export function getAppChecks(appPaths) {
|
|
355
|
+
return [["config", resolveConfigPath(appPaths)]]
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export function assertFrameworkInstall(frameworkPaths) {
|
|
359
|
+
const missing = getFrameworkChecks(frameworkPaths)
|
|
360
|
+
.filter(([, filePath]) => !existsSync(filePath))
|
|
361
|
+
.map(([label]) => label)
|
|
362
|
+
|
|
363
|
+
if (missing.length > 0) {
|
|
364
|
+
throw new Error(
|
|
365
|
+
`Reset CLI installation is incomplete. Missing: ${missing.join(", ")}`
|
|
366
|
+
)
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export function assertAppProject(appPaths, config) {
|
|
371
|
+
const checks = [...getAppChecks(appPaths)]
|
|
372
|
+
|
|
373
|
+
if (config) {
|
|
374
|
+
checks.unshift(["frontend", resolveFrontendDir(appPaths, config)])
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const missing = checks
|
|
378
|
+
.filter(([, filePath]) => !existsSync(filePath))
|
|
379
|
+
.map(([label]) => label)
|
|
380
|
+
|
|
381
|
+
if (missing.length > 0) {
|
|
382
|
+
throw new Error(
|
|
383
|
+
`Current directory does not look like a Reset app. Missing: ${missing.join(", ")}`
|
|
384
|
+
)
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
export function validateResetConfig(rawConfig) {
|
|
389
|
+
const frontend = optionalObject(rawConfig, "frontend")
|
|
390
|
+
const build = optionalObject(rawConfig, "build")
|
|
391
|
+
const project = optionalObject(rawConfig, "project")
|
|
392
|
+
const security = optionalObject(rawConfig, "security")
|
|
393
|
+
const protocols = optionalObject(rawConfig, "protocols")
|
|
394
|
+
const windowConfig = optionalObject(rawConfig, "window")
|
|
395
|
+
const rawProtocolSchemes = Array.isArray(protocols.schemes) ? protocols.schemes : []
|
|
396
|
+
const seenProtocolSchemes = new Set()
|
|
397
|
+
|
|
398
|
+
return {
|
|
399
|
+
...rawConfig,
|
|
400
|
+
name: sanitizeName(requireString(rawConfig, "name", "config")),
|
|
401
|
+
productName: requireString(rawConfig, "productName", "config"),
|
|
402
|
+
appId: requireString(rawConfig, "appId", "config"),
|
|
403
|
+
version: requireString(rawConfig, "version", "config"),
|
|
404
|
+
window: {
|
|
405
|
+
title: optionalString(windowConfig, "title", "Reset App")
|
|
406
|
+
},
|
|
407
|
+
frontend: {
|
|
408
|
+
devUrl: requireString(frontend, "devUrl", "frontend"),
|
|
409
|
+
distDir: optionalString(frontend, "distDir", "dist"),
|
|
410
|
+
entryHtml: optionalString(frontend, "entryHtml", "index.html")
|
|
411
|
+
},
|
|
412
|
+
project: {
|
|
413
|
+
frontendDir: normalizeFrontendDir(optionalString(project, "frontendDir", "frontend")),
|
|
414
|
+
styling: normalizeStyling(optionalString(project, "styling", "css"))
|
|
415
|
+
},
|
|
416
|
+
build: {
|
|
417
|
+
outputDir: optionalString(build, "outputDir", ".reset/build")
|
|
418
|
+
},
|
|
419
|
+
security: {
|
|
420
|
+
permissions: Array.isArray(security.permissions)
|
|
421
|
+
? security.permissions.map((value) => {
|
|
422
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
423
|
+
throw new Error("Missing or invalid string field 'security.permissions'")
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return value
|
|
427
|
+
})
|
|
428
|
+
: []
|
|
429
|
+
},
|
|
430
|
+
protocols: {
|
|
431
|
+
schemes: rawProtocolSchemes.map((entry) => {
|
|
432
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
433
|
+
throw new Error("protocols.schemes entries must be objects")
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const scheme = normalizeProtocolScheme(entry.scheme)
|
|
437
|
+
if (seenProtocolSchemes.has(scheme)) {
|
|
438
|
+
throw new Error(`Duplicate protocol scheme '${scheme}'`)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
seenProtocolSchemes.add(scheme)
|
|
442
|
+
|
|
443
|
+
return {
|
|
444
|
+
scheme,
|
|
445
|
+
name:
|
|
446
|
+
typeof entry.name === "string" && entry.name.trim() !== ""
|
|
447
|
+
? entry.name
|
|
448
|
+
: scheme,
|
|
449
|
+
role:
|
|
450
|
+
entry.role === undefined
|
|
451
|
+
? "Viewer"
|
|
452
|
+
: normalizeProtocolRole(entry.role)
|
|
453
|
+
}
|
|
454
|
+
})
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export function loadResetConfig(appPaths) {
|
|
460
|
+
const configPath = resolveConfigPath(appPaths)
|
|
461
|
+
const raw = readFileSync(configPath, "utf8")
|
|
462
|
+
|
|
463
|
+
try {
|
|
464
|
+
return validateResetConfig(JSON.parse(raw))
|
|
465
|
+
} catch (error) {
|
|
466
|
+
if (error instanceof SyntaxError) {
|
|
467
|
+
throw new Error(`Invalid JSON in ${configPath}: ${error.message}`)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
throw error
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
397
474
|
export function resolveAppOutputPaths(appPaths, config) {
|
|
398
475
|
const outputRoot = path.resolve(appPaths.appRoot, config.build.outputDir)
|
|
399
476
|
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
400
|
-
const
|
|
401
|
-
const
|
|
402
|
-
const
|
|
403
|
-
const
|
|
477
|
+
const isWindows = process.platform === "win32"
|
|
478
|
+
const appBundleName = isWindows ? config.productName : `${config.productName}.app`
|
|
479
|
+
const platformDir = path.join(outputRoot, isWindows ? "windows" : "macos")
|
|
480
|
+
const appBundlePath = path.join(platformDir, appBundleName)
|
|
481
|
+
const resourcesDir = isWindows
|
|
482
|
+
? path.join(appBundlePath, "resources")
|
|
483
|
+
: path.join(appBundlePath, "Contents", "Resources")
|
|
404
484
|
const packagesDir = path.join(outputRoot, "packages")
|
|
405
485
|
|
|
406
486
|
return {
|
|
407
487
|
outputRoot,
|
|
408
|
-
macosDir,
|
|
488
|
+
macosDir: isWindows ? undefined : platformDir,
|
|
489
|
+
windowsDir: isWindows ? platformDir : undefined,
|
|
409
490
|
appBundlePath,
|
|
491
|
+
appExecutablePath: isWindows
|
|
492
|
+
? path.join(appBundlePath, `${config.productName}.exe`)
|
|
493
|
+
: undefined,
|
|
410
494
|
resourcesDir,
|
|
411
495
|
bundledConfigPath: path.join(resourcesDir, "reset.config.json"),
|
|
412
496
|
bundledFrontendDir: path.join(resourcesDir, config.frontend.distDir),
|
|
413
497
|
frontendDistDir: path.resolve(frontendDir, config.frontend.distDir),
|
|
414
498
|
frontendEntryFile: path.resolve(
|
|
415
|
-
frontendDir,
|
|
416
|
-
config.frontend.distDir,
|
|
417
|
-
config.frontend.entryHtml
|
|
499
|
+
frontendDir,
|
|
500
|
+
config.frontend.distDir,
|
|
501
|
+
config.frontend.entryHtml
|
|
418
502
|
),
|
|
419
503
|
packagesDir,
|
|
420
|
-
zipPath: path.join(packagesDir, `${config.name}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
export function resolveFrontendDir(appPaths, config) {
|
|
425
|
-
return path.resolve(appPaths.appRoot, config.project.frontendDir)
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
export function resolveDevServerOptions(config) {
|
|
429
|
-
const url = new URL(config.frontend.devUrl)
|
|
430
|
-
|
|
431
|
-
return {
|
|
432
|
-
host: url.hostname,
|
|
433
|
-
port: url.port || "5173",
|
|
434
|
-
url: url.toString()
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
export function makeAppMetadata(appName) {
|
|
439
|
-
const name = sanitizeName(appName)
|
|
440
|
-
const productName = toTitleCase(appName)
|
|
441
|
-
|
|
442
|
-
return {
|
|
443
|
-
name,
|
|
444
|
-
productName,
|
|
445
|
-
appId: `com.example.${name}`,
|
|
446
|
-
title: productName
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
export function resolveSdkDependencySpec(frameworkPaths) {
|
|
451
|
-
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.sdkPackage.localFallback) {
|
|
452
|
-
return `file:${frameworkPaths.sdkPackage.packageRoot}`
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
return `^${frameworkPaths.sdkPackage.version}`
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
export function resolveCliDependencySpec(frameworkPaths) {
|
|
459
|
-
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.cliPackage.localFallback) {
|
|
460
|
-
return `file:${frameworkPaths.cliPackage.packageRoot}`
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
return `^${frameworkPaths.cliPackage.version}`
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
function detectPackageManagerFromManifest(packageJsonPath) {
|
|
467
|
-
if (!fileExists(packageJsonPath)) {
|
|
468
|
-
return null
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
const manifest = readJsonFile(packageJsonPath)
|
|
472
|
-
const raw = typeof manifest.packageManager === "string" ? manifest.packageManager.trim() : ""
|
|
473
|
-
if (raw === "") {
|
|
474
|
-
return null
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
const [name] = raw.split("@")
|
|
478
|
-
if (name === "npm" || name === "pnpm" || name === "yarn" || name === "bun") {
|
|
479
|
-
return name
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
return null
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
function detectPackageManagerFromLocks(directory) {
|
|
486
|
-
if (!fileExists(directory)) {
|
|
487
|
-
return null
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
if (fileExists(path.join(directory, "bun.lock")) || fileExists(path.join(directory, "bun.lockb"))) {
|
|
491
|
-
return "bun"
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
if (fileExists(path.join(directory, "pnpm-lock.yaml"))) {
|
|
495
|
-
return "pnpm"
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
if (fileExists(path.join(directory, "yarn.lock"))) {
|
|
499
|
-
return "yarn"
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
if (fileExists(path.join(directory, "package-lock.json"))) {
|
|
503
|
-
return "npm"
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
return null
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
export function resolveAppPackageManager(appPaths, config) {
|
|
510
|
-
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
511
|
-
const frontendPackageJsonPath = path.join(frontendDir, "package.json")
|
|
512
|
-
|
|
513
|
-
return (
|
|
514
|
-
detectPackageManagerFromManifest(appPaths.appPackageJsonPath) ??
|
|
515
|
-
detectPackageManagerFromManifest(frontendPackageJsonPath) ??
|
|
516
|
-
detectPackageManagerFromLocks(appPaths.appRoot) ??
|
|
517
|
-
detectPackageManagerFromLocks(frontendDir) ??
|
|
518
|
-
"npm"
|
|
519
|
-
)
|
|
520
|
-
}
|
|
504
|
+
zipPath: path.join(packagesDir, `${config.name}-${isWindows ? "windows" : "macos"}.zip`)
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
export function resolveFrontendDir(appPaths, config) {
|
|
509
|
+
return path.resolve(appPaths.appRoot, config.project.frontendDir)
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
export function resolveDevServerOptions(config) {
|
|
513
|
+
const url = new URL(config.frontend.devUrl)
|
|
514
|
+
|
|
515
|
+
return {
|
|
516
|
+
host: url.hostname,
|
|
517
|
+
port: url.port || "5173",
|
|
518
|
+
url: url.toString()
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
export function makeAppMetadata(appName) {
|
|
523
|
+
const name = sanitizeName(appName)
|
|
524
|
+
const productName = toTitleCase(appName)
|
|
525
|
+
|
|
526
|
+
return {
|
|
527
|
+
name,
|
|
528
|
+
productName,
|
|
529
|
+
appId: `com.example.${name}`,
|
|
530
|
+
title: productName
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
export function resolveSdkDependencySpec(frameworkPaths) {
|
|
535
|
+
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.sdkPackage.localFallback) {
|
|
536
|
+
return `file:${frameworkPaths.sdkPackage.packageRoot}`
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return `^${frameworkPaths.sdkPackage.version}`
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
export function resolveCliDependencySpec(frameworkPaths) {
|
|
543
|
+
if (frameworkPaths.isWorkspaceLayout || frameworkPaths.cliPackage.localFallback) {
|
|
544
|
+
return `file:${frameworkPaths.cliPackage.packageRoot}`
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
return `^${frameworkPaths.cliPackage.version}`
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function detectPackageManagerFromManifest(packageJsonPath) {
|
|
551
|
+
if (!fileExists(packageJsonPath)) {
|
|
552
|
+
return null
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const manifest = readJsonFile(packageJsonPath)
|
|
556
|
+
const raw = typeof manifest.packageManager === "string" ? manifest.packageManager.trim() : ""
|
|
557
|
+
if (raw === "") {
|
|
558
|
+
return null
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
const [name] = raw.split("@")
|
|
562
|
+
if (name === "npm" || name === "pnpm" || name === "yarn" || name === "bun") {
|
|
563
|
+
return name
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
return null
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function detectPackageManagerFromLocks(directory) {
|
|
570
|
+
if (!fileExists(directory)) {
|
|
571
|
+
return null
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (fileExists(path.join(directory, "bun.lock")) || fileExists(path.join(directory, "bun.lockb"))) {
|
|
575
|
+
return "bun"
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
if (fileExists(path.join(directory, "pnpm-lock.yaml"))) {
|
|
579
|
+
return "pnpm"
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
if (fileExists(path.join(directory, "yarn.lock"))) {
|
|
583
|
+
return "yarn"
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
if (fileExists(path.join(directory, "package-lock.json"))) {
|
|
587
|
+
return "npm"
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
return null
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
export function resolveAppPackageManager(appPaths, config) {
|
|
594
|
+
const frontendDir = resolveFrontendDir(appPaths, config)
|
|
595
|
+
const frontendPackageJsonPath = path.join(frontendDir, "package.json")
|
|
596
|
+
|
|
597
|
+
return (
|
|
598
|
+
detectPackageManagerFromManifest(appPaths.appPackageJsonPath) ??
|
|
599
|
+
detectPackageManagerFromManifest(frontendPackageJsonPath) ??
|
|
600
|
+
detectPackageManagerFromLocks(appPaths.appRoot) ??
|
|
601
|
+
detectPackageManagerFromLocks(frontendDir) ??
|
|
602
|
+
"npm"
|
|
603
|
+
)
|
|
604
|
+
}
|