@owdproject/core 3.1.4-beta.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/bin/cli.js +395 -0
- package/bin/desktop.js +5 -0
- package/bin/lib/catalog.js +293 -0
- package/bin/lib/config.js +109 -0
- package/bin/lib/desktopConfig.js +56 -0
- package/bin/lib/generateTemplate.js +389 -0
- package/bin/lib/install.js +408 -0
- package/bin/lib/migrateModulePlayground.config.mjs +164 -0
- package/bin/lib/migrateModulePlayground.mjs +313 -0
- package/bin/lib/npmVersions.js +124 -0
- package/bin/lib/playgroundContext.js +188 -0
- package/bin/lib/scaffold.js +197 -0
- package/bin/lib/status.js +289 -0
- package/bin/lib/validateModule.js +683 -0
- package/bin/lib/workspace.js +182 -0
- package/bin/owd.js +2 -25
- package/bin/tui.js +1379 -0
- package/dist/module.d.mts +13 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +219 -0
- package/dist/types.d.mts +7 -0
- package/module.ts +53 -19
- package/package.json +78 -22
- package/runtime/components/Core/Application/CoreApplicationRender.vue +3 -1
- package/runtime/components/Core/Application/CoreApplicationWindowsRender.vue +28 -7
- package/runtime/components/Core/Desktop/CoreDesktop.vue +11 -7
- package/runtime/components/Core/Window/CoreWindow.vue +45 -9
- package/runtime/components/Core/Window/CoreWindowNav.vue +26 -8
- package/runtime/composables/useApplicationEntries.ts +1 -1
- package/runtime/composables/useApplicationManager.ts +282 -4
- package/runtime/composables/useDesktopManager.ts +46 -4
- package/runtime/composables/useOwdDialogs.ts +13 -0
- package/runtime/composables/useTerminalManager.ts +62 -3
- package/runtime/composables/useWorkspaceOverview.ts +41 -0
- package/runtime/core/controllers/ApplicationController.ts +120 -30
- package/runtime/core/controllers/WindowController.ts +5 -10
- package/runtime/dialogs/owdDialogProvider.ts +81 -0
- package/runtime/plugins/01.owd-dialogs-fallback.ts +15 -0
- package/runtime/stores/storeApplicationMeta.ts +56 -12
- package/runtime/stores/storeDesktop.ts +79 -0
- package/runtime/stores/storeDesktopDefaultApps.ts +53 -0
- package/runtime/stores/storeDesktopExplorer.ts +74 -0
- package/runtime/stores/storeDesktopWorkspace.ts +14 -2
- package/runtime/utils/captureElementToCanvas.ts +21 -0
- package/runtime/utils/explorerEntryPath.ts +10 -0
- package/runtime/utils/resolveDesktopConfigPath.ts +52 -0
- package/runtime/utils/validateOwdUserConfig.ts +44 -0
- package/types/index.d.ts +64 -12
- package/CHANGELOG.md +0 -25
- package/project.json +0 -4
- package/runtime/composables/useClipboardFs.ts +0 -25
- package/runtime/core/managers/ApplicationManager.ts +0 -281
- package/runtime/core/managers/DesktopManager.ts +0 -47
- package/runtime/core/managers/TerminalManager.ts +0 -48
- package/runtime/stores/storeApplication.ts +0 -235
- package/test/basic.test.ts +0 -15
- package/test/fixtures/basic/app.vue +0 -5
- package/test/fixtures/basic/nuxt.config.ts +0 -5
- package/test/fixtures/basic/package.json +0 -5
- package/tsconfig.app.json +0 -31
- package/tsconfig.json +0 -12
- package/tsconfig.spec.json +0 -37
- package/vitest.config.ts +0 -24
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import {
|
|
2
|
+
existsSync,
|
|
3
|
+
readFileSync,
|
|
4
|
+
readdirSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
writeFileSync,
|
|
7
|
+
statSync,
|
|
8
|
+
} from 'node:fs'
|
|
9
|
+
import { join } from 'node:path'
|
|
10
|
+
import { execSync } from 'node:child_process'
|
|
11
|
+
import {
|
|
12
|
+
KINDS,
|
|
13
|
+
SCOPE,
|
|
14
|
+
fullName,
|
|
15
|
+
shortName,
|
|
16
|
+
inferKind,
|
|
17
|
+
isInstallableDesktopModule,
|
|
18
|
+
desktopMetaDir,
|
|
19
|
+
} from './workspace.js'
|
|
20
|
+
import { hasLocalWorkspaceSource } from './install.js'
|
|
21
|
+
|
|
22
|
+
const CACHE_TTL_MS = 60 * 60 * 1000
|
|
23
|
+
|
|
24
|
+
function cachePath(workspaceRoot) {
|
|
25
|
+
return join(desktopMetaDir(workspaceRoot), 'catalog-cache.json')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function readCache(workspaceRoot) {
|
|
29
|
+
const path = cachePath(workspaceRoot)
|
|
30
|
+
if (!existsSync(path)) return null
|
|
31
|
+
try {
|
|
32
|
+
const data = JSON.parse(readFileSync(path, 'utf8'))
|
|
33
|
+
if (Date.now() - data.fetchedAt > CACHE_TTL_MS) return null
|
|
34
|
+
const ageMin = Math.round((Date.now() - data.fetchedAt) / 60_000)
|
|
35
|
+
return { entries: data.entries, cacheAge: `${ageMin}m` }
|
|
36
|
+
} catch {
|
|
37
|
+
return null
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function formatCacheAge(fetchedAt) {
|
|
42
|
+
const ageMin = Math.round((Date.now() - fetchedAt) / 60_000)
|
|
43
|
+
if (ageMin < 1) return '<1m'
|
|
44
|
+
if (ageMin < 60) return `${ageMin}m`
|
|
45
|
+
return `${Math.round(ageMin / 60)}h`
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function writeCache(workspaceRoot, entries) {
|
|
49
|
+
mkdirSync(desktopMetaDir(workspaceRoot), { recursive: true })
|
|
50
|
+
writeFileSync(
|
|
51
|
+
cachePath(workspaceRoot),
|
|
52
|
+
JSON.stringify({ fetchedAt: Date.now(), entries }, null, 2),
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function fetchTopic(topic, org) {
|
|
57
|
+
const q = encodeURIComponent(`topic:${topic} org:${org}`)
|
|
58
|
+
const url = `https://api.github.com/search/repositories?q=${q}&sort=stars&per_page=100`
|
|
59
|
+
const headers = {
|
|
60
|
+
Accept: 'application/vnd.github+json',
|
|
61
|
+
'User-Agent': 'owd-desktop-cli',
|
|
62
|
+
}
|
|
63
|
+
if (process.env.GITHUB_TOKEN) {
|
|
64
|
+
headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const res = await fetch(url, { headers })
|
|
68
|
+
if (!res.ok) throw new Error(`GitHub API ${res.status} for ${org}/${topic}`)
|
|
69
|
+
const json = await res.json()
|
|
70
|
+
return (json.items ?? []).map((repo) => ({
|
|
71
|
+
shortName: repo.name,
|
|
72
|
+
description: repo.description ?? '',
|
|
73
|
+
stars: repo.stargazers_count ?? 0,
|
|
74
|
+
htmlUrl: repo.html_url,
|
|
75
|
+
org: repo.owner?.login ?? org,
|
|
76
|
+
kind: inferKind(repo.name),
|
|
77
|
+
}))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function fetchUserRepos(user) {
|
|
81
|
+
const url = `https://api.github.com/users/${encodeURIComponent(user)}/repos?per_page=100&sort=updated`
|
|
82
|
+
const headers = {
|
|
83
|
+
Accept: 'application/vnd.github+json',
|
|
84
|
+
'User-Agent': 'owd-desktop-cli',
|
|
85
|
+
}
|
|
86
|
+
if (process.env.GITHUB_TOKEN) {
|
|
87
|
+
headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const res = await fetch(url, { headers })
|
|
91
|
+
if (!res.ok) return []
|
|
92
|
+
const repos = await res.json()
|
|
93
|
+
return repos
|
|
94
|
+
.filter((repo) => /^(app|theme|module|kit)-/.test(repo.name))
|
|
95
|
+
.map((repo) => ({
|
|
96
|
+
shortName: repo.name,
|
|
97
|
+
description: repo.description ?? '',
|
|
98
|
+
stars: repo.stargazers_count ?? 0,
|
|
99
|
+
htmlUrl: repo.html_url,
|
|
100
|
+
org: repo.owner?.login ?? user,
|
|
101
|
+
kind: inferKind(repo.name),
|
|
102
|
+
}))
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function scanLocal(workspaceRoot, kind) {
|
|
106
|
+
const dir = join(workspaceRoot, KINDS[kind].workspaceDir)
|
|
107
|
+
if (!existsSync(dir)) return []
|
|
108
|
+
|
|
109
|
+
return readdirSync(dir, { withFileTypes: true })
|
|
110
|
+
.filter((d) => d.isDirectory())
|
|
111
|
+
.map((d) => {
|
|
112
|
+
const pkgPath = join(dir, d.name, 'package.json')
|
|
113
|
+
if (!existsSync(pkgPath)) return null
|
|
114
|
+
try {
|
|
115
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
|
|
116
|
+
if (!pkg.name?.startsWith(SCOPE)) return null
|
|
117
|
+
let remote = null
|
|
118
|
+
try {
|
|
119
|
+
remote = execSync(`git -C ${join(dir, d.name)} remote get-url origin`, {
|
|
120
|
+
encoding: 'utf8',
|
|
121
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
122
|
+
}).trim()
|
|
123
|
+
} catch {
|
|
124
|
+
/* no git */
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
shortName: shortName(pkg.name),
|
|
128
|
+
description: pkg.description ?? '',
|
|
129
|
+
stars: 0,
|
|
130
|
+
htmlUrl: pkg.homepage ?? pkg.repository?.url ?? null,
|
|
131
|
+
org: 'workspace',
|
|
132
|
+
kind,
|
|
133
|
+
localPath: join(KINDS[kind].workspaceDir, d.name),
|
|
134
|
+
remote,
|
|
135
|
+
version: pkg.version,
|
|
136
|
+
}
|
|
137
|
+
} catch {
|
|
138
|
+
return null
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
.filter(Boolean)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export async function loadCatalog(workspaceRoot, settings) {
|
|
145
|
+
const cached = readCache(workspaceRoot)
|
|
146
|
+
let remote = cached?.entries ?? null
|
|
147
|
+
let cacheAge = cached?.cacheAge ?? null
|
|
148
|
+
|
|
149
|
+
if (!remote) {
|
|
150
|
+
remote = []
|
|
151
|
+
const orgs = [...new Set([...(settings.githubOrgs ?? ['owdproject']), settings.githubUser].filter(Boolean))]
|
|
152
|
+
|
|
153
|
+
for (const org of orgs) {
|
|
154
|
+
for (const kind of Object.keys(KINDS)) {
|
|
155
|
+
try {
|
|
156
|
+
const items = await fetchTopic(KINDS[kind].topic, org)
|
|
157
|
+
remote.push(...items)
|
|
158
|
+
} catch {
|
|
159
|
+
/* offline — use local only */
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (settings.githubUser && !orgs.includes(settings.githubUser)) {
|
|
165
|
+
try {
|
|
166
|
+
remote.push(...(await fetchUserRepos(settings.githubUser)))
|
|
167
|
+
} catch {
|
|
168
|
+
/* ignore */
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (remote.length) {
|
|
173
|
+
const at = Date.now()
|
|
174
|
+
writeCache(workspaceRoot, remote)
|
|
175
|
+
cacheAge = formatCacheAge(at)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const byName = new Map()
|
|
180
|
+
|
|
181
|
+
for (const item of remote) {
|
|
182
|
+
byName.set(item.shortName, { ...item, sources: [item.org] })
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
for (const kind of Object.keys(KINDS)) {
|
|
186
|
+
for (const item of scanLocal(workspaceRoot, kind)) {
|
|
187
|
+
const prev = byName.get(item.shortName)
|
|
188
|
+
if (prev) {
|
|
189
|
+
byName.set(item.shortName, {
|
|
190
|
+
...prev,
|
|
191
|
+
...item,
|
|
192
|
+
localPath: item.localPath,
|
|
193
|
+
remote: item.remote ?? prev.htmlUrl,
|
|
194
|
+
sources: [...new Set([...(prev.sources ?? []), 'workspace'])],
|
|
195
|
+
})
|
|
196
|
+
} else {
|
|
197
|
+
byName.set(item.shortName, { ...item, sources: ['workspace'] })
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const entries = [...byName.values()].map((entry) => ({
|
|
203
|
+
...entry,
|
|
204
|
+
name: fullName(entry.shortName),
|
|
205
|
+
kind: entry.kind ?? inferKind(entry.shortName),
|
|
206
|
+
}))
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
entries,
|
|
210
|
+
cacheAge: cacheAge ?? 'live',
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function filterCatalog(catalog, kind) {
|
|
215
|
+
return catalog
|
|
216
|
+
.filter((e) => e.kind === kind)
|
|
217
|
+
.filter((e) => kind !== 'module' || isInstallableDesktopModule(e.name))
|
|
218
|
+
.sort((a, b) => {
|
|
219
|
+
if (a.org === 'workspace' && b.org !== 'workspace') return -1
|
|
220
|
+
if (b.org === 'workspace' && a.org !== 'workspace') return 1
|
|
221
|
+
return (b.stars ?? 0) - (a.stars ?? 0) || a.shortName.localeCompare(b.shortName)
|
|
222
|
+
})
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function mergeInstalled(catalog, config, deps, workspaceRoot) {
|
|
226
|
+
const installedApps = new Set(config.apps ?? [])
|
|
227
|
+
const installedModules = new Set(config.modules ?? [])
|
|
228
|
+
const activeTheme = config.theme
|
|
229
|
+
|
|
230
|
+
return catalog.map((entry) => {
|
|
231
|
+
let installed = false
|
|
232
|
+
if (entry.kind === 'app') installed = installedApps.has(entry.name)
|
|
233
|
+
else if (entry.kind === 'module') installed = installedModules.has(entry.name)
|
|
234
|
+
else if (entry.kind === 'theme') installed = activeTheme === entry.name
|
|
235
|
+
|
|
236
|
+
const localSource = workspaceRoot
|
|
237
|
+
? hasLocalWorkspaceSource(workspaceRoot, entry.name)
|
|
238
|
+
: entry.org === 'workspace'
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
...entry,
|
|
242
|
+
installed,
|
|
243
|
+
localSource,
|
|
244
|
+
inPackageJson: deps.includes(entry.name),
|
|
245
|
+
activeTheme: entry.kind === 'theme' && activeTheme === entry.name,
|
|
246
|
+
}
|
|
247
|
+
})
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function readThemeMeta(workspaceRoot, themePkgName) {
|
|
251
|
+
const short = shortName(themePkgName)
|
|
252
|
+
const localDir = join(workspaceRoot, 'themes', short)
|
|
253
|
+
const pkgPath = join(localDir, 'package.json')
|
|
254
|
+
|
|
255
|
+
if (!existsSync(pkgPath)) {
|
|
256
|
+
return {
|
|
257
|
+
name: themePkgName,
|
|
258
|
+
description: 'Theme package not in workspace',
|
|
259
|
+
version: '—',
|
|
260
|
+
author: '—',
|
|
261
|
+
remote: null,
|
|
262
|
+
license: '—',
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
|
|
267
|
+
let remote = null
|
|
268
|
+
try {
|
|
269
|
+
remote = execSync(`git -C ${localDir} remote get-url origin`, {
|
|
270
|
+
encoding: 'utf8',
|
|
271
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
272
|
+
}).trim()
|
|
273
|
+
} catch {
|
|
274
|
+
remote = pkg.repository?.url ?? pkg.homepage ?? null
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const author =
|
|
278
|
+
typeof pkg.author === 'string'
|
|
279
|
+
? pkg.author
|
|
280
|
+
: pkg.author?.name
|
|
281
|
+
? `${pkg.author.name}${pkg.author.url ? ` · ${pkg.author.url}` : ''}`
|
|
282
|
+
: '—'
|
|
283
|
+
|
|
284
|
+
return {
|
|
285
|
+
name: pkg.name,
|
|
286
|
+
description: pkg.description ?? '',
|
|
287
|
+
version: pkg.version ?? '—',
|
|
288
|
+
author,
|
|
289
|
+
license: pkg.license ?? 'MIT',
|
|
290
|
+
remote,
|
|
291
|
+
homepage: pkg.homepage ?? null,
|
|
292
|
+
}
|
|
293
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { readFileSync, existsSync, copyFileSync } from 'node:fs'
|
|
2
|
+
import { createRequire } from 'node:module'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { SCOPE } from './workspace.js'
|
|
5
|
+
import { LEGACY_CONFIG_DEPRECATION } from './desktopConfig.js'
|
|
6
|
+
|
|
7
|
+
const require = createRequire(import.meta.url)
|
|
8
|
+
|
|
9
|
+
function loadTsMorph(workspaceRoot) {
|
|
10
|
+
const utilPath = join(
|
|
11
|
+
workspaceRoot,
|
|
12
|
+
'node_modules/@owdproject/nx/dist/utils/utilConfig.js',
|
|
13
|
+
)
|
|
14
|
+
if (!existsSync(utilPath)) {
|
|
15
|
+
throw new Error('Missing @owdproject/nx — run pnpm install at the repo root.')
|
|
16
|
+
}
|
|
17
|
+
const { Project, SyntaxKind } = require('ts-morph')
|
|
18
|
+
return { Project, SyntaxKind }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getConfigObject(sourceFile, SyntaxKind) {
|
|
22
|
+
const exportDefault = sourceFile.getExportAssignmentOrThrow((exp) => !exp.isExportEquals())
|
|
23
|
+
const callExpr = exportDefault.getExpressionIfKindOrThrow(SyntaxKind.CallExpression)
|
|
24
|
+
const args = callExpr.getArguments()
|
|
25
|
+
if (args.length === 0) throw new Error('defineDesktopConfig({}) is empty')
|
|
26
|
+
return args[0].asKindOrThrow(SyntaxKind.ObjectLiteralExpression)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function readArrayProperty(configObj, key, SyntaxKind) {
|
|
30
|
+
const prop = configObj.getProperty(key)?.asKind(SyntaxKind.PropertyAssignment)
|
|
31
|
+
if (!prop) return []
|
|
32
|
+
const init = prop.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression)
|
|
33
|
+
if (!init) return []
|
|
34
|
+
return init
|
|
35
|
+
.getElements()
|
|
36
|
+
.map((el) => el.getText().trim().replace(/['"`]/g, ''))
|
|
37
|
+
.filter(Boolean)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readTheme(configObj, SyntaxKind) {
|
|
41
|
+
const prop = configObj.getProperty('theme')?.asKind(SyntaxKind.PropertyAssignment)
|
|
42
|
+
if (!prop) return null
|
|
43
|
+
return prop.getInitializer()?.getText().trim().replace(/['"`]/g, '') ?? null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function setArrayProperty(configObj, key, values, SyntaxKind) {
|
|
47
|
+
const quoted = values.map((v) => `'${v}'`).join(', ')
|
|
48
|
+
const initializer = `[ ${quoted} ]`
|
|
49
|
+
const existing = configObj.getProperty(key)?.asKind(SyntaxKind.PropertyAssignment)
|
|
50
|
+
if (existing) {
|
|
51
|
+
existing.setInitializer(initializer)
|
|
52
|
+
} else {
|
|
53
|
+
configObj.addPropertyAssignment({ name: key, initializer })
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function readDesktopConfig(configPath, workspaceRoot) {
|
|
58
|
+
const { Project, SyntaxKind } = loadTsMorph(workspaceRoot)
|
|
59
|
+
const project = new Project()
|
|
60
|
+
const sourceFile = project.addSourceFileAtPath(configPath)
|
|
61
|
+
const configObj = getConfigObject(sourceFile, SyntaxKind)
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
theme: readTheme(configObj, SyntaxKind),
|
|
65
|
+
apps: readArrayProperty(configObj, 'apps', SyntaxKind),
|
|
66
|
+
modules: readArrayProperty(configObj, 'modules', SyntaxKind),
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* When saving from the TUI, always target desktop.config.ts (migrate from legacy on first save).
|
|
72
|
+
*
|
|
73
|
+
* @param {{ config: string, configWrite: string }} paths
|
|
74
|
+
*/
|
|
75
|
+
export function resolveConfigPathForWrite(paths) {
|
|
76
|
+
if (paths.config === paths.configWrite) {
|
|
77
|
+
return paths.configWrite
|
|
78
|
+
}
|
|
79
|
+
if (!existsSync(paths.configWrite) && existsSync(paths.config)) {
|
|
80
|
+
copyFileSync(paths.config, paths.configWrite)
|
|
81
|
+
console.warn(LEGACY_CONFIG_DEPRECATION)
|
|
82
|
+
}
|
|
83
|
+
return paths.configWrite
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function writeDesktopConfig(configPath, workspaceRoot, state) {
|
|
87
|
+
const { Project, SyntaxKind } = loadTsMorph(workspaceRoot)
|
|
88
|
+
const project = new Project()
|
|
89
|
+
const sourceFile = project.addSourceFileAtPath(configPath)
|
|
90
|
+
const configObj = getConfigObject(sourceFile, SyntaxKind)
|
|
91
|
+
|
|
92
|
+
if (state.theme) {
|
|
93
|
+
const themeProp = configObj.getProperty('theme')?.asKind(SyntaxKind.PropertyAssignment)
|
|
94
|
+
if (themeProp) themeProp.setInitializer(`'${state.theme}'`)
|
|
95
|
+
else configObj.addPropertyAssignment({ name: 'theme', initializer: `'${state.theme}'` })
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (state.apps) setArrayProperty(configObj, 'apps', state.apps, SyntaxKind)
|
|
99
|
+
if (state.modules) setArrayProperty(configObj, 'modules', state.modules, SyntaxKind)
|
|
100
|
+
|
|
101
|
+
sourceFile.saveSync()
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function readDesktopDependencies(packageJsonPath) {
|
|
105
|
+
if (!existsSync(packageJsonPath)) return []
|
|
106
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
|
|
107
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies }
|
|
108
|
+
return Object.keys(deps).filter((name) => name.startsWith(SCOPE))
|
|
109
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
export const DESKTOP_CONFIG_FILENAME = 'desktop.config.ts'
|
|
5
|
+
export const LEGACY_DESKTOP_CONFIG_FILENAME = 'owd.config.ts'
|
|
6
|
+
|
|
7
|
+
export const LEGACY_CONFIG_DEPRECATION =
|
|
8
|
+
'[@owdproject/core] owd.config.ts is deprecated and kept only for backward compatibility; rename to desktop.config.ts (required from @owdproject/core 3.2).'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Resolve the desktop config file under a Nuxt project root (or desktop/ folder).
|
|
12
|
+
*
|
|
13
|
+
* @param {string} rootDir
|
|
14
|
+
* @returns {{ path: string, file: string, legacy: boolean } | null}
|
|
15
|
+
*/
|
|
16
|
+
export function resolveDesktopConfigPath(rootDir) {
|
|
17
|
+
const desktopPath = join(rootDir, DESKTOP_CONFIG_FILENAME)
|
|
18
|
+
const legacyPath = join(rootDir, LEGACY_DESKTOP_CONFIG_FILENAME)
|
|
19
|
+
const hasDesktop = existsSync(desktopPath)
|
|
20
|
+
const hasLegacy = existsSync(legacyPath)
|
|
21
|
+
|
|
22
|
+
if (hasDesktop && hasLegacy) {
|
|
23
|
+
console.warn(
|
|
24
|
+
'[@owdproject/core] Both desktop.config.ts and owd.config.ts exist; using desktop.config.ts. Remove owd.config.ts.',
|
|
25
|
+
)
|
|
26
|
+
return { path: desktopPath, file: DESKTOP_CONFIG_FILENAME, legacy: false }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (hasDesktop) {
|
|
30
|
+
return { path: desktopPath, file: DESKTOP_CONFIG_FILENAME, legacy: false }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (hasLegacy) {
|
|
34
|
+
return { path: legacyPath, file: LEGACY_DESKTOP_CONFIG_FILENAME, legacy: true }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {{ legacy?: boolean, file?: string } | null | undefined} resolved
|
|
42
|
+
*/
|
|
43
|
+
export function warnLegacyDesktopConfig(resolved) {
|
|
44
|
+
if (resolved?.legacy) {
|
|
45
|
+
console.warn(LEGACY_CONFIG_DEPRECATION)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Path used when creating or updating config from the CLI (always the new filename).
|
|
51
|
+
*
|
|
52
|
+
* @param {string} desktopDir
|
|
53
|
+
*/
|
|
54
|
+
export function desktopConfigWritePath(desktopDir) {
|
|
55
|
+
return join(desktopDir, DESKTOP_CONFIG_FILENAME)
|
|
56
|
+
}
|