fg-devkit 1.2.0 → 1.3.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 +18 -0
- package/configs/dependency-policy.vue-workspace.json +1 -21
- package/configs/lefthook.yml +4 -0
- package/package.json +6 -1
- package/scripts/fg-devkit.mjs +100 -1
- package/scripts/prune-consumer-deps.mjs +7 -0
- package/scripts/refresh-dependency-policy-from-repos.mjs +13 -0
- package/scripts/sync-consumer-lefthook.mjs +67 -0
- package/scripts/sync-consumer-scripts.mjs +61 -0
package/README.md
CHANGED
|
@@ -52,6 +52,24 @@ pnpm exec fgd prune-consumer-deps
|
|
|
52
52
|
pnpm install
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
To sync standard consumer scripts to `fgd` commands:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pnpm exec fgd sync-consumer-scripts
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
To migrate from Husky + lint-staged to Lefthook:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pnpm exec fgd setup-lefthook
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Run full consumer setup in one command:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pnpm exec fgd full-consumer-setup
|
|
71
|
+
```
|
|
72
|
+
|
|
55
73
|
## tsconfig in consuming repos
|
|
56
74
|
|
|
57
75
|
Use `fgd sync-project-configs` (or `fgd sync-tooling-configs`) to write the local `tsconfig.json` template from `fg-devkit`.
|
|
@@ -49,10 +49,8 @@
|
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@chromatic-com/storybook": "5.0.1",
|
|
51
51
|
"@eslint/js": "9.39.1",
|
|
52
|
-
"@intlify/eslint-plugin-vue-i18n": "4.3.0",
|
|
53
52
|
"@intlify/unplugin-vue-i18n": "11.0.7",
|
|
54
53
|
"@playwright/test": "1.59.1",
|
|
55
|
-
"@rushstack/eslint-patch": "1.16.1",
|
|
56
54
|
"@storybook/addon-a11y": "10.1.10",
|
|
57
55
|
"@storybook/addon-docs": "10.1.10",
|
|
58
56
|
"@storybook/addon-vitest": "10.2.12",
|
|
@@ -62,45 +60,27 @@
|
|
|
62
60
|
"@tsconfig/node22": "22.0.5",
|
|
63
61
|
"@types/lodash-es": "4.17.12",
|
|
64
62
|
"@types/node": "22.16.5",
|
|
65
|
-
"@typescript-eslint/eslint-plugin": "8.57.2",
|
|
66
|
-
"@typescript-eslint/parser": "8.57.2",
|
|
67
63
|
"@vitest/browser": "3.2.4",
|
|
68
|
-
"@vitest/eslint-plugin": "1.6.14",
|
|
69
64
|
"@vue/compiler-dom": "3.5.29",
|
|
70
|
-
"@vue/eslint-config-prettier": "10.2.0",
|
|
71
65
|
"@vue/eslint-config-standard": "8.0.1",
|
|
72
|
-
"@vue/eslint-config-typescript": "14.7.0",
|
|
73
66
|
"@vue/server-renderer": "3.5.29",
|
|
74
67
|
"@vue/test-utils": "2.4.6",
|
|
75
|
-
"@vue/tsconfig": "0.8.1",
|
|
76
68
|
"@vuepic/vue-datepicker": "6.0.3",
|
|
77
69
|
"arg": "5.0.2",
|
|
78
70
|
"babel-eslint": "10.1.0",
|
|
79
|
-
"commitizen": "4.3.1",
|
|
80
|
-
"eslint": "10.0.2",
|
|
81
|
-
"eslint-plugin-prettier": "5.5.5",
|
|
82
71
|
"eslint-plugin-storybook": "10.1.10",
|
|
83
|
-
"eslint-plugin-vue": "10.8.0",
|
|
84
72
|
"globals": "15.11.0",
|
|
85
|
-
"husky": "9.1.6",
|
|
86
73
|
"jsdom": "26.1.0",
|
|
87
|
-
"jsonc-eslint-parser": "2.4.1",
|
|
88
|
-
"lint-staged": "16.4.0",
|
|
89
74
|
"postcss": "8.5.6",
|
|
90
|
-
"prettier": "3.8.1",
|
|
91
75
|
"sass": "1.97.3",
|
|
92
76
|
"start-server-and-test": "2.1.3",
|
|
93
77
|
"storybook": "10.2.12",
|
|
94
78
|
"tsx": "4.21.0",
|
|
95
|
-
"typescript": "5.9.3",
|
|
96
79
|
"vega": "6.2.0",
|
|
97
80
|
"vite-plugin-dts": "4.5.4",
|
|
98
81
|
"vite-plugin-vue-devtools": "8.0.7",
|
|
99
82
|
"vitest": "3.2.4",
|
|
100
|
-
"
|
|
101
|
-
"vue-tsc": "3.2.6",
|
|
102
|
-
"yaml": "2.8.3",
|
|
103
|
-
"yaml-eslint-parser": "1.3.1"
|
|
83
|
+
"yaml": "2.8.3"
|
|
104
84
|
}
|
|
105
85
|
},
|
|
106
86
|
"managedAnywhere": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fg-devkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Shared configs, scripts, and DX tooling for Vue / TypeScript frontend repos",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"./tsconfig.app.sync.json": "./configs/tsconfig.app.sync.json",
|
|
16
16
|
"./eslint.config.base.js": "./configs/eslint.config.base.js",
|
|
17
17
|
"./prettier.config.js": "./configs/prettier.config.js",
|
|
18
|
+
"./lefthook.yml": "./configs/lefthook.yml",
|
|
18
19
|
"./vscode-settings.json": "./configs/vscode-settings.json",
|
|
19
20
|
"./dependency-policy.vue-workspace.json": "./configs/dependency-policy.vue-workspace.json",
|
|
20
21
|
"./vuln-commit": "./scripts/vuln-commit.mjs",
|
|
@@ -24,6 +25,8 @@
|
|
|
24
25
|
"./scripts/sync-vscode-settings.mjs": "./scripts/sync-vscode-settings.mjs",
|
|
25
26
|
"./scripts/sync-tooling-configs.mjs": "./scripts/sync-tooling-configs.mjs",
|
|
26
27
|
"./scripts/sync-project-configs.mjs": "./scripts/sync-project-configs.mjs",
|
|
28
|
+
"./scripts/sync-consumer-scripts.mjs": "./scripts/sync-consumer-scripts.mjs",
|
|
29
|
+
"./scripts/sync-consumer-lefthook.mjs": "./scripts/sync-consumer-lefthook.mjs",
|
|
27
30
|
"./scripts/prune-consumer-deps.mjs": "./scripts/prune-consumer-deps.mjs",
|
|
28
31
|
"./scripts/check-dependency-policy.mjs": "./scripts/check-dependency-policy.mjs",
|
|
29
32
|
"./scripts/sync-dependency-policy.mjs": "./scripts/sync-dependency-policy.mjs",
|
|
@@ -60,11 +63,13 @@
|
|
|
60
63
|
"@typescript-eslint/parser": "8.58.2",
|
|
61
64
|
"@vitest/eslint-plugin": "1.6.16",
|
|
62
65
|
"@vue/eslint-config-prettier": "10.2.0",
|
|
66
|
+
"@vue/eslint-config-typescript": "14.7.0",
|
|
63
67
|
"@vue/tsconfig": "0.9.1",
|
|
64
68
|
"commitizen": "4.3.1",
|
|
65
69
|
"eslint": "10.2.1",
|
|
66
70
|
"eslint-plugin-prettier": "5.5.5",
|
|
67
71
|
"eslint-plugin-vue": "10.8.0",
|
|
72
|
+
"lefthook": "2.1.6",
|
|
68
73
|
"prettier": "3.8.3",
|
|
69
74
|
"typescript": "5.9.3",
|
|
70
75
|
"vue-eslint-parser": "10.4.0",
|
package/scripts/fg-devkit.mjs
CHANGED
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
* pnpm exec fg-devkit sync-project-configs (VS Code + tooling sync; overwrites config files)
|
|
9
9
|
* pnpm exec fg-devkit sync-tooling-configs (tooling sync only; overwrites config files)
|
|
10
10
|
* pnpm exec fg-devkit sync-vscode-settings
|
|
11
|
+
* pnpm exec fg-devkit sync-consumer-scripts
|
|
12
|
+
* pnpm exec fg-devkit setup-lefthook
|
|
11
13
|
* pnpm exec fg-devkit prune-consumer-deps [--dry-run]
|
|
14
|
+
* pnpm exec fg-devkit full-consumer-setup
|
|
12
15
|
* pnpm exec fg-devkit create-release [patch|minor|major]
|
|
13
16
|
* pnpm exec fg-devkit commit [cz-args...] (Commitizen; uses fg-devkit bundled cz adapter)
|
|
14
17
|
* pnpm exec fg-devkit commit-vuln (staged package.json version bumps → vuln() commit)
|
|
@@ -77,6 +80,79 @@ function runReleaseScript(args = []) {
|
|
|
77
80
|
return r.status ?? 1
|
|
78
81
|
}
|
|
79
82
|
|
|
83
|
+
/** Run pnpm install in the consuming repo after setup steps. */
|
|
84
|
+
function runPnpmInstall() {
|
|
85
|
+
const r = spawnSync('pnpm', ['install'], {
|
|
86
|
+
stdio: 'inherit',
|
|
87
|
+
cwd: process.cwd(),
|
|
88
|
+
env: process.env,
|
|
89
|
+
})
|
|
90
|
+
if (r.error) {
|
|
91
|
+
console.error('[fg-devkit]', r.error.message)
|
|
92
|
+
return 1
|
|
93
|
+
}
|
|
94
|
+
return r.status ?? 1
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Run Lefthook from fg-devkit bundled dependency set. */
|
|
98
|
+
function runBundledLefthook(args = []) {
|
|
99
|
+
let lefthookBin
|
|
100
|
+
try {
|
|
101
|
+
lefthookBin = require.resolve('lefthook/bin/index.js')
|
|
102
|
+
} catch {
|
|
103
|
+
console.error('[fg-devkit] Could not resolve bundled lefthook. Reinstall fg-devkit and retry.')
|
|
104
|
+
return 1
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const r = spawnSync(process.execPath, [lefthookBin, ...args], {
|
|
108
|
+
stdio: 'inherit',
|
|
109
|
+
cwd: process.cwd(),
|
|
110
|
+
env: process.env,
|
|
111
|
+
})
|
|
112
|
+
if (r.error) {
|
|
113
|
+
console.error('[fg-devkit]', r.error.message)
|
|
114
|
+
return 1
|
|
115
|
+
}
|
|
116
|
+
return r.status ?? 1
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Setup lefthook config and install git hooks in the consumer repository. */
|
|
120
|
+
function runSetupLefthook() {
|
|
121
|
+
const syncCode = runNode('sync-consumer-lefthook.mjs')
|
|
122
|
+
if (syncCode !== 0) return syncCode
|
|
123
|
+
return runBundledLefthook(['install', '--reset-hooks-path'])
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Full consumer setup flow:
|
|
128
|
+
* - Step 7: remove unnecessary deps
|
|
129
|
+
* - Sync required consumer scripts for fgd commands
|
|
130
|
+
* - Setup lefthook and migrate from husky/lint-staged
|
|
131
|
+
* - Step 3: sync project configs
|
|
132
|
+
* - Step 2: sync dependency policy
|
|
133
|
+
* - Then run pnpm install
|
|
134
|
+
*/
|
|
135
|
+
function runFullConsumerSetup() {
|
|
136
|
+
console.log('[fg-devkit] Running full consumer sync and setup')
|
|
137
|
+
|
|
138
|
+
const step7 = runNode('prune-consumer-deps.mjs')
|
|
139
|
+
if (step7 !== 0) return step7
|
|
140
|
+
|
|
141
|
+
const scriptsStep = runNode('sync-consumer-scripts.mjs')
|
|
142
|
+
if (scriptsStep !== 0) return scriptsStep
|
|
143
|
+
|
|
144
|
+
const hooksStep = runSetupLefthook()
|
|
145
|
+
if (hooksStep !== 0) return hooksStep
|
|
146
|
+
|
|
147
|
+
const step3 = runNode('sync-project-configs.mjs')
|
|
148
|
+
if (step3 !== 0) return step3
|
|
149
|
+
|
|
150
|
+
const step2 = runNode('sync-dependency-policy.mjs')
|
|
151
|
+
if (step2 !== 0) return step2
|
|
152
|
+
|
|
153
|
+
return runPnpmInstall()
|
|
154
|
+
}
|
|
155
|
+
|
|
80
156
|
/** Prompt release type in CLI before invoking release.sh to avoid a "stuck" terminal feeling. */
|
|
81
157
|
async function promptReleaseType(rl) {
|
|
82
158
|
console.log('\nSelect release type:')
|
|
@@ -220,6 +296,8 @@ const DIRECT_COMMANDS = {
|
|
|
220
296
|
'sync-project-configs': 'sync-project-configs.mjs',
|
|
221
297
|
'sync-tooling-configs': 'sync-tooling-configs.mjs',
|
|
222
298
|
'sync-vscode-settings': 'sync-vscode-settings.mjs',
|
|
299
|
+
'sync-consumer-scripts': 'sync-consumer-scripts.mjs',
|
|
300
|
+
'setup-lefthook': 'setup-lefthook',
|
|
223
301
|
'prune-consumer-deps': 'prune-consumer-deps.mjs',
|
|
224
302
|
}
|
|
225
303
|
|
|
@@ -233,7 +311,10 @@ Commands:
|
|
|
233
311
|
sync-project-configs VS Code + tooling sync (overwrites config files)
|
|
234
312
|
sync-tooling-configs Tooling sync only (overwrites config files)
|
|
235
313
|
sync-vscode-settings Copy shared VS Code settings into .vscode/settings.json
|
|
314
|
+
sync-consumer-scripts Enforce standard fgd scripts in consumer package.json
|
|
315
|
+
setup-lefthook Setup lefthook and migrate from husky/lint-staged
|
|
236
316
|
prune-consumer-deps [--dry-run] Remove consumer tooling deps bundled by fg-devkit
|
|
317
|
+
full-consumer-setup Run: step 7 -> scripts -> lefthook -> step 3 -> step 2 -> pnpm install
|
|
237
318
|
create-release [bump] Version bump, git push, GitHub release (patch|minor|major; omit = prompt)
|
|
238
319
|
(alias: createRelease)
|
|
239
320
|
commit [args...] Commitizen (git-cz) with fg-devkit bundled adapter
|
|
@@ -285,9 +366,19 @@ const MENU = [
|
|
|
285
366
|
},
|
|
286
367
|
{
|
|
287
368
|
key: '7',
|
|
288
|
-
label: 'Remove
|
|
369
|
+
label: 'Remove unnecessary deps in package.json',
|
|
289
370
|
run: () => runNode('prune-consumer-deps.mjs'),
|
|
290
371
|
},
|
|
372
|
+
{
|
|
373
|
+
key: '8',
|
|
374
|
+
label: 'Full consumer setup (7 -> scripts -> lefthook -> 3 -> 2 -> pnpm install)',
|
|
375
|
+
run: () => runFullConsumerSetup(),
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
key: '9',
|
|
379
|
+
label: 'Setup lefthook (migrate from husky/lint-staged)',
|
|
380
|
+
run: () => runSetupLefthook(),
|
|
381
|
+
},
|
|
291
382
|
]
|
|
292
383
|
|
|
293
384
|
async function runInteractiveMenu() {
|
|
@@ -348,6 +439,14 @@ async function main() {
|
|
|
348
439
|
}
|
|
349
440
|
|
|
350
441
|
if (sub) {
|
|
442
|
+
if (sub === 'setup-lefthook') {
|
|
443
|
+
process.exitCode = runSetupLefthook()
|
|
444
|
+
return
|
|
445
|
+
}
|
|
446
|
+
if (sub === 'full-consumer-setup') {
|
|
447
|
+
process.exitCode = runFullConsumerSetup()
|
|
448
|
+
return
|
|
449
|
+
}
|
|
351
450
|
if (sub === 'create-release' || sub === 'createRelease') {
|
|
352
451
|
process.exitCode = runReleaseScript(rest)
|
|
353
452
|
return
|
|
@@ -20,13 +20,20 @@ const BUNDLED_TOOLING_PACKAGES = new Set([
|
|
|
20
20
|
'@typescript-eslint/parser',
|
|
21
21
|
'@vitest/eslint-plugin',
|
|
22
22
|
'@vue/eslint-config-prettier',
|
|
23
|
+
'@vue/eslint-config-typescript',
|
|
23
24
|
'@vue/tsconfig',
|
|
25
|
+
'@rushstack/eslint-patch',
|
|
24
26
|
'commitizen',
|
|
25
27
|
'eslint',
|
|
26
28
|
'eslint-plugin-prettier',
|
|
27
29
|
'eslint-plugin-vue',
|
|
30
|
+
'husky',
|
|
31
|
+
'jsonc-eslint-parser',
|
|
32
|
+
'lint-staged',
|
|
33
|
+
'lefthook',
|
|
28
34
|
'prettier',
|
|
29
35
|
'typescript',
|
|
36
|
+
'yaml-eslint-parser',
|
|
30
37
|
'vue-eslint-parser',
|
|
31
38
|
'vue-tsc',
|
|
32
39
|
])
|
|
@@ -29,6 +29,7 @@ import { collectPinViolations } from './dependency-policy-pins.mjs'
|
|
|
29
29
|
|
|
30
30
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
31
31
|
const fgDevkitRoot = path.resolve(scriptDir, '..')
|
|
32
|
+
const fgDevkitPackageJsonPath = path.join(fgDevkitRoot, 'package.json')
|
|
32
33
|
|
|
33
34
|
const projectsRoot = process.argv[2]
|
|
34
35
|
? path.resolve(process.cwd(), process.argv[2])
|
|
@@ -41,6 +42,15 @@ const policyPath = process.argv[3]
|
|
|
41
42
|
/** Relative paths under projectsRoot whose package.json files are ignored (maintainer choice). */
|
|
42
43
|
/** Relative path prefixes under projectsRoot to skip when scanning (add repo names as needed). */
|
|
43
44
|
const SKIP_DIR_PREFIXES = []
|
|
45
|
+
const EXTRA_TOOLING_EXCLUDES = new Set(['husky', 'lint-staged', '@rushstack/eslint-patch', 'jsonc-eslint-parser', 'yaml-eslint-parser'])
|
|
46
|
+
const EXCLUDED_POLICY_PACKAGES = (() => {
|
|
47
|
+
try {
|
|
48
|
+
const pkg = JSON.parse(fs.readFileSync(fgDevkitPackageJsonPath, 'utf8'))
|
|
49
|
+
return new Set([...Object.keys(pkg.dependencies ?? {}), ...EXTRA_TOOLING_EXCLUDES])
|
|
50
|
+
} catch {
|
|
51
|
+
return EXTRA_TOOLING_EXCLUDES
|
|
52
|
+
}
|
|
53
|
+
})()
|
|
44
54
|
|
|
45
55
|
/** Recursively collect every package.json path under dir, skipping node_modules and .git. */
|
|
46
56
|
function walk(dir, acc = []) {
|
|
@@ -147,6 +157,9 @@ const outAny = {}
|
|
|
147
157
|
|
|
148
158
|
// Pick highest semver per package and assign to dependencies, devDependencies, or managedAnywhere.
|
|
149
159
|
for (const [name, u] of usage) {
|
|
160
|
+
if (EXCLUDED_POLICY_PACKAGES.has(name)) {
|
|
161
|
+
continue
|
|
162
|
+
}
|
|
150
163
|
if (u.partsList.length === 0) {
|
|
151
164
|
continue
|
|
152
165
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Syncs Lefthook setup into a consuming repo:
|
|
4
|
+
* - writes lefthook.yml from fg-devkit template
|
|
5
|
+
* - removes legacy .husky directory (if present)
|
|
6
|
+
* - removes legacy lint-staged config block from package.json
|
|
7
|
+
* - removes legacy prepare hook scripts for husky/lefthook bootstrap
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node node_modules/fg-devkit/scripts/sync-consumer-lefthook.mjs
|
|
11
|
+
* pnpm exec fg-devkit setup-lefthook
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from 'node:fs'
|
|
15
|
+
import path from 'node:path'
|
|
16
|
+
import { fileURLToPath } from 'node:url'
|
|
17
|
+
|
|
18
|
+
const projectRoot = process.cwd()
|
|
19
|
+
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
20
|
+
const fgRoot = path.resolve(scriptDir, '..')
|
|
21
|
+
|
|
22
|
+
const lefthookTemplate = path.join(fgRoot, 'configs', 'lefthook.yml')
|
|
23
|
+
const lefthookTarget = path.join(projectRoot, 'lefthook.yml')
|
|
24
|
+
const huskyDir = path.join(projectRoot, '.husky')
|
|
25
|
+
const packageJsonPath = path.join(projectRoot, 'package.json')
|
|
26
|
+
|
|
27
|
+
if (!fs.existsSync(lefthookTemplate)) {
|
|
28
|
+
console.error(`[sync-consumer-lefthook] Missing template: ${lefthookTemplate}`)
|
|
29
|
+
process.exit(1)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
33
|
+
console.error(`[sync-consumer-lefthook] package.json not found at ${packageJsonPath}`)
|
|
34
|
+
process.exit(1)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let pkg
|
|
38
|
+
try {
|
|
39
|
+
pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
|
|
40
|
+
} catch (err) {
|
|
41
|
+
console.error(`[sync-consumer-lefthook] Failed to parse package.json: ${err.message}`)
|
|
42
|
+
process.exit(1)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
pkg.scripts = pkg.scripts && typeof pkg.scripts === 'object' ? pkg.scripts : {}
|
|
46
|
+
if (
|
|
47
|
+
pkg.scripts.prepare &&
|
|
48
|
+
(pkg.scripts.prepare.includes('husky') || pkg.scripts.prepare.includes('setup-lefthook'))
|
|
49
|
+
) {
|
|
50
|
+
delete pkg.scripts.prepare
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (pkg['lint-staged'] !== undefined) {
|
|
54
|
+
delete pkg['lint-staged']
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
fs.copyFileSync(lefthookTemplate, lefthookTarget)
|
|
59
|
+
fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8')
|
|
60
|
+
if (fs.existsSync(huskyDir)) {
|
|
61
|
+
fs.rmSync(huskyDir, { recursive: true, force: true })
|
|
62
|
+
}
|
|
63
|
+
console.log('[sync-consumer-lefthook] Synced lefthook.yml and removed .husky/lint-staged legacy setup.')
|
|
64
|
+
} catch (err) {
|
|
65
|
+
console.error(`[sync-consumer-lefthook] ${err.message}`)
|
|
66
|
+
process.exit(1)
|
|
67
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Syncs standard fg-devkit npm scripts into a consuming repo package.json.
|
|
4
|
+
*
|
|
5
|
+
* This updates only known script keys and leaves all other scripts untouched.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node node_modules/fg-devkit/scripts/sync-consumer-scripts.mjs
|
|
9
|
+
* pnpm exec fg-devkit sync-consumer-scripts
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from 'node:fs'
|
|
13
|
+
import path from 'node:path'
|
|
14
|
+
|
|
15
|
+
const REQUIRED_SCRIPTS = {
|
|
16
|
+
'lint:ts': 'pnpm exec fgd typecheck',
|
|
17
|
+
lint: 'pnpm exec fgd lint --fix .',
|
|
18
|
+
'lint-check': 'pnpm exec fgd lint .',
|
|
19
|
+
'sync:vscode:settings': 'pnpm exec fgd sync-vscode-settings',
|
|
20
|
+
'create:release': 'pnpm exec fgd create-release',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function main() {
|
|
24
|
+
const packageJsonPath = path.join(process.cwd(), 'package.json')
|
|
25
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
26
|
+
console.error(`[sync-consumer-scripts] package.json not found at ${packageJsonPath}`)
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let pkg
|
|
31
|
+
try {
|
|
32
|
+
pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.error(`[sync-consumer-scripts] Failed to parse package.json: ${err.message}`)
|
|
35
|
+
process.exit(1)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
pkg.scripts = pkg.scripts && typeof pkg.scripts === 'object' ? pkg.scripts : {}
|
|
39
|
+
|
|
40
|
+
const changed = []
|
|
41
|
+
for (const [name, value] of Object.entries(REQUIRED_SCRIPTS)) {
|
|
42
|
+
if (pkg.scripts[name] !== value) {
|
|
43
|
+
pkg.scripts[name] = value
|
|
44
|
+
changed.push(name)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8')
|
|
49
|
+
|
|
50
|
+
if (changed.length === 0) {
|
|
51
|
+
console.log('[sync-consumer-scripts] package.json scripts already up to date.')
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log('[sync-consumer-scripts] Updated scripts:')
|
|
56
|
+
for (const name of changed) {
|
|
57
|
+
console.log(` - ${name}`)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
main()
|