fg-devkit 1.0.0 → 1.1.2

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 CHANGED
@@ -4,10 +4,66 @@ Shared settings and tools to improve the developer experience for Vue and TypeSc
4
4
 
5
5
  ## Quick command alias (zsh)
6
6
 
7
- To run `fg` instead of `pnpm exec fg`, add this alias:
7
+ To run `fgd` instead of `pnpm exec fg-devkit`, add this alias:
8
8
 
9
9
  ```bash
10
- echo "alias fg='pnpm exec fg'" >> ~/.zshrc && source ~/.zshrc
10
+ echo "alias fgd='pnpm exec fg-devkit'" >> ~/.zshrc && source ~/.zshrc
11
11
  ```
12
12
 
13
13
  This works in repos where `fg-devkit` is installed.
14
+
15
+ ## Bundled ESLint stack
16
+
17
+ `fg-devkit` ships its own ESLint stack (core + parser + plugins), so consuming repos do not need to install ESLint packages just to lint with the shared config.
18
+
19
+ Run lint via CLI:
20
+
21
+ ```bash
22
+ pnpm exec fgd lint .
23
+ pnpm exec fgd lint-fix .
24
+ ```
25
+
26
+ ## Bundled Prettier
27
+
28
+ `fg-devkit` also ships Prettier, so consuming repos can format using the bundled package.
29
+
30
+ Run formatting via CLI:
31
+
32
+ ```bash
33
+ pnpm exec fgd format
34
+ pnpm exec fgd format-check
35
+ ```
36
+
37
+ ## Bundled TypeScript
38
+
39
+ `fg-devkit` ships `vue-tsc` and `typescript`, so consuming repos can run Vue typecheck without installing local TS tooling.
40
+
41
+ Run typecheck via CLI:
42
+
43
+ ```bash
44
+ pnpm exec fgd typecheck
45
+ pnpm exec fgd typecheck-watch
46
+ ```
47
+
48
+ ## tsconfig in consuming repos
49
+
50
+ Use `fgd sync-project-configs` (or `fgd sync-tooling-configs`) to write the local `tsconfig.json` template from `fg-devkit`.
51
+
52
+ Do not use an extends-only `tsconfig.json` to `fg-devkit/tsconfig.app.sync.json` in consuming repos.
53
+ TypeScript resolves `include`/`exclude` relative to the extended config file location in `node_modules`,
54
+ which can cause `No inputs were found`.
55
+
56
+ The supported approach is: keep a local `tsconfig.json` file in each consuming repo and let sync overwrite
57
+ it with the shared app template.
58
+
59
+ ## Minimal local Prettier config for consuming repos
60
+
61
+ Use this as your local `prettier.config.js` to inherit defaults from `fg-devkit`:
62
+
63
+ ```js
64
+ import basePrettierConfig from 'fg-devkit/prettier.config.js'
65
+
66
+ export default {
67
+ ...basePrettierConfig,
68
+ }
69
+ ```
@@ -3,8 +3,10 @@
3
3
 
4
4
  import tseslint from '@typescript-eslint/eslint-plugin'
5
5
  import tsparser from '@typescript-eslint/parser'
6
+ import pluginI18n from '@intlify/eslint-plugin-vue-i18n'
6
7
  import pluginVitest from '@vitest/eslint-plugin'
7
8
  import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
9
+ import pluginPrettier from 'eslint-plugin-prettier'
8
10
  import pluginVue from 'eslint-plugin-vue'
9
11
  import { globalIgnores } from 'eslint/config'
10
12
  import vueParser from 'vue-eslint-parser'
@@ -23,9 +25,6 @@ export default function createBaseConfig(options = {}) {
23
25
  additionalSettings = {},
24
26
  } = options
25
27
 
26
- // Note: Optional plugins should be imported by the consuming project
27
- // This config accepts them via additionalPlugins option
28
-
29
28
  const defaultAdditionalIgnores = [
30
29
  'test-results/**',
31
30
  'playwright-report/**',
@@ -130,6 +129,8 @@ export default function createBaseConfig(options = {}) {
130
129
  files: ['**/*.vue', '**/*.js', '**/*.jsx', '**/*.cjs', '**/*.mjs', '**/*.ts', '**/*.tsx', '**/*.cts', '**/*.mts'],
131
130
  plugins: {
132
131
  '@typescript-eslint': tseslint,
132
+ ...(enablePrettier ? { prettier: pluginPrettier } : {}),
133
+ ...(enableI18n ? { '@intlify/vue-i18n': pluginI18n } : {}),
133
134
  ...additionalPlugins,
134
135
  },
135
136
  settings: {
@@ -172,12 +173,13 @@ export default function createBaseConfig(options = {}) {
172
173
  'no-useless-return': 'error',
173
174
  'no-useless-concat': 'error',
174
175
  '@typescript-eslint/no-unused-vars': [
175
- 'error',
176
+ 'warn',
176
177
  {
177
178
  argsIgnorePattern: '^_',
178
179
  varsIgnorePattern: '^_',
179
180
  },
180
181
  ],
182
+ 'padding-line-between-statements': ['error', { blankLine: 'always', prev: 'export', next: 'export' }],
181
183
  '@typescript-eslint/ban-ts-comment': 'off',
182
184
  '@typescript-eslint/explicit-function-return-type': 'off',
183
185
  '@typescript-eslint/no-var-requires': 'off',
@@ -197,9 +199,9 @@ export default function createBaseConfig(options = {}) {
197
199
  'eol-last': 'error',
198
200
  'no-lonely-if': 'error',
199
201
  // Prettier integration (if enabled and plugin provided)
200
- ...(enablePrettier && additionalPlugins.prettier ? { 'prettier/prettier': 'warn' } : {}),
202
+ ...(enablePrettier ? { 'prettier/prettier': 'warn' } : {}),
201
203
  // i18n rules (if enabled and plugin provided)
202
- ...(enableI18n && additionalPlugins['@intlify/vue-i18n']
204
+ ...(enableI18n
203
205
  ? {
204
206
  '@intlify/vue-i18n/no-missing-keys': 'error',
205
207
  '@intlify/vue-i18n/no-raw-text': [
@@ -1,7 +1,6 @@
1
1
  /**
2
- * Minimal ESLint flat config for apps using fg-devkit.
3
- * Copied to eslint.config.js by sync-tooling-configs / sync-project-configs.
4
- * Customize locally (plugins, rules) or pass options via createBaseConfig after syncing.
2
+ * ESLint sync template for Vue apps using fg-devkit.
3
+ * Mirrors the previously used project defaults so sync preserves current behavior.
5
4
  */
6
5
  import createBaseConfig from 'fg-devkit/eslint.config.base.js'
7
6
  import { fileURLToPath } from 'node:url'
@@ -9,11 +8,12 @@ import { fileURLToPath } from 'node:url'
9
8
  const tsconfigRootDir = fileURLToPath(new URL('.', import.meta.url))
10
9
 
11
10
  export default [
12
- {
13
- ignores: ['.yalc/**', '**/node_modules/**'],
14
- },
15
11
  ...createBaseConfig({
16
12
  tsconfigRootDir,
17
13
  tsconfigFiles: ['./tsconfig.json'],
14
+ extraNonTypeAwareFiles: ['playwright.config.ts', 'poeditor/**/*.ts'],
15
+ enablePrettier: true,
16
+ enableI18n: true,
17
+ i18nLocaleDir: './src/lang/*.json',
18
18
  }),
19
19
  ]
@@ -0,0 +1,6 @@
1
+ // Extend shared Prettier config from fg-devkit
2
+ import basePrettierConfig from 'fg-devkit/prettier.config.js'
3
+
4
+ export default {
5
+ ...basePrettierConfig,
6
+ }
@@ -1,38 +1,14 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/tsconfig",
3
3
  "extends": "fg-devkit/tsconfig.base.json",
4
- "include": [
5
- "env.d.ts",
6
- "src/**/*",
7
- "src/**/*.vue",
8
- "src/**/*.ts",
9
- "src/**/*.d.ts",
10
- "src/vuex.d.ts"
11
- ],
4
+ "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "src/**/*.ts", "src/**/*.d.ts", "src/vuex.d.ts"],
12
5
  "exclude": ["src/**/__tests__/*"],
13
6
  "compilerOptions": {
14
- "strict": true,
15
- "composite": true,
16
- "noEmit": true,
17
7
  "types": ["@intlify/unplugin-vue-i18n/messages", "vue-i18n", "vite/client"],
18
- "moduleResolution": "bundler",
19
- "resolvePackageJsonExports": true,
20
8
  "paths": {
21
9
  "@/*": ["./src/*"],
22
10
  "@intlify/*": ["./node_modules/@intlify/*"]
23
11
  },
24
- "baseUrl": ".",
25
- "allowJs": true,
26
- "esModuleInterop": true,
27
- "allowSyntheticDefaultImports": true,
28
- "noUnusedLocals": true,
29
- "noUnusedParameters": true,
30
- "skipLibCheck": true,
31
- "preserveSymlinks": false
32
- },
33
- "vueCompilerOptions": {
34
- "strictTemplates": true,
35
- "experimentalCompatMode": 2,
36
- "types": ["fds-vue-core"]
12
+ "baseUrl": "."
37
13
  }
38
14
  }
@@ -1,18 +1,26 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/tsconfig",
3
- "extends": "@vue/tsconfig/tsconfig.dom.json",
3
+ "extends": "./tsconfig.vue-dom.json",
4
4
  "compilerOptions": {
5
+ "target": "ES2022",
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "strict": true,
8
+ "moduleResolution": "bundler",
9
+ "resolvePackageJsonExports": true,
10
+ "noEmit": true,
11
+ "composite": true,
5
12
  "skipLibCheck": true,
6
13
  "resolveJsonModule": true,
7
14
  "allowJs": true,
15
+ "esModuleInterop": true,
16
+ "allowSyntheticDefaultImports": true,
8
17
  "noUnusedLocals": true,
9
18
  "noUnusedParameters": true,
10
- "paths": {
11
- "@/*": ["./src/*"]
12
- }
19
+ "preserveSymlinks": false
13
20
  },
14
21
  "vueCompilerOptions": {
15
22
  "strictTemplates": true,
23
+ "experimentalCompatMode": 2,
16
24
  "types": ["fds-vue-core"]
17
25
  }
18
26
  }
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "compilerOptions": {
4
+ "noEmit": true,
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "resolveJsonModule": true,
8
+ "allowImportingTsExtensions": true,
9
+ "moduleDetection": "force",
10
+ "jsx": "preserve",
11
+ "jsxImportSource": "vue",
12
+ "noImplicitThis": true,
13
+ "strict": true,
14
+ "verbatimModuleSyntax": true,
15
+ "target": "ESNext",
16
+ "useDefineForClassFields": true,
17
+ "esModuleInterop": true,
18
+ "forceConsistentCasingInFileNames": true,
19
+ "libReplacement": false,
20
+ "skipLibCheck": true
21
+ }
22
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "extends": "./tsconfig.vue-base.json",
4
+ "compilerOptions": {
5
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
6
+ "types": []
7
+ }
8
+ }
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "fg-devkit",
3
- "version": "1.0.0",
3
+ "version": "1.1.2",
4
4
  "description": "Shared configs, scripts, and DX tooling for Vue / TypeScript frontend repos",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
7
7
  "bin": {
8
- "fg": "./scripts/fg-devkit.mjs",
8
+ "fgd": "./scripts/fg-devkit.mjs",
9
9
  "fg-devkit": "./scripts/fg-devkit.mjs",
10
10
  "fg-vuln-commit": "./scripts/vuln-commit.mjs",
11
11
  "fds-vuln-commit": "./scripts/vuln-commit.mjs"
@@ -48,20 +48,25 @@
48
48
  "typescript",
49
49
  "vue"
50
50
  ],
51
- "peerDependencies": {
52
- "@typescript-eslint/eslint-plugin": "^8.57.0",
53
- "@typescript-eslint/parser": "^8.57.0",
54
- "@vitest/eslint-plugin": "^1.5.0",
55
- "@vue/eslint-config-prettier": "^10.0.0",
56
- "@vue/tsconfig": "^0.8.0",
57
- "eslint": "^9.0.0 || ^10.0.0",
58
- "eslint-plugin-vue": "^10.0.0",
59
- "typescript": ">=5.0.0",
60
- "vue-eslint-parser": "^10.0.0"
61
- },
62
- "peerDependenciesMeta": {
63
- "@vitest/eslint-plugin": {
64
- "optional": true
51
+ "config": {
52
+ "commitizen": {
53
+ "path": "./scripts/cz/cz-adapter.cjs"
65
54
  }
55
+ },
56
+ "dependencies": {
57
+ "@intlify/eslint-plugin-vue-i18n": "4.3.0",
58
+ "@typescript-eslint/eslint-plugin": "8.58.2",
59
+ "@typescript-eslint/parser": "8.58.2",
60
+ "@vitest/eslint-plugin": "1.6.16",
61
+ "@vue/eslint-config-prettier": "10.2.0",
62
+ "@vue/tsconfig": "0.9.1",
63
+ "commitizen": "4.3.1",
64
+ "eslint": "10.2.1",
65
+ "eslint-plugin-prettier": "5.5.5",
66
+ "eslint-plugin-vue": "10.8.0",
67
+ "prettier": "3.8.3",
68
+ "typescript": "5.9.3",
69
+ "vue-eslint-parser": "10.4.0",
70
+ "vue-tsc": "3.2.7"
66
71
  }
67
72
  }
@@ -4,6 +4,7 @@
4
4
  */
5
5
  module.exports = {
6
6
  prompter(cz, commit) {
7
+ const defaultType = process.env.FG_DEVKIT_CZ_DEFAULT_TYPE;
7
8
  const types = [
8
9
  { value: "feat", name: "feat(scope): Added" },
9
10
  { value: "fix", name: "fix(scope): Fixed" },
@@ -22,6 +23,7 @@ module.exports = {
22
23
  name: "change_type",
23
24
  message: "Select the type of change you are committing",
24
25
  choices: types,
26
+ default: defaultType && types.some((t) => t.value === defaultType) ? defaultType : undefined,
25
27
  },
26
28
  {
27
29
  type: "input",
@@ -5,12 +5,18 @@
5
5
  * Non-interactive (for scripts and automation):
6
6
  * pnpm exec fg-devkit check-deps [policy-file]
7
7
  * pnpm exec fg-devkit sync-deps [policy-file]
8
- * pnpm exec fg-devkit sync-project-configs (VS Code + Prettier + ESLint stub + tsconfig app template)
9
- * pnpm exec fg-devkit sync-tooling-configs (Prettier + ESLint stub + tsconfig app template only)
8
+ * pnpm exec fg-devkit sync-project-configs (VS Code + tooling sync; overwrites config files)
9
+ * pnpm exec fg-devkit sync-tooling-configs (tooling sync only; overwrites config files)
10
10
  * pnpm exec fg-devkit sync-vscode-settings
11
11
  * pnpm exec fg-devkit create-release [patch|minor|major]
12
- * pnpm exec fg-devkit commit [cz-args...] (Commitizen; uses package.json config.commitizen.path)
12
+ * pnpm exec fg-devkit commit [cz-args...] (Commitizen; uses fg-devkit bundled cz adapter)
13
13
  * pnpm exec fg-devkit commit-vuln (staged package.json version bumps → vuln() commit)
14
+ * pnpm exec fg-devkit lint [eslint-args...] (run ESLint with fg-devkit bundled packages)
15
+ * pnpm exec fg-devkit lint-fix [eslint-args...] (same as lint plus --fix)
16
+ * pnpm exec fg-devkit format [prettier-args...] (run Prettier with fg-devkit bundled package)
17
+ * pnpm exec fg-devkit format-check [prettier-args...] (same as format plus --check)
18
+ * pnpm exec fg-devkit typecheck [vue-tsc-args...] (run vue-tsc with fg-devkit bundled package)
19
+ * pnpm exec fg-devkit typecheck-watch [vue-tsc-args...] (same as typecheck plus --watch)
14
20
  * Interactive menu (no subcommand):
15
21
  * pnpm exec fg-devkit
16
22
  *
@@ -24,8 +30,10 @@ import readline from 'node:readline/promises'
24
30
  import path from 'node:path'
25
31
  import { fileURLToPath } from 'node:url'
26
32
  import { stdin as input, stdout as output } from 'node:process'
33
+ import { createRequire } from 'node:module'
27
34
 
28
35
  const scriptDir = path.dirname(fileURLToPath(import.meta.url))
36
+ const require = createRequire(import.meta.url)
29
37
 
30
38
  /** Run another script in this package via Node; inherits stdio and returns the child exit code. */
31
39
  function runNode(scriptRelative, args = [], options = {}) {
@@ -68,37 +76,140 @@ function runReleaseScript(args = []) {
68
76
  return r.status ?? 1
69
77
  }
70
78
 
79
+ /** Prompt release type in CLI before invoking release.sh to avoid a "stuck" terminal feeling. */
80
+ async function promptReleaseType(rl) {
81
+ console.log('\nSelect release type:')
82
+ console.log(' 1) patch')
83
+ console.log(' 2) minor')
84
+ console.log(' 3) major')
85
+ console.log(' 0) Cancel\n')
86
+ const choice = (await rl.question('Release type [1-3] (default: 1): ')).trim() || '1'
87
+ if (choice === '0') {
88
+ return null
89
+ }
90
+ if (choice === '1') {
91
+ return 'patch'
92
+ }
93
+ if (choice === '2') {
94
+ return 'minor'
95
+ }
96
+ if (choice === '3') {
97
+ return 'major'
98
+ }
99
+ console.error('[fg-devkit] Invalid release type selection.')
100
+ return null
101
+ }
102
+
71
103
  /**
72
- * Run Commitizen in the consumer repo (reads config.commitizen.path from package.json).
73
- * Tries pnpm exec cz, then pnpm exec git-cz, then npx commitizen git-cz.
104
+ * Run Commitizen from fg-devkit's bundled dependency set.
105
+ * Always forces fg-devkit's bundled cz adapter so it stays interactive.
74
106
  */
75
- function runCommitizen(args = []) {
76
- const cwd = process.cwd()
77
- const attempts = [
78
- () => spawnSync('pnpm', ['exec', 'cz', ...args], { stdio: 'inherit', cwd, env: process.env }),
79
- () => spawnSync('pnpm', ['exec', 'git-cz', ...args], { stdio: 'inherit', cwd, env: process.env }),
80
- () =>
81
- spawnSync('npx', ['--yes', 'commitizen', 'git-cz', ...args], {
82
- stdio: 'inherit',
83
- cwd,
84
- env: process.env,
85
- }),
86
- ]
87
- for (const run of attempts) {
88
- const r = run()
89
- if (r.error) {
90
- if (r.error.code === 'ENOENT') {
91
- continue
92
- }
93
- console.error('[fg-devkit]', r.error.message)
94
- return 1
95
- }
96
- return r.status ?? 1
107
+ function runCommitizen(args = [], extraEnv = {}) {
108
+ let bootstrapBin
109
+ let commitizenPkgDir
110
+ const adapterPath = path.join(scriptDir, 'cz', 'cz-adapter.cjs')
111
+ try {
112
+ bootstrapBin = require.resolve('commitizen/dist/cli/git-cz.js')
113
+ commitizenPkgDir = path.dirname(require.resolve('commitizen/package.json'))
114
+ } catch {
115
+ console.error('[fg-devkit] Could not resolve bundled commitizen. Reinstall fg-devkit and retry.')
116
+ return 1
117
+ }
118
+
119
+ const launcher = `
120
+ const { bootstrap } = require(${JSON.stringify(bootstrapBin)});
121
+ const argv = ['node', 'git-cz', ...JSON.parse(process.env.FG_DEVKIT_CZ_ARGS || '[]')];
122
+ bootstrap(
123
+ {
124
+ cliPath: ${JSON.stringify(commitizenPkgDir)},
125
+ config: { path: ${JSON.stringify(adapterPath)} },
126
+ },
127
+ argv
128
+ );
129
+ `
130
+
131
+ const r = spawnSync(process.execPath, ['-e', launcher], {
132
+ stdio: 'inherit',
133
+ cwd: process.cwd(),
134
+ env: {
135
+ ...process.env,
136
+ FG_DEVKIT_CZ_ARGS: JSON.stringify(args),
137
+ ...extraEnv,
138
+ },
139
+ })
140
+ if (r.error) {
141
+ console.error('[fg-devkit]', r.error.message)
142
+ return 1
143
+ }
144
+ return r.status ?? 1
145
+ }
146
+
147
+
148
+ /** Run ESLint from fg-devkit's bundled dependency set. */
149
+ function runBundledEslint(args = []) {
150
+ let eslintBin
151
+ try {
152
+ const eslintPkgPath = require.resolve('eslint/package.json')
153
+ eslintBin = path.join(path.dirname(eslintPkgPath), 'bin', 'eslint.js')
154
+ } catch {
155
+ console.error('[fg-devkit] Could not resolve bundled eslint. Reinstall fg-devkit and retry.')
156
+ return 1
157
+ }
158
+
159
+ const r = spawnSync(process.execPath, [eslintBin, ...args], {
160
+ stdio: 'inherit',
161
+ cwd: process.cwd(),
162
+ env: process.env,
163
+ })
164
+ if (r.error) {
165
+ console.error('[fg-devkit]', r.error.message)
166
+ return 1
167
+ }
168
+ return r.status ?? 1
169
+ }
170
+
171
+ /** Run Prettier from fg-devkit's bundled dependency set. */
172
+ function runBundledPrettier(args = []) {
173
+ let prettierBin
174
+ try {
175
+ prettierBin = require.resolve('prettier/bin/prettier.cjs')
176
+ } catch {
177
+ console.error('[fg-devkit] Could not resolve bundled prettier. Reinstall fg-devkit and retry.')
178
+ return 1
97
179
  }
98
- console.error(
99
- '[fg-devkit] Commitizen not found. Add devDependency "commitizen", set config.commitizen.path, then retry.',
100
- )
101
- return 1
180
+
181
+ const r = spawnSync(process.execPath, [prettierBin, ...args], {
182
+ stdio: 'inherit',
183
+ cwd: process.cwd(),
184
+ env: process.env,
185
+ })
186
+ if (r.error) {
187
+ console.error('[fg-devkit]', r.error.message)
188
+ return 1
189
+ }
190
+ return r.status ?? 1
191
+ }
192
+
193
+ /** Run vue-tsc from fg-devkit's bundled dependency set. */
194
+ function runBundledTypeScript(args = []) {
195
+ let vueTscBin
196
+ try {
197
+ vueTscBin = require.resolve('vue-tsc/bin/vue-tsc.js')
198
+ } catch {
199
+ console.error('[fg-devkit] Could not resolve bundled vue-tsc. Reinstall fg-devkit and retry.')
200
+ return 1
201
+ }
202
+
203
+ const r = spawnSync(process.execPath, [vueTscBin, ...args], {
204
+ stdio: 'inherit',
205
+ cwd: process.cwd(),
206
+ env: process.env,
207
+ })
208
+ if (r.error) {
209
+ console.error('[fg-devkit]', r.error.message)
210
+ return 1
211
+ }
212
+ return r.status ?? 1
102
213
  }
103
214
 
104
215
  /** Map subcommand name → script file (extra argv after subcommand is forwarded). */
@@ -117,13 +228,19 @@ function printHelp() {
117
228
  Commands:
118
229
  check-deps [policy-file] Validate package.json + pins against policy
119
230
  sync-deps [policy-file] Align declared versions to policy (existing keys only)
120
- sync-project-configs VS Code settings + Prettier + ESLint + tsconfig (app template)
121
- sync-tooling-configs Prettier + ESLint + tsconfig (app template; no VS Code)
231
+ sync-project-configs VS Code + tooling sync (overwrites config files)
232
+ sync-tooling-configs Tooling sync only (overwrites config files)
122
233
  sync-vscode-settings Copy shared VS Code settings into .vscode/settings.json
123
234
  create-release [bump] Version bump, git push, GitHub release (patch|minor|major; omit = prompt)
124
235
  (alias: createRelease)
125
- commit [args...] Commitizen (git-cz); uses config.commitizen.path in package.json
236
+ commit [args...] Commitizen (git-cz) with fg-devkit bundled adapter
126
237
  commit-vuln Commit staged dependency bumps as vuln() (alias: vuln-commit)
238
+ lint [eslint-args...] Run ESLint using fg-devkit bundled ESLint stack
239
+ lint-fix [eslint-args...] Run ESLint with --fix using fg-devkit bundled ESLint stack
240
+ format [prettier-args...] Run Prettier using fg-devkit bundled package
241
+ format-check [prettier-args...] Run Prettier with --check using fg-devkit bundled package
242
+ typecheck [vue-tsc-args...] Run vue-tsc using fg-devkit bundled package
243
+ typecheck-watch [vue-tsc-args...] Run vue-tsc with --watch using fg-devkit bundled package
127
244
 
128
245
  With no command, opens an interactive menu.
129
246
 
@@ -135,33 +252,33 @@ Options:
135
252
  const MENU = [
136
253
  {
137
254
  key: '1',
138
- label: 'Check dependency policy against package.json (check-deps)',
255
+ label: 'Check dependency policy',
139
256
  run: () => runNode('check-dependency-policy.mjs'),
140
257
  },
141
258
  {
142
259
  key: '2',
143
- label: 'Sync dependency versions from policy (sync-deps)',
260
+ label: 'Sync dependency policy',
144
261
  run: () => runNode('sync-dependency-policy.mjs'),
145
262
  },
146
263
  {
147
264
  key: '3',
148
- label: 'Sync project configs (VS Code + Prettier + ESLint + tsconfig app template)',
265
+ label: 'Sync configs (vscode, eslint, prettier, tsconfig)',
149
266
  run: () => runNode('sync-project-configs.mjs'),
150
267
  },
151
268
  {
152
269
  key: '4',
153
- label: 'Create release (version bump, push, gh release — run from package repo root)',
270
+ label: 'Create release',
154
271
  run: () => runReleaseScript(),
155
272
  },
156
273
  {
157
274
  key: '5',
158
- label: 'Commit (Commitizen — interactive conventional commit)',
275
+ label: 'Commit (Commitizen)',
159
276
  run: () => runCommitizen(),
160
277
  },
161
278
  {
162
279
  key: '6',
163
- label: 'Commit vulnerability bumps (staged package.json → vuln() message)',
164
- run: () => runNode('vuln-commit.mjs'),
280
+ label: 'Commit vulnerability (Commitizen)',
281
+ run: () => runCommitizen([], { FG_DEVKIT_CZ_DEFAULT_TYPE: 'vuln' }),
165
282
  },
166
283
  ]
167
284
 
@@ -189,18 +306,29 @@ async function runInteractiveMenu() {
189
306
  return 1
190
307
  }
191
308
 
192
- let exitCode = 0
193
- try {
194
- const out = item.run()
195
- if (typeof out === 'object' && out !== null && typeof out.then === 'function') {
196
- exitCode = await out
197
- } else if (typeof out === 'number') {
198
- exitCode = out
309
+ let out
310
+ if (item.key === '4') {
311
+ const bumpType = await promptReleaseType(rl)
312
+ if (!bumpType) {
313
+ rl.close()
314
+ return 0
199
315
  }
200
- } finally {
316
+ // Close menu readline before spawning interactive child processes.
317
+ rl.close()
318
+ out = runReleaseScript([bumpType])
319
+ } else {
320
+ // Close menu readline before spawning interactive child processes.
201
321
  rl.close()
322
+ out = item.run()
202
323
  }
203
- return exitCode
324
+
325
+ if (typeof out === 'object' && out !== null && typeof out.then === 'function') {
326
+ return await out
327
+ }
328
+ if (typeof out === 'number') {
329
+ return out
330
+ }
331
+ return 0
204
332
  }
205
333
 
206
334
  async function main() {
@@ -224,6 +352,30 @@ async function main() {
224
352
  process.exitCode = runNode('vuln-commit.mjs', rest)
225
353
  return
226
354
  }
355
+ if (sub === 'lint') {
356
+ process.exitCode = runBundledEslint(rest.length > 0 ? rest : ['.'])
357
+ return
358
+ }
359
+ if (sub === 'lint-fix') {
360
+ process.exitCode = runBundledEslint(rest.length > 0 ? ['--fix', ...rest] : ['--fix', '.'])
361
+ return
362
+ }
363
+ if (sub === 'format') {
364
+ process.exitCode = runBundledPrettier(rest.length > 0 ? rest : ['--write', '.'])
365
+ return
366
+ }
367
+ if (sub === 'format-check') {
368
+ process.exitCode = runBundledPrettier(rest.length > 0 ? ['--check', ...rest] : ['--check', '.'])
369
+ return
370
+ }
371
+ if (sub === 'typecheck') {
372
+ process.exitCode = runBundledTypeScript(rest.length > 0 ? rest : ['--noEmit', '-p', 'tsconfig.json'])
373
+ return
374
+ }
375
+ if (sub === 'typecheck-watch') {
376
+ process.exitCode = runBundledTypeScript(rest.length > 0 ? ['--watch', ...rest] : ['--noEmit', '--watch', '-p', 'tsconfig.json'])
377
+ return
378
+ }
227
379
  const script = DIRECT_COMMANDS[sub]
228
380
  if (!script) {
229
381
  console.error(`[fg-devkit] Unknown command: ${sub}`)
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * Syncs shared tooling files from fg-devkit into the repo root:
4
- * - prettier.config.js — full copy from fg-devkit
5
- * - eslint.config.js — copy of the minimal eslint.sync-stub.js (flat config + createBaseConfig)
6
- * - tsconfig.json — full copy of tsconfig.app.sync.json (Vue app defaults: include/exclude,
7
- * compilerOptions, vueCompilerOptions, extends fg-devkit/tsconfig.base.json)
4
+ * - prettier.config.js — overwritten from fg-devkit prettier sync template
5
+ * - eslint.config.js — overwritten from fg-devkit eslint sync template
6
+ * - tsconfig.json — overwritten from fg-devkit tsconfig app sync template
7
+ *
8
+ * This command is intentionally deterministic: each run rewrites files to the shared templates.
8
9
  *
9
10
  * Requires fg-devkit on disk (direct dependency or via fds-vue-core).
10
11
  *
@@ -15,11 +16,14 @@
15
16
 
16
17
  import fs from 'node:fs'
17
18
  import path from 'node:path'
19
+ import { fileURLToPath } from 'node:url'
18
20
 
19
21
  const projectRoot = process.cwd()
22
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url))
20
23
 
21
24
  function findFgDevkitPackageRoot() {
22
25
  const candidates = [
26
+ path.resolve(scriptDir, '..'),
23
27
  path.join(projectRoot, 'node_modules', 'fg-devkit'),
24
28
  path.join(projectRoot, 'node_modules', 'fds-vue-core', 'node_modules', 'fg-devkit'),
25
29
  ]
@@ -39,13 +43,13 @@ if (!fgRoot) {
39
43
  process.exit(1)
40
44
  }
41
45
 
42
- const prettierSrc = path.join(fgRoot, 'configs', 'prettier.config.js')
46
+ const prettierSrc = path.join(fgRoot, 'configs', 'prettier.sync-stub.js')
43
47
  const eslintStubSrc = path.join(fgRoot, 'configs', 'eslint.sync-stub.js')
44
48
  const tsconfigSrc = path.join(fgRoot, 'configs', 'tsconfig.app.sync.json')
45
49
 
46
50
  if (!fs.existsSync(prettierSrc) || !fs.existsSync(eslintStubSrc) || !fs.existsSync(tsconfigSrc)) {
47
51
  console.error(
48
- '[sync-tooling] Missing prettier.config.js, eslint.sync-stub.js, or tsconfig.app.sync.json inside fg-devkit package.',
52
+ '[sync-tooling] Missing prettier.sync-stub.js, eslint.sync-stub.js, or tsconfig.app.sync.json inside fg-devkit package.',
49
53
  )
50
54
  process.exit(1)
51
55
  }
@@ -54,9 +58,8 @@ try {
54
58
  fs.copyFileSync(prettierSrc, path.join(projectRoot, 'prettier.config.js'))
55
59
  fs.copyFileSync(eslintStubSrc, path.join(projectRoot, 'eslint.config.js'))
56
60
  fs.copyFileSync(tsconfigSrc, path.join(projectRoot, 'tsconfig.json'))
61
+ console.log('[sync-tooling] Updated prettier.config.js, eslint.config.js, and tsconfig.json.')
57
62
  } catch (err) {
58
63
  console.error(`[sync-tooling] ${err.message}`)
59
64
  process.exit(1)
60
65
  }
61
-
62
- console.log('[sync-tooling] Updated prettier.config.js, eslint.config.js, and tsconfig.json.')