fg-devkit 1.15.1 → 1.16.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fg-devkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.1",
|
|
4
4
|
"description": "Shared configs, scripts, and DX tooling for Vue / TypeScript frontend repos",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"./scripts/sync-tooling-configs.mjs": "./scripts/sync-tooling-configs.mjs",
|
|
27
27
|
"./scripts/sync-project-configs.mjs": "./scripts/sync-project-configs.mjs",
|
|
28
28
|
"./scripts/sync-consumer-scripts.mjs": "./scripts/sync-consumer-scripts.mjs",
|
|
29
|
+
"./scripts/sync-vite-plugin-vue-inspector.mjs": "./scripts/sync-vite-plugin-vue-inspector.mjs",
|
|
29
30
|
"./scripts/sync-consumer-lefthook.mjs": "./scripts/sync-consumer-lefthook.mjs",
|
|
30
31
|
"./scripts/policy-outdated.mjs": "./scripts/policy-outdated.mjs",
|
|
31
32
|
"./scripts/policy-vulns.mjs": "./scripts/policy-vulns.mjs",
|
|
@@ -33,10 +33,11 @@
|
|
|
33
33
|
"@tanstack/vue-query-devtools": "6.1.48",
|
|
34
34
|
"@types/node": "22.16.5",
|
|
35
35
|
"@vitejs/plugin-vue": "6.0.8",
|
|
36
|
-
"fg-devkit": "1.
|
|
36
|
+
"fg-devkit": "1.16.1",
|
|
37
37
|
"tailwindcss": "4.3.3",
|
|
38
38
|
"tsx": "4.23.13",
|
|
39
|
-
"vite": "7.3.5"
|
|
39
|
+
"vite": "7.3.5",
|
|
40
|
+
"vite-plugin-vue-inspector": "7.0.0"
|
|
40
41
|
},
|
|
41
42
|
"packageManager": "pnpm@11.25.0",
|
|
42
43
|
"engines": {
|
|
@@ -4,6 +4,7 @@ import vue from '@vitejs/plugin-vue'
|
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
5
|
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
|
|
6
6
|
import tailwindcss from '@tailwindcss/vite'
|
|
7
|
+
import Inspector from 'vite-plugin-vue-inspector'
|
|
7
8
|
|
|
8
9
|
export default defineConfig({
|
|
9
10
|
plugins: [
|
|
@@ -19,6 +20,10 @@ export default defineConfig({
|
|
|
19
20
|
strictMessage: false,
|
|
20
21
|
}),
|
|
21
22
|
tailwindcss(),
|
|
23
|
+
Inspector({
|
|
24
|
+
launchEditor: 'cursor',
|
|
25
|
+
toggleComboKey: 'meta-alt',
|
|
26
|
+
}),
|
|
22
27
|
],
|
|
23
28
|
resolve: {
|
|
24
29
|
alias: {
|
package/scripts/fg-devkit.mjs
CHANGED
|
@@ -445,6 +445,7 @@ function runSyncConfigTarget(target) {
|
|
|
445
445
|
if (target === 'tsconfig') return syncFileFromTemplate('configs/tsconfig.app.sync.json', 'tsconfig.json')
|
|
446
446
|
if (target === 'fallow') return syncFileFromTemplate('configs/fallowrc.sync-stub.json', '.fallowrc.json')
|
|
447
447
|
if (target === 'cursor') return runNode('sync-core-coding-standards.mjs')
|
|
448
|
+
if (target === 'vue-inspector') return runNode('sync-vite-plugin-vue-inspector.mjs')
|
|
448
449
|
if (target === 'all') return runNode('sync-project-configs.mjs')
|
|
449
450
|
console.error(`[fg-devkit] Unknown config sync target: ${target}`)
|
|
450
451
|
return 1
|
|
@@ -477,6 +478,7 @@ const DIRECT_COMMANDS = {
|
|
|
477
478
|
'sync-tooling-configs': 'sync-tooling-configs.mjs',
|
|
478
479
|
'sync-vscode-settings': 'sync-vscode-settings.mjs',
|
|
479
480
|
'sync-core-coding-standards': 'sync-core-coding-standards.mjs',
|
|
481
|
+
'sync-vite-plugin-vue-inspector': 'sync-vite-plugin-vue-inspector.mjs',
|
|
480
482
|
'sync-consumer-scripts': 'sync-consumer-scripts.mjs',
|
|
481
483
|
'sync-release-notes-config': 'sync-release-notes-config.mjs',
|
|
482
484
|
'generate-release-notes': 'generate-release-notes.mjs',
|
|
@@ -538,6 +540,7 @@ Commands:
|
|
|
538
540
|
sync-tooling-configs Tooling sync only (overwrites config files)
|
|
539
541
|
sync-vscode-settings Copy shared VS Code settings into .vscode/settings.json
|
|
540
542
|
sync-core-coding-standards Copy .cursor core coding standards with consumer package name
|
|
543
|
+
sync-vite-plugin-vue-inspector Add/pin vite-plugin-vue-inspector, wire vite.config, install, commit
|
|
541
544
|
sync-consumer-scripts Enforce standard fgd scripts in consumer package.json
|
|
542
545
|
setup-lefthook Setup lefthook and migrate from husky/lint-staged
|
|
543
546
|
full-consumer-setup Run: scripts -> lefthook -> step 3 -> step 2 -> pnpm install
|
|
@@ -836,6 +839,7 @@ async function runInteractiveMenu() {
|
|
|
836
839
|
{ name: 'tsconfig', value: 'tsconfig' },
|
|
837
840
|
{ name: 'Fallow', value: 'fallow' },
|
|
838
841
|
{ name: 'Cursor', value: 'cursor' },
|
|
842
|
+
{ name: 'Vue inspector (vite-plugin-vue-inspector)', value: 'vue-inspector' },
|
|
839
843
|
{ name: 'All', value: 'all' },
|
|
840
844
|
{ name: 'Cancel', value: 'cancel' },
|
|
841
845
|
],
|
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Ensures vite-plugin-vue-inspector is declared and wired in a Vue consumer repo.
|
|
4
|
+
*
|
|
5
|
+
* - Adds/pins the package in package.json devDependencies (version from dependency policy)
|
|
6
|
+
* - Ensures import + Inspector({ launchEditor: 'cursor', toggleComboKey: 'meta-alt' }) in vite.config.*
|
|
7
|
+
* - Runs pnpm install, then commits related files
|
|
8
|
+
*
|
|
9
|
+
* Does not overwrite the rest of vite.config. Idempotent when already up to date
|
|
10
|
+
* (skips install/commit).
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* node node_modules/fg-devkit/scripts/sync-vite-plugin-vue-inspector.mjs
|
|
14
|
+
* pnpm exec fg-devkit sync-vite-plugin-vue-inspector
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import fs from 'node:fs'
|
|
18
|
+
import path from 'node:path'
|
|
19
|
+
import { fileURLToPath } from 'node:url'
|
|
20
|
+
import { spawnSync } from 'node:child_process'
|
|
21
|
+
|
|
22
|
+
import { resolveDependencyPolicyPath } from './resolve-dependency-policy-path.mjs'
|
|
23
|
+
|
|
24
|
+
const PACKAGE_NAME = 'vite-plugin-vue-inspector'
|
|
25
|
+
const IMPORT_LINE = `import Inspector from '${PACKAGE_NAME}'`
|
|
26
|
+
const PLUGIN_OPTIONS = {
|
|
27
|
+
launchEditor: 'cursor',
|
|
28
|
+
toggleComboKey: 'meta-alt',
|
|
29
|
+
}
|
|
30
|
+
const COMMIT_MESSAGE = 'dep(vite-plugin-vue-inspector): add dependency and config'
|
|
31
|
+
|
|
32
|
+
const VITE_CONFIG_CANDIDATES = [
|
|
33
|
+
'vite.config.ts',
|
|
34
|
+
'vite.config.mts',
|
|
35
|
+
'vite.config.js',
|
|
36
|
+
'vite.config.mjs',
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
40
|
+
const cwd = process.cwd()
|
|
41
|
+
const policyPath = resolveDependencyPolicyPath(scriptDir, cwd, process.argv)
|
|
42
|
+
|
|
43
|
+
function fail(message) {
|
|
44
|
+
console.error(`[sync-vite-plugin-vue-inspector] ${message}`)
|
|
45
|
+
process.exit(1)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function runPnpm(args) {
|
|
49
|
+
const result = spawnSync('pnpm', args, {
|
|
50
|
+
stdio: 'inherit',
|
|
51
|
+
cwd,
|
|
52
|
+
env: process.env,
|
|
53
|
+
})
|
|
54
|
+
if (result.error) {
|
|
55
|
+
fail(result.error.message)
|
|
56
|
+
}
|
|
57
|
+
return result.status ?? 1
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function runGit(args, options = {}) {
|
|
61
|
+
const result = spawnSync('git', args, {
|
|
62
|
+
stdio: options.capture ? 'pipe' : 'inherit',
|
|
63
|
+
encoding: options.capture ? 'utf8' : undefined,
|
|
64
|
+
cwd,
|
|
65
|
+
env: process.env,
|
|
66
|
+
})
|
|
67
|
+
if (result.error) {
|
|
68
|
+
fail(result.error.message)
|
|
69
|
+
}
|
|
70
|
+
return { status: result.status ?? 1, stdout: result.stdout ?? '' }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function fileDiffersFromHead(filePath) {
|
|
74
|
+
const absolutePath = path.join(cwd, filePath)
|
|
75
|
+
if (!fs.existsSync(absolutePath)) return false
|
|
76
|
+
|
|
77
|
+
const tracked = runGit(['ls-files', '--error-unmatch', '--', filePath], { capture: true })
|
|
78
|
+
if (tracked.status !== 0) {
|
|
79
|
+
return true
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const diff = runGit(['diff', '--quiet', 'HEAD', '--', filePath], { capture: true })
|
|
83
|
+
return diff.status !== 0
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function stageExistingFiles(files) {
|
|
87
|
+
const existingFiles = files.filter((filePath) => fs.existsSync(path.join(cwd, filePath)))
|
|
88
|
+
if (existingFiles.length === 0) return 0
|
|
89
|
+
return runGit(['add', '--', ...existingFiles]).status
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function resolvePluginVersion(policy) {
|
|
93
|
+
return (
|
|
94
|
+
policy.managedDependencies?.devDependencies?.[PACKAGE_NAME] ??
|
|
95
|
+
policy.managedAnywhere?.[PACKAGE_NAME]
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function findViteConfigPath(projectRoot) {
|
|
100
|
+
for (const name of VITE_CONFIG_CANDIDATES) {
|
|
101
|
+
const candidate = path.join(projectRoot, name)
|
|
102
|
+
if (fs.existsSync(candidate)) return candidate
|
|
103
|
+
}
|
|
104
|
+
return null
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function formatPluginCall(indent) {
|
|
108
|
+
return [
|
|
109
|
+
'Inspector({',
|
|
110
|
+
`${indent} launchEditor: '${PLUGIN_OPTIONS.launchEditor}',`,
|
|
111
|
+
`${indent} toggleComboKey: '${PLUGIN_OPTIONS.toggleComboKey}',`,
|
|
112
|
+
`${indent}})`,
|
|
113
|
+
].join('\n')
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Find matching closing `)` for a call starting at openParenIndex (the `(`). */
|
|
117
|
+
function findMatchingParen(source, openParenIndex) {
|
|
118
|
+
let depth = 0
|
|
119
|
+
let inSingle = false
|
|
120
|
+
let inDouble = false
|
|
121
|
+
let inTemplate = false
|
|
122
|
+
let inLineComment = false
|
|
123
|
+
let inBlockComment = false
|
|
124
|
+
|
|
125
|
+
for (let i = openParenIndex; i < source.length; i++) {
|
|
126
|
+
const ch = source[i]
|
|
127
|
+
const next = source[i + 1]
|
|
128
|
+
|
|
129
|
+
if (inLineComment) {
|
|
130
|
+
if (ch === '\n') inLineComment = false
|
|
131
|
+
continue
|
|
132
|
+
}
|
|
133
|
+
if (inBlockComment) {
|
|
134
|
+
if (ch === '*' && next === '/') {
|
|
135
|
+
inBlockComment = false
|
|
136
|
+
i++
|
|
137
|
+
}
|
|
138
|
+
continue
|
|
139
|
+
}
|
|
140
|
+
if (inSingle) {
|
|
141
|
+
if (ch === '\\') {
|
|
142
|
+
i++
|
|
143
|
+
continue
|
|
144
|
+
}
|
|
145
|
+
if (ch === "'") inSingle = false
|
|
146
|
+
continue
|
|
147
|
+
}
|
|
148
|
+
if (inDouble) {
|
|
149
|
+
if (ch === '\\') {
|
|
150
|
+
i++
|
|
151
|
+
continue
|
|
152
|
+
}
|
|
153
|
+
if (ch === '"') inDouble = false
|
|
154
|
+
continue
|
|
155
|
+
}
|
|
156
|
+
if (inTemplate) {
|
|
157
|
+
if (ch === '\\') {
|
|
158
|
+
i++
|
|
159
|
+
continue
|
|
160
|
+
}
|
|
161
|
+
if (ch === '`') inTemplate = false
|
|
162
|
+
continue
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (ch === '/' && next === '/') {
|
|
166
|
+
inLineComment = true
|
|
167
|
+
i++
|
|
168
|
+
continue
|
|
169
|
+
}
|
|
170
|
+
if (ch === '/' && next === '*') {
|
|
171
|
+
inBlockComment = true
|
|
172
|
+
i++
|
|
173
|
+
continue
|
|
174
|
+
}
|
|
175
|
+
if (ch === "'") {
|
|
176
|
+
inSingle = true
|
|
177
|
+
continue
|
|
178
|
+
}
|
|
179
|
+
if (ch === '"') {
|
|
180
|
+
inDouble = true
|
|
181
|
+
continue
|
|
182
|
+
}
|
|
183
|
+
if (ch === '`') {
|
|
184
|
+
inTemplate = true
|
|
185
|
+
continue
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (ch === '(') depth++
|
|
189
|
+
else if (ch === ')') {
|
|
190
|
+
depth--
|
|
191
|
+
if (depth === 0) return i
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return -1
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Find the closing `]` of `plugins: [` starting at openBracketIndex. */
|
|
198
|
+
function findMatchingBracket(source, openBracketIndex) {
|
|
199
|
+
let depth = 0
|
|
200
|
+
let inSingle = false
|
|
201
|
+
let inDouble = false
|
|
202
|
+
let inTemplate = false
|
|
203
|
+
let inLineComment = false
|
|
204
|
+
let inBlockComment = false
|
|
205
|
+
|
|
206
|
+
for (let i = openBracketIndex; i < source.length; i++) {
|
|
207
|
+
const ch = source[i]
|
|
208
|
+
const next = source[i + 1]
|
|
209
|
+
|
|
210
|
+
if (inLineComment) {
|
|
211
|
+
if (ch === '\n') inLineComment = false
|
|
212
|
+
continue
|
|
213
|
+
}
|
|
214
|
+
if (inBlockComment) {
|
|
215
|
+
if (ch === '*' && next === '/') {
|
|
216
|
+
inBlockComment = false
|
|
217
|
+
i++
|
|
218
|
+
}
|
|
219
|
+
continue
|
|
220
|
+
}
|
|
221
|
+
if (inSingle) {
|
|
222
|
+
if (ch === '\\') {
|
|
223
|
+
i++
|
|
224
|
+
continue
|
|
225
|
+
}
|
|
226
|
+
if (ch === "'") inSingle = false
|
|
227
|
+
continue
|
|
228
|
+
}
|
|
229
|
+
if (inDouble) {
|
|
230
|
+
if (ch === '\\') {
|
|
231
|
+
i++
|
|
232
|
+
continue
|
|
233
|
+
}
|
|
234
|
+
if (ch === '"') inDouble = false
|
|
235
|
+
continue
|
|
236
|
+
}
|
|
237
|
+
if (inTemplate) {
|
|
238
|
+
if (ch === '\\') {
|
|
239
|
+
i++
|
|
240
|
+
continue
|
|
241
|
+
}
|
|
242
|
+
if (ch === '`') inTemplate = false
|
|
243
|
+
continue
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (ch === '/' && next === '/') {
|
|
247
|
+
inLineComment = true
|
|
248
|
+
i++
|
|
249
|
+
continue
|
|
250
|
+
}
|
|
251
|
+
if (ch === '/' && next === '*') {
|
|
252
|
+
inBlockComment = true
|
|
253
|
+
i++
|
|
254
|
+
continue
|
|
255
|
+
}
|
|
256
|
+
if (ch === "'") {
|
|
257
|
+
inSingle = true
|
|
258
|
+
continue
|
|
259
|
+
}
|
|
260
|
+
if (ch === '"') {
|
|
261
|
+
inDouble = true
|
|
262
|
+
continue
|
|
263
|
+
}
|
|
264
|
+
if (ch === '`') {
|
|
265
|
+
inTemplate = true
|
|
266
|
+
continue
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (ch === '[') depth++
|
|
270
|
+
else if (ch === ']') {
|
|
271
|
+
depth--
|
|
272
|
+
if (depth === 0) return i
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return -1
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function hasInspectorImport(source) {
|
|
279
|
+
return /from\s+['"]vite-plugin-vue-inspector['"]/.test(source)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function ensureImport(source) {
|
|
283
|
+
if (hasInspectorImport(source)) return { source, changed: false }
|
|
284
|
+
|
|
285
|
+
const importRe = /^import\s.+from\s+['"][^'"]+['"].*$/gm
|
|
286
|
+
let lastImportEnd = -1
|
|
287
|
+
for (const match of source.matchAll(importRe)) {
|
|
288
|
+
lastImportEnd = match.index + match[0].length
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (lastImportEnd === -1) {
|
|
292
|
+
return { source: `${IMPORT_LINE}\n${source}`, changed: true }
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const before = source.slice(0, lastImportEnd)
|
|
296
|
+
const after = source.slice(lastImportEnd)
|
|
297
|
+
return { source: `${before}\n${IMPORT_LINE}${after}`, changed: true }
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function isCanonicalInspectorCall(callText) {
|
|
301
|
+
const launchOk = /launchEditor\s*:\s*['"]cursor['"]/.test(callText)
|
|
302
|
+
const toggleOk = /toggleComboKey\s*:\s*['"]meta-alt['"]/.test(callText)
|
|
303
|
+
const onlyExpectedKeys = [...callText.matchAll(/(\w+)\s*:/g)]
|
|
304
|
+
.map((m) => m[1])
|
|
305
|
+
.every((key) => ['launchEditor', 'toggleComboKey'].includes(key))
|
|
306
|
+
return launchOk && toggleOk && onlyExpectedKeys
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function ensurePluginCall(source) {
|
|
310
|
+
const callMatch = /\bInspector\s*\(/.exec(source)
|
|
311
|
+
if (callMatch) {
|
|
312
|
+
const openParen = callMatch.index + callMatch[0].length - 1
|
|
313
|
+
const closeParen = findMatchingParen(source, openParen)
|
|
314
|
+
if (closeParen === -1) {
|
|
315
|
+
fail('Found Inspector( but could not find matching closing parenthesis')
|
|
316
|
+
}
|
|
317
|
+
const callText = source.slice(callMatch.index, closeParen + 1)
|
|
318
|
+
if (isCanonicalInspectorCall(callText)) {
|
|
319
|
+
return { source, changed: false, action: null }
|
|
320
|
+
}
|
|
321
|
+
const indentMatch = source.slice(0, callMatch.index).match(/(^|\n)([ \t]*)$/)
|
|
322
|
+
const indent = indentMatch ? indentMatch[2] : ' '
|
|
323
|
+
const formatted = formatPluginCall(indent)
|
|
324
|
+
return {
|
|
325
|
+
source: source.slice(0, callMatch.index) + formatted + source.slice(closeParen + 1),
|
|
326
|
+
changed: true,
|
|
327
|
+
action: 'updated',
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const pluginsMatch = /plugins\s*:\s*\[/.exec(source)
|
|
332
|
+
if (!pluginsMatch) {
|
|
333
|
+
fail('Could not find plugins: [...] in vite config')
|
|
334
|
+
}
|
|
335
|
+
const openBracket = pluginsMatch.index + pluginsMatch[0].length - 1
|
|
336
|
+
const closeBracket = findMatchingBracket(source, openBracket)
|
|
337
|
+
if (closeBracket === -1) {
|
|
338
|
+
fail('Could not find closing ] for plugins array')
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const arrayBody = source.slice(openBracket + 1, closeBracket)
|
|
342
|
+
const indentMatch = arrayBody.match(/\n([ \t]+)\S/)
|
|
343
|
+
const itemIndent = indentMatch ? indentMatch[1] : ' '
|
|
344
|
+
const closeIndent = itemIndent.slice(0, Math.max(0, itemIndent.length - 2)) || ' '
|
|
345
|
+
|
|
346
|
+
const trimmedBody = arrayBody.trimEnd()
|
|
347
|
+
const bodyEnd = openBracket + 1 + trimmedBody.length
|
|
348
|
+
const needsComma = trimmedBody.length > 0 && !/,\s*$/.test(trimmedBody)
|
|
349
|
+
const pluginLine = formatPluginCall(itemIndent)
|
|
350
|
+
const insertion = `${needsComma ? ',' : ''}\n${itemIndent}${pluginLine},\n${closeIndent}`
|
|
351
|
+
|
|
352
|
+
return {
|
|
353
|
+
source: source.slice(0, bodyEnd) + insertion + source.slice(closeBracket),
|
|
354
|
+
changed: true,
|
|
355
|
+
action: 'added',
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function syncPackageJson(projectRoot, version) {
|
|
360
|
+
const packageJsonPath = path.join(projectRoot, 'package.json')
|
|
361
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
362
|
+
fail(`package.json not found at ${packageJsonPath}`)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
let pkg
|
|
366
|
+
try {
|
|
367
|
+
pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
|
|
368
|
+
} catch (err) {
|
|
369
|
+
fail(`Failed to parse package.json: ${err.message}`)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
pkg.devDependencies =
|
|
373
|
+
pkg.devDependencies && typeof pkg.devDependencies === 'object' ? pkg.devDependencies : {}
|
|
374
|
+
|
|
375
|
+
const changes = []
|
|
376
|
+
if (pkg.dependencies?.[PACKAGE_NAME] !== undefined) {
|
|
377
|
+
delete pkg.dependencies[PACKAGE_NAME]
|
|
378
|
+
changes.push(`removed ${PACKAGE_NAME} from dependencies`)
|
|
379
|
+
}
|
|
380
|
+
if (pkg.devDependencies[PACKAGE_NAME] !== version) {
|
|
381
|
+
pkg.devDependencies[PACKAGE_NAME] = version
|
|
382
|
+
changes.push(`devDependencies.${PACKAGE_NAME} = ${version}`)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (changes.length > 0) {
|
|
386
|
+
fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8')
|
|
387
|
+
}
|
|
388
|
+
return changes
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function syncViteConfig(projectRoot) {
|
|
392
|
+
const viteConfigPath = findViteConfigPath(projectRoot)
|
|
393
|
+
if (!viteConfigPath) {
|
|
394
|
+
fail(
|
|
395
|
+
`No vite.config.(ts|mts|js|mjs) found in ${projectRoot}. Add a Vite config before syncing the inspector plugin.`,
|
|
396
|
+
)
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const configName = path.basename(viteConfigPath)
|
|
400
|
+
let source = fs.readFileSync(viteConfigPath, 'utf8')
|
|
401
|
+
const changes = []
|
|
402
|
+
|
|
403
|
+
const importResult = ensureImport(source)
|
|
404
|
+
source = importResult.source
|
|
405
|
+
if (importResult.changed) changes.push(`added import in ${configName}`)
|
|
406
|
+
|
|
407
|
+
const pluginResult = ensurePluginCall(source)
|
|
408
|
+
source = pluginResult.source
|
|
409
|
+
if (pluginResult.action === 'added') {
|
|
410
|
+
changes.push(`added Inspector() to plugins in ${configName}`)
|
|
411
|
+
} else if (pluginResult.action === 'updated') {
|
|
412
|
+
changes.push(`updated Inspector() options in ${configName}`)
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (importResult.changed || pluginResult.changed) {
|
|
416
|
+
fs.writeFileSync(viteConfigPath, source, 'utf8')
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return { changes, configName }
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function installAndCommit(viteConfigName) {
|
|
423
|
+
console.log('[sync-vite-plugin-vue-inspector] Running pnpm install…')
|
|
424
|
+
const installExitCode = runPnpm(['install'])
|
|
425
|
+
if (installExitCode !== 0) {
|
|
426
|
+
process.exit(installExitCode)
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const candidateFiles = ['package.json', 'pnpm-lock.yaml', viteConfigName].filter(Boolean)
|
|
430
|
+
const filesToStage = candidateFiles.filter((filePath) => fileDiffersFromHead(filePath))
|
|
431
|
+
if (filesToStage.length === 0) {
|
|
432
|
+
console.log('[sync-vite-plugin-vue-inspector] No related changes to commit.')
|
|
433
|
+
return
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const stageExitCode = stageExistingFiles(filesToStage)
|
|
437
|
+
if (stageExitCode !== 0) {
|
|
438
|
+
process.exit(stageExitCode)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
console.log(`[sync-vite-plugin-vue-inspector] Staged ${filesToStage.length} file(s)`)
|
|
442
|
+
console.log(`[sync-vite-plugin-vue-inspector] Auto-committing: ${COMMIT_MESSAGE}`)
|
|
443
|
+
const commitExitCode = runGit(['commit', '-m', COMMIT_MESSAGE]).status
|
|
444
|
+
if (commitExitCode !== 0) {
|
|
445
|
+
process.exit(commitExitCode)
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function main() {
|
|
450
|
+
if (!fs.existsSync(policyPath)) {
|
|
451
|
+
fail(`Could not find dependency policy: ${policyPath}`)
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const policy = JSON.parse(fs.readFileSync(policyPath, 'utf8'))
|
|
455
|
+
const version = resolvePluginVersion(policy)
|
|
456
|
+
if (!version) {
|
|
457
|
+
fail(
|
|
458
|
+
`${PACKAGE_NAME} is not listed in the dependency policy (managedDependencies.devDependencies)`,
|
|
459
|
+
)
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const pkgChanges = syncPackageJson(cwd, version)
|
|
463
|
+
const { changes: viteChanges, configName } = syncViteConfig(cwd)
|
|
464
|
+
const allChanges = [...pkgChanges, ...viteChanges]
|
|
465
|
+
|
|
466
|
+
if (allChanges.length === 0) {
|
|
467
|
+
console.log('[sync-vite-plugin-vue-inspector] Already up to date.')
|
|
468
|
+
return
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
console.log('[sync-vite-plugin-vue-inspector] Updated:')
|
|
472
|
+
for (const change of allChanges) {
|
|
473
|
+
console.log(` - ${change}`)
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
installAndCommit(configName)
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
main()
|