@luxkit/cli 1.0.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.
Files changed (3) hide show
  1. package/README.md +323 -0
  2. package/dist/index.js +2011 -0
  3. package/package.json +56 -0
package/dist/index.js ADDED
@@ -0,0 +1,2011 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { program } from "commander";
5
+
6
+ // src/commands/fmt.ts
7
+ import path3 from "path";
8
+
9
+ // src/presets/fmt/electron.ts
10
+ var electronFmt = {
11
+ name: "electron",
12
+ description: "Vue 3 + Electron desktop app",
13
+ eslint: () => `import withVue from '@vue/eslint-config-typescript'
14
+ import withPrettier from '@vue/eslint-config-prettier/skip-formatting'
15
+ import pluginVue from 'eslint-plugin-vue'
16
+
17
+ export default [
18
+ ...pluginVue.configs['flat/recommended'],
19
+ ...withVue(),
20
+ ...withPrettier(),
21
+ {
22
+ rules: {
23
+ 'vue/multi-word-component-names': 'off',
24
+ '@typescript-eslint/no-explicit-any': 'warn',
25
+ '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
26
+ },
27
+ },
28
+ ]
29
+ `,
30
+ prettier: () => JSON.stringify(
31
+ {
32
+ semi: false,
33
+ singleQuote: true,
34
+ tabWidth: 2,
35
+ trailingComma: "all",
36
+ printWidth: 100,
37
+ endOfLine: "lf"
38
+ },
39
+ null,
40
+ 2
41
+ ) + "\n",
42
+ prettierIgnore: () => `# Dependencies
43
+ node_modules/
44
+ pnpm-lock.yaml
45
+ package-lock.json
46
+
47
+ # Build outputs
48
+ dist/
49
+ release/
50
+ out/
51
+ *.tsbuildinfo
52
+
53
+ # Logs
54
+ *.log
55
+ logs/
56
+
57
+ # Environment files
58
+ .env
59
+ .env.local
60
+ .env.*.local
61
+
62
+ # IDE files
63
+ .vscode/
64
+ .idea/
65
+ *.swp
66
+ *.swo
67
+
68
+ # Coverage
69
+ coverage/
70
+
71
+ # Static assets
72
+ *.svg
73
+ *.png
74
+ *.jpg
75
+ *.jpeg
76
+ *.gif
77
+ *.ico
78
+ *.woff
79
+ *.woff2
80
+ *.ttf
81
+ *.eot
82
+ `,
83
+ stylelint: () => `export default {
84
+ plugins: ['stylelint-order', '@stylistic/stylelint-plugin'],
85
+ extends: [
86
+ 'stylelint-config-standard-scss',
87
+ 'stylelint-config-recess-order',
88
+ ],
89
+ overrides: [
90
+ {
91
+ files: ['**/*.vue'],
92
+ customSyntax: 'postcss-html',
93
+ },
94
+ ],
95
+ rules: {
96
+ 'selector-class-pattern': null,
97
+ 'scss/dollar-variable-pattern': null,
98
+ 'scss/percent-placeholder-pattern': null,
99
+ 'scss/at-mixin-pattern': null,
100
+ 'order/properties-order': null,
101
+ },
102
+ }
103
+ `,
104
+ stylelintIgnore: () => `# Dependencies
105
+ node_modules/
106
+ pnpm-lock.yaml
107
+
108
+ # Build outputs
109
+ dist/
110
+ release/
111
+ out/
112
+ *.tsbuildinfo
113
+
114
+ # Logs
115
+ *.log
116
+
117
+ # Environment files
118
+ .env
119
+ .env.local
120
+
121
+ # Coverage
122
+ coverage/
123
+
124
+ # Static assets
125
+ *.svg
126
+ *.png
127
+ *.jpg
128
+ *.jpeg
129
+ *.gif
130
+ *.ico
131
+ `,
132
+ cspell: () => JSON.stringify(
133
+ {
134
+ $schema: "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json",
135
+ version: "0.2",
136
+ language: "en,en-US",
137
+ allowCompoundWords: true,
138
+ words: ["vite", "pinia", "vueuse", "unplugin", "trw", "electron", "electron-builder"],
139
+ ignorePaths: ["pnpm-lock.yaml", "/coverage/", "*.svg", "*.png"]
140
+ },
141
+ null,
142
+ 2
143
+ ) + "\n",
144
+ editorconfig: () => `root = true
145
+
146
+ [*]
147
+ charset = utf-8
148
+ indent_style = space
149
+ indent_size = 2
150
+ end_of_line = lf
151
+ insert_final_newline = true
152
+ trim_trailing_whitespace = true
153
+
154
+ [*.md]
155
+ trim_trailing_whitespace = false
156
+ `,
157
+ dependencies: {
158
+ dev: [
159
+ "eslint",
160
+ "@vue/eslint-config-typescript",
161
+ "@vue/eslint-config-prettier",
162
+ "eslint-plugin-vue",
163
+ "prettier",
164
+ "stylelint",
165
+ "stylelint-config-standard-scss",
166
+ "stylelint-order",
167
+ "stylelint-scss",
168
+ "@stylistic/stylelint-plugin",
169
+ "postcss-html",
170
+ "postcss-scss",
171
+ "cspell"
172
+ ]
173
+ },
174
+ scripts: {
175
+ lint: "eslint .",
176
+ "lint:fix": 'eslint "src/**/*.{js,ts,vue}" --fix',
177
+ format: 'prettier --write "src/**/*.{ts,js,json,vue,css,scss}"',
178
+ "format:check": 'prettier --check "src/**/*.{ts,js,json,vue,css,scss}"',
179
+ stylelint: 'stylelint "src/**/*.{css,scss,vue}"',
180
+ "stylelint:fix": 'stylelint "src/**/*.{css,scss,vue}" --fix',
181
+ cspell: 'cspell --gitignore "src/**/*"',
182
+ "type:check": "vue-tsc --noEmit",
183
+ "code:check": "<pm> lint && <pm> format:check",
184
+ "code:fix": "<pm> lint:fix && <pm> format",
185
+ "code:check:all": "<pm> lint && <pm> format:check && <pm> stylelint && <pm> cspell",
186
+ "code:fix:all": "<pm> lint:fix && <pm> format && <pm> stylelint:fix"
187
+ }
188
+ };
189
+
190
+ // src/presets/fmt/nest.ts
191
+ var nestFmt = {
192
+ name: "nest",
193
+ description: "NestJS backend (enhancement mode)",
194
+ // Never overwrite eslint.config.mjs — NestJS has its own ESLint setup
195
+ neverOverwrite: ["eslint.config.mjs"],
196
+ // Always overwrite .prettierrc — ensure consistent formatting
197
+ forceOverwrite: [".prettierrc"],
198
+ // No ESLint generation — Nest CLI manages its own eslint.config.mjs
199
+ prettier: () => JSON.stringify(
200
+ {
201
+ semi: false,
202
+ singleQuote: true,
203
+ tabWidth: 2,
204
+ trailingComma: "all",
205
+ printWidth: 100,
206
+ endOfLine: "lf"
207
+ },
208
+ null,
209
+ 2
210
+ ) + "\n",
211
+ prettierIgnore: () => `# Dependencies
212
+ node_modules/
213
+ pnpm-lock.yaml
214
+ package-lock.json
215
+
216
+ # Build outputs
217
+ dist/
218
+ build/
219
+ *.tsbuildinfo
220
+
221
+ # Logs
222
+ *.log
223
+ logs/
224
+
225
+ # Environment files
226
+ .env
227
+ .env.local
228
+ .env.*.local
229
+
230
+ # IDE files
231
+ .vscode/
232
+
233
+ # Coverage
234
+ coverage/
235
+
236
+ # Static assets
237
+ *.svg
238
+ *.png
239
+ *.jpg
240
+ *.jpeg
241
+ *.gif
242
+ *.ico
243
+ *.woff
244
+ *.woff2
245
+ *.ttf
246
+ *.eot
247
+ `,
248
+ // No stylelint for NestJS
249
+ cspell: () => JSON.stringify(
250
+ {
251
+ $schema: "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json",
252
+ version: "0.2",
253
+ language: "en,en-US",
254
+ allowCompoundWords: true,
255
+ words: ["nestjs", "typeorm", "dtos"],
256
+ ignorePaths: ["pnpm-lock.yaml", "*.svg", "*.png"]
257
+ },
258
+ null,
259
+ 2
260
+ ) + "\n",
261
+ editorconfig: () => `root = true
262
+
263
+ [*]
264
+ charset = utf-8
265
+ indent_style = space
266
+ indent_size = 2
267
+ end_of_line = lf
268
+ insert_final_newline = true
269
+ trim_trailing_whitespace = true
270
+
271
+ [*.md]
272
+ trim_trailing_whitespace = false
273
+ `,
274
+ dependencies: {
275
+ dev: ["prettier", "cspell"]
276
+ },
277
+ // NestJS: only append new scripts, don't conflict with existing ones
278
+ scripts: {
279
+ cspell: 'cspell --gitignore "src/**/*"',
280
+ "type:check": "tsc --noEmit",
281
+ "code:check": "<pm> lint && <pm> format:check",
282
+ "code:check:all": "<pm> lint && <pm> format:check && <pm> cspell"
283
+ }
284
+ };
285
+
286
+ // src/presets/fmt/node.ts
287
+ var nodeFmt = {
288
+ name: "node",
289
+ description: "Node.js CLI / scripts",
290
+ eslint: () => `// @ts-check
291
+ import eslint from '@eslint/js'
292
+ import { defineConfig } from 'eslint/config'
293
+ import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
294
+ import tseslint from 'typescript-eslint'
295
+
296
+ export default defineConfig(
297
+ {
298
+ ignores: ['eslint.config.mjs', 'dist/', 'vitest.config.ts', 'tsup.config.ts'],
299
+ },
300
+ eslint.configs.recommended,
301
+ ...tseslint.configs.recommended,
302
+ eslintPluginPrettierRecommended,
303
+ {
304
+ files: ['src/**/*.ts'],
305
+ languageOptions: {
306
+ sourceType: 'module',
307
+ parserOptions: {
308
+ projectService: true,
309
+ tsconfigRootDir: import.meta.dirname,
310
+ },
311
+ },
312
+ },
313
+ {
314
+ files: ['scripts/**/*.ts', 'tests/**/*.ts'],
315
+ languageOptions: {
316
+ sourceType: 'module',
317
+ },
318
+ },
319
+ {
320
+ rules: {
321
+ '@typescript-eslint/no-explicit-any': 'warn',
322
+ '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
323
+ },
324
+ },
325
+ )
326
+ `,
327
+ prettier: () => JSON.stringify(
328
+ {
329
+ semi: true,
330
+ trailingComma: "all",
331
+ singleQuote: true,
332
+ printWidth: 100,
333
+ tabWidth: 3,
334
+ useTabs: false,
335
+ quoteProps: "as-needed",
336
+ jsxSingleQuote: true,
337
+ bracketSpacing: true,
338
+ bracketSameLine: false,
339
+ arrowParens: "avoid",
340
+ endOfLine: "lf",
341
+ proseWrap: "preserve",
342
+ htmlWhitespaceSensitivity: "css",
343
+ embeddedLanguageFormatting: "auto"
344
+ },
345
+ null,
346
+ 2
347
+ ) + "\n",
348
+ prettierIgnore: () => `# Dependencies
349
+ node_modules/
350
+ bun.lock
351
+ package-lock.json
352
+
353
+ # Build outputs
354
+ dist/
355
+ build/
356
+ *.tsbuildinfo
357
+
358
+ # Logs
359
+ *.log
360
+ logs/
361
+
362
+ # Environment files
363
+ .env
364
+ .env.local
365
+ .env.*.local
366
+
367
+ # IDE files
368
+ .vscode/
369
+
370
+ # Coverage
371
+ coverage/
372
+
373
+ # Static assets
374
+ *.svg
375
+ *.png
376
+ *.jpg
377
+ *.jpeg
378
+ *.gif
379
+ *.ico
380
+ *.woff
381
+ *.woff2
382
+ *.ttf
383
+ *.eot
384
+ `,
385
+ // No stylelint for node projects
386
+ cspell: () => JSON.stringify(
387
+ {
388
+ $schema: "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json",
389
+ version: "0.2",
390
+ language: "en,en-US",
391
+ allowCompoundWords: true,
392
+ words: [],
393
+ ignorePaths: ["bun.lock", "*.svg", "*.png"]
394
+ },
395
+ null,
396
+ 2
397
+ ) + "\n",
398
+ editorconfig: () => `root = true
399
+
400
+ [*]
401
+ charset = utf-8
402
+ indent_style = space
403
+ indent_size = 3
404
+ end_of_line = lf
405
+ insert_final_newline = true
406
+ trim_trailing_whitespace = true
407
+
408
+ [*.md]
409
+ trim_trailing_whitespace = false
410
+ `,
411
+ dependencies: {
412
+ dev: [
413
+ "@eslint/js",
414
+ "eslint",
415
+ "typescript-eslint",
416
+ "eslint-plugin-prettier",
417
+ "eslint-config-prettier",
418
+ "prettier",
419
+ "cspell"
420
+ ]
421
+ },
422
+ scripts: {
423
+ lint: "eslint .",
424
+ "lint:fix": 'eslint "src/**/*.{js,ts}" --fix',
425
+ format: 'prettier --write "src/**/*.{ts,js,json}"',
426
+ "format:check": 'prettier --check "src/**/*.{ts,js,json}"',
427
+ cspell: 'cspell --gitignore "src/**/*"',
428
+ "type:check": "tsc --noEmit",
429
+ "code:check": "<pm> lint && <pm> format:check",
430
+ "code:fix": "<pm> lint:fix && <pm> format",
431
+ "code:check:all": "<pm> lint && <pm> format:check && <pm> cspell",
432
+ "code:fix:all": "<pm> lint:fix && <pm> format"
433
+ }
434
+ };
435
+
436
+ // src/presets/fmt/uniapp.ts
437
+ var uniappFmt = {
438
+ name: "uniapp",
439
+ description: "Vue 3 + UniApp WeChat mini program",
440
+ eslint: () => `import withVue from '@vue/eslint-config-typescript'
441
+ import withPrettier from '@vue/eslint-config-prettier/skip-formatting'
442
+ import pluginVue from 'eslint-plugin-vue'
443
+
444
+ export default [
445
+ ...pluginVue.configs['flat/recommended'],
446
+ ...withVue(),
447
+ ...withPrettier(),
448
+ {
449
+ rules: {
450
+ 'vue/multi-word-component-names': 'off',
451
+ '@typescript-eslint/no-explicit-any': 'warn',
452
+ '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
453
+ },
454
+ },
455
+ ]
456
+ `,
457
+ prettier: () => JSON.stringify(
458
+ {
459
+ semi: false,
460
+ singleQuote: true,
461
+ tabWidth: 2,
462
+ trailingComma: "all",
463
+ printWidth: 100,
464
+ endOfLine: "lf"
465
+ },
466
+ null,
467
+ 2
468
+ ) + "\n",
469
+ prettierIgnore: () => `# Dependencies
470
+ node_modules/
471
+ pnpm-lock.yaml
472
+ package-lock.json
473
+
474
+ # Build outputs (UniApp \u7F16\u8BD1\u8F93\u51FA)
475
+ dist/
476
+ unpackage/
477
+
478
+ # Logs
479
+ *.log
480
+ logs/
481
+
482
+ # Environment files
483
+ .env
484
+ .env.local
485
+ .env.*.local
486
+
487
+ # IDE files
488
+ .vscode/
489
+ .idea/
490
+ *.swp
491
+ *.swo
492
+
493
+ # Coverage
494
+ coverage/
495
+
496
+ # Static assets
497
+ *.svg
498
+ *.png
499
+ *.jpg
500
+ *.jpeg
501
+ *.gif
502
+ *.ico
503
+ *.woff
504
+ *.woff2
505
+ *.ttf
506
+ *.eot
507
+ `,
508
+ stylelint: () => `export default {
509
+ plugins: ['stylelint-order', '@stylistic/stylelint-plugin'],
510
+ extends: [
511
+ 'stylelint-config-standard-scss',
512
+ 'stylelint-config-recess-order',
513
+ ],
514
+ overrides: [
515
+ {
516
+ files: ['**/*.vue'],
517
+ customSyntax: 'postcss-html',
518
+ },
519
+ ],
520
+ rules: {
521
+ 'selector-class-pattern': null,
522
+ 'scss/dollar-variable-pattern': null,
523
+ 'scss/percent-placeholder-pattern': null,
524
+ 'scss/at-mixin-pattern': null,
525
+ 'order/properties-order': null,
526
+ },
527
+ }
528
+ `,
529
+ stylelintIgnore: () => `# Dependencies
530
+ node_modules/
531
+ pnpm-lock.yaml
532
+
533
+ # Build outputs (UniApp \u7F16\u8BD1\u8F93\u51FA)
534
+ dist/
535
+ unpackage/
536
+
537
+ # Logs
538
+ *.log
539
+
540
+ # Environment files
541
+ .env
542
+ .env.local
543
+
544
+ # Coverage
545
+ coverage/
546
+
547
+ # Static assets
548
+ *.svg
549
+ *.png
550
+ *.jpg
551
+ *.jpeg
552
+ *.gif
553
+ *.ico
554
+ `,
555
+ cspell: () => JSON.stringify(
556
+ {
557
+ $schema: "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json",
558
+ version: "0.2",
559
+ language: "en,en-US",
560
+ allowCompoundWords: true,
561
+ words: ["vite", "pinia", "vueuse", "unplugin", "trw", "uniapp"],
562
+ ignorePaths: ["pnpm-lock.yaml", "/coverage/", "*.svg", "*.png"]
563
+ },
564
+ null,
565
+ 2
566
+ ) + "\n",
567
+ editorconfig: () => `root = true
568
+
569
+ [*]
570
+ charset = utf-8
571
+ indent_style = space
572
+ indent_size = 2
573
+ end_of_line = lf
574
+ insert_final_newline = true
575
+ trim_trailing_whitespace = true
576
+
577
+ [*.md]
578
+ trim_trailing_whitespace = false
579
+ `,
580
+ dependencies: {
581
+ dev: [
582
+ "eslint",
583
+ "@vue/eslint-config-typescript",
584
+ "@vue/eslint-config-prettier",
585
+ "eslint-plugin-vue",
586
+ "prettier",
587
+ "stylelint",
588
+ "stylelint-config-standard-scss",
589
+ "stylelint-order",
590
+ "stylelint-scss",
591
+ "@stylistic/stylelint-plugin",
592
+ "postcss-html",
593
+ "postcss-scss",
594
+ "cspell"
595
+ ]
596
+ },
597
+ scripts: {
598
+ lint: "eslint .",
599
+ "lint:fix": 'eslint "src/**/*.{js,ts,vue}" --fix',
600
+ format: 'prettier --write "src/**/*.{ts,js,json,vue,css,scss}"',
601
+ "format:check": 'prettier --check "src/**/*.{ts,js,json,vue,css,scss}"',
602
+ stylelint: 'stylelint "src/**/*.{css,scss,vue}"',
603
+ "stylelint:fix": 'stylelint "src/**/*.{css,scss,vue}" --fix',
604
+ cspell: 'cspell --gitignore "src/**/*"',
605
+ "type:check": "vue-tsc --noEmit",
606
+ "code:check": "<pm> lint && <pm> format:check",
607
+ "code:fix": "<pm> lint:fix && <pm> format",
608
+ "code:check:all": "<pm> lint && <pm> format:check && <pm> stylelint && <pm> cspell",
609
+ "code:fix:all": "<pm> lint:fix && <pm> format && <pm> stylelint:fix"
610
+ }
611
+ };
612
+
613
+ // src/presets/fmt/web.ts
614
+ var webFmt = {
615
+ name: "web",
616
+ description: "Vue 3 Web frontend (Vite + Vue + TypeScript)",
617
+ eslint: () => `import withVue from '@vue/eslint-config-typescript'
618
+ import withPrettier from '@vue/eslint-config-prettier/skip-formatting'
619
+ import pluginVue from 'eslint-plugin-vue'
620
+
621
+ export default [
622
+ ...pluginVue.configs['flat/recommended'],
623
+ ...withVue(),
624
+ ...withPrettier(),
625
+ {
626
+ rules: {
627
+ 'vue/multi-word-component-names': 'off',
628
+ '@typescript-eslint/no-explicit-any': 'warn',
629
+ '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
630
+ },
631
+ },
632
+ ]
633
+ `,
634
+ prettier: () => JSON.stringify(
635
+ {
636
+ semi: false,
637
+ singleQuote: true,
638
+ tabWidth: 2,
639
+ trailingComma: "all",
640
+ printWidth: 100,
641
+ endOfLine: "lf"
642
+ },
643
+ null,
644
+ 2
645
+ ) + "\n",
646
+ prettierIgnore: () => `# Dependencies
647
+ node_modules/
648
+ pnpm-lock.yaml
649
+ package-lock.json
650
+
651
+ # Build outputs
652
+ dist/
653
+ *.tsbuildinfo
654
+
655
+ # Logs
656
+ *.log
657
+ logs/
658
+
659
+ # Environment files
660
+ .env
661
+ .env.local
662
+ .env.*.local
663
+
664
+ # IDE files
665
+ .vscode/
666
+ .idea/
667
+ *.swp
668
+ *.swo
669
+
670
+ # Coverage
671
+ coverage/
672
+
673
+ # Static assets
674
+ *.svg
675
+ *.png
676
+ *.jpg
677
+ *.jpeg
678
+ *.gif
679
+ *.ico
680
+ *.woff
681
+ *.woff2
682
+ *.ttf
683
+ *.eot
684
+ `,
685
+ stylelint: () => `export default {
686
+ plugins: ['stylelint-order', '@stylistic/stylelint-plugin'],
687
+ extends: [
688
+ 'stylelint-config-standard-scss',
689
+ 'stylelint-config-recess-order',
690
+ ],
691
+ overrides: [
692
+ {
693
+ files: ['**/*.vue'],
694
+ customSyntax: 'postcss-html',
695
+ },
696
+ ],
697
+ rules: {
698
+ 'selector-class-pattern': null,
699
+ 'scss/dollar-variable-pattern': null,
700
+ 'scss/percent-placeholder-pattern': null,
701
+ 'scss/at-mixin-pattern': null,
702
+ 'order/properties-order': null,
703
+ },
704
+ }
705
+ `,
706
+ stylelintIgnore: () => `# Dependencies
707
+ node_modules/
708
+ pnpm-lock.yaml
709
+
710
+ # Build outputs
711
+ dist/
712
+ *.tsbuildinfo
713
+
714
+ # Logs
715
+ *.log
716
+
717
+ # Environment files
718
+ .env
719
+ .env.local
720
+
721
+ # Coverage
722
+ coverage/
723
+
724
+ # Static assets
725
+ *.svg
726
+ *.png
727
+ *.jpg
728
+ *.jpeg
729
+ *.gif
730
+ *.ico
731
+ `,
732
+ cspell: () => JSON.stringify(
733
+ {
734
+ $schema: "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json",
735
+ version: "0.2",
736
+ language: "en,en-US",
737
+ allowCompoundWords: true,
738
+ words: ["vite", "pinia", "vueuse", "unplugin", "trw"],
739
+ ignorePaths: ["pnpm-lock.yaml", "/coverage/", "*.svg", "*.png"]
740
+ },
741
+ null,
742
+ 2
743
+ ) + "\n",
744
+ editorconfig: () => `root = true
745
+
746
+ [*]
747
+ charset = utf-8
748
+ indent_style = space
749
+ indent_size = 2
750
+ end_of_line = lf
751
+ insert_final_newline = true
752
+ trim_trailing_whitespace = true
753
+
754
+ [*.md]
755
+ trim_trailing_whitespace = false
756
+ `,
757
+ dependencies: {
758
+ dev: [
759
+ "eslint",
760
+ "@vue/eslint-config-typescript",
761
+ "@vue/eslint-config-prettier",
762
+ "eslint-plugin-vue",
763
+ "prettier",
764
+ "stylelint",
765
+ "stylelint-config-standard-scss",
766
+ "stylelint-order",
767
+ "stylelint-scss",
768
+ "@stylistic/stylelint-plugin",
769
+ "postcss-html",
770
+ "postcss-scss",
771
+ "cspell"
772
+ ]
773
+ },
774
+ scripts: {
775
+ lint: "eslint .",
776
+ "lint:fix": 'eslint "src/**/*.{js,ts,vue}" --fix',
777
+ format: 'prettier --write "src/**/*.{ts,js,json,vue,css,scss}"',
778
+ "format:check": 'prettier --check "src/**/*.{ts,js,json,vue,css,scss}"',
779
+ stylelint: 'stylelint "src/**/*.{css,scss,vue}"',
780
+ "stylelint:fix": 'stylelint "src/**/*.{css,scss,vue}" --fix',
781
+ cspell: 'cspell --gitignore "src/**/*"',
782
+ "type:check": "vue-tsc --noEmit",
783
+ "code:check": "<pm> lint && <pm> format:check",
784
+ "code:fix": "<pm> lint:fix && <pm> format",
785
+ "code:check:all": "<pm> lint && <pm> format:check && <pm> stylelint && <pm> cspell",
786
+ "code:fix:all": "<pm> lint:fix && <pm> format && <pm> stylelint:fix"
787
+ }
788
+ };
789
+
790
+ // src/presets/fmt/index.ts
791
+ var FMT_PRESETS = [webFmt, electronFmt, uniappFmt, nodeFmt, nestFmt];
792
+
793
+ // src/utils/logger.ts
794
+ import chalk from "chalk";
795
+ var logger = {
796
+ info(msg) {
797
+ console.log(chalk.blue("\u2139"), msg);
798
+ },
799
+ success(msg) {
800
+ console.log(chalk.green("\u2714"), msg);
801
+ },
802
+ warn(msg) {
803
+ console.log(chalk.yellow("\u26A0"), msg);
804
+ },
805
+ error(msg) {
806
+ console.error(chalk.red("\u2716"), msg);
807
+ },
808
+ skip(file, reason) {
809
+ console.log(chalk.yellow("\u2298"), chalk.gray(file), chalk.gray(`(${reason})`));
810
+ },
811
+ create(file) {
812
+ console.log(chalk.green("\u271A"), file);
813
+ },
814
+ overwrite(file) {
815
+ console.log(chalk.cyan("\u21BB"), file);
816
+ }
817
+ };
818
+
819
+ // src/utils/errors.ts
820
+ import chalk2 from "chalk";
821
+ var CliError = class extends Error {
822
+ code;
823
+ suggestion;
824
+ constructor(message, code, suggestion) {
825
+ super(message);
826
+ this.name = "CliError";
827
+ this.code = code;
828
+ this.suggestion = suggestion;
829
+ }
830
+ };
831
+ var PresetNotFoundError = class extends CliError {
832
+ constructor(name, available) {
833
+ const suggestion = fuzzyMatchPreset(name, available);
834
+ const msg = suggestion ? `Preset '${name}' not found. Did you mean '${suggestion}'?` : `Preset '${name}' not found. Available: ${available.join(", ")}`;
835
+ super(msg, "PRESET_NOT_FOUND", suggestion ?? void 0);
836
+ }
837
+ };
838
+ function fuzzyMatchPreset(input, available) {
839
+ let best = null;
840
+ let bestDist = Infinity;
841
+ for (const name of available) {
842
+ const dist = levenshtein(input.toLowerCase(), name.toLowerCase());
843
+ if (dist < bestDist && dist <= Math.max(2, Math.floor(name.length / 3))) {
844
+ bestDist = dist;
845
+ best = name;
846
+ }
847
+ }
848
+ return best;
849
+ }
850
+ function levenshtein(a, b) {
851
+ const m = a.length;
852
+ const n = b.length;
853
+ const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
854
+ for (let i = 0; i <= m; i++) dp[i][0] = i;
855
+ for (let j = 0; j <= n; j++) dp[0][j] = j;
856
+ for (let i = 1; i <= m; i++) {
857
+ for (let j = 1; j <= n; j++) {
858
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
859
+ dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
860
+ }
861
+ }
862
+ return dp[m][n];
863
+ }
864
+ function resolvePreset(presets, name) {
865
+ const found = presets.find((p) => p.name === name);
866
+ if (!found) {
867
+ const err = new PresetNotFoundError(
868
+ name,
869
+ presets.map((p) => p.name)
870
+ );
871
+ console.error(chalk2.red("\u2716"), err.message);
872
+ process.exit(1);
873
+ }
874
+ return found;
875
+ }
876
+
877
+ // src/generators/fmt.ts
878
+ import path2 from "path";
879
+
880
+ // src/core/conflict-resolver.ts
881
+ function resolveConflict(filename, exists, preset, forceFlag) {
882
+ if (exists && preset.neverOverwrite?.includes(filename)) {
883
+ return "skip";
884
+ }
885
+ if (exists && preset.forceOverwrite?.includes(filename)) {
886
+ return "overwrite";
887
+ }
888
+ if (!exists) {
889
+ return "create";
890
+ }
891
+ if (forceFlag) {
892
+ return "overwrite";
893
+ }
894
+ return "skip";
895
+ }
896
+
897
+ // src/utils/fs.ts
898
+ import fs from "fs";
899
+ import path from "path";
900
+ function fileExists(filePath) {
901
+ return fs.existsSync(filePath);
902
+ }
903
+ function ensureDir(dirPath) {
904
+ if (!fs.existsSync(dirPath)) {
905
+ fs.mkdirSync(dirPath, { recursive: true });
906
+ }
907
+ }
908
+ function writeFile(filePath, content) {
909
+ ensureDir(path.dirname(filePath));
910
+ fs.writeFileSync(filePath, content, "utf-8");
911
+ }
912
+ function readJson(filePath) {
913
+ try {
914
+ const raw = fs.readFileSync(filePath, "utf-8");
915
+ return JSON.parse(raw);
916
+ } catch {
917
+ return null;
918
+ }
919
+ }
920
+ function writeJson(filePath, data) {
921
+ const content = JSON.stringify(data, null, 2) + "\n";
922
+ writeFile(filePath, content);
923
+ }
924
+
925
+ // src/generators/fmt.ts
926
+ var CONFIG_FILES = [
927
+ { filename: "eslint.config.mjs", getContent: (p) => p.eslint?.() },
928
+ { filename: ".prettierrc", getContent: (p) => p.prettier?.() },
929
+ { filename: ".prettierignore", getContent: (p) => p.prettierIgnore?.() },
930
+ { filename: "stylelint.config.mjs", getContent: (p) => p.stylelint?.() },
931
+ { filename: ".stylelintignore", getContent: (p) => p.stylelintIgnore?.() },
932
+ { filename: "cspell.json", getContent: (p) => p.cspell?.() },
933
+ { filename: ".editorconfig", getContent: (p) => p.editorconfig?.() }
934
+ ];
935
+ function generateConfigFile(preset, filename, content, opts) {
936
+ const filepath = path2.join(opts.cwd, filename);
937
+ const exists = fileExists(filepath);
938
+ const action = resolveConflict(filename, exists, preset, opts.force);
939
+ if (action === "skip") {
940
+ logger.skip(filename, "already exists");
941
+ return false;
942
+ }
943
+ if (opts.dryRun) {
944
+ logger.info(`[dry-run] Would ${exists ? "overwrite" : "create"} ${filename}`);
945
+ return true;
946
+ }
947
+ writeFile(filepath, content);
948
+ if (exists) {
949
+ logger.overwrite(filename);
950
+ } else {
951
+ logger.create(filename);
952
+ }
953
+ return true;
954
+ }
955
+ function generateAllFmt(preset, opts) {
956
+ const generated = [];
957
+ for (const { filename, getContent } of CONFIG_FILES) {
958
+ const content = getContent(preset);
959
+ if (content === void 0) continue;
960
+ if (generateConfigFile(preset, filename, content, opts)) {
961
+ generated.push(filename);
962
+ }
963
+ }
964
+ return generated;
965
+ }
966
+
967
+ // src/presets/versions.ts
968
+ var DEPS_VERSIONS = {
969
+ eslint: "^10.2.0",
970
+ "@eslint/js": "^10.0.1",
971
+ "typescript-eslint": "^8.58.0",
972
+ "eslint-plugin-prettier": "^5.5.5",
973
+ "eslint-config-prettier": "^10.1.8",
974
+ "@vue/eslint-config-typescript": "^14.7.0",
975
+ "@vue/eslint-config-prettier": "^10.2.0",
976
+ "eslint-plugin-vue": "^10.8.0",
977
+ prettier: "^3.8.1",
978
+ stylelint: "^17.6.0",
979
+ "stylelint-config-standard-scss": "^17.0.0",
980
+ "stylelint-order": "^8.1.1",
981
+ "stylelint-scss": "^7.0.0",
982
+ "@stylistic/stylelint-plugin": "^5.1.0",
983
+ "postcss-html": "^1.8.1",
984
+ "postcss-scss": "^4.0.9",
985
+ cspell: "^10.0.0"
986
+ };
987
+ function resolveVersions(packages) {
988
+ return packages.map((pkg) => {
989
+ const version = DEPS_VERSIONS[pkg];
990
+ return version ? `${pkg}@${version}` : pkg;
991
+ });
992
+ }
993
+
994
+ // src/utils/execFileNoThrow.ts
995
+ import { exec } from "child_process";
996
+ import { promisify } from "util";
997
+ var execAsync = promisify(exec);
998
+ async function execFileNoThrow(command, args, options) {
999
+ const cmdStr = args.length > 0 ? `${command} ${args.join(" ")}` : command;
1000
+ try {
1001
+ const { stdout, stderr } = await execAsync(cmdStr, {
1002
+ cwd: options?.cwd
1003
+ });
1004
+ return { stdout: stdout.trim(), stderr: stderr.trim(), exitCode: 0 };
1005
+ } catch (err) {
1006
+ const error = err;
1007
+ return {
1008
+ stdout: (error.stdout ?? "").trim(),
1009
+ stderr: (error.stderr ?? "").trim(),
1010
+ exitCode: error.code === "ENOENT" ? null : 1
1011
+ };
1012
+ }
1013
+ }
1014
+
1015
+ // src/utils/deps.ts
1016
+ function detectPackageManager(cwd) {
1017
+ if (fileExists(`${cwd}/bun.lockb`) || fileExists(`${cwd}/bun.lock`)) return "bun";
1018
+ if (fileExists(`${cwd}/pnpm-lock.yaml`)) return "pnpm";
1019
+ if (fileExists(`${cwd}/yarn.lock`)) return "yarn";
1020
+ return "npm";
1021
+ }
1022
+ function getRunPrefix(pm) {
1023
+ switch (pm) {
1024
+ case "bun":
1025
+ return "bun run";
1026
+ case "pnpm":
1027
+ return "pnpm run";
1028
+ case "yarn":
1029
+ return "yarn run";
1030
+ case "npm":
1031
+ return "npm run";
1032
+ }
1033
+ }
1034
+ var INSTALL_CMDS = {
1035
+ bun: ["bun", ["add"]],
1036
+ pnpm: ["pnpm", ["add"]],
1037
+ yarn: ["yarn", ["add"]],
1038
+ npm: ["npm", ["install"]]
1039
+ };
1040
+ async function installDevDeps(packages, cwd, pm) {
1041
+ const manager = pm ?? detectPackageManager(cwd);
1042
+ const resolvedPackages = resolveVersions(packages);
1043
+ logger.info(`Installing ${resolvedPackages.length} devDependencies via ${manager}...`);
1044
+ const [command, subcommand] = INSTALL_CMDS[manager];
1045
+ const args = [...subcommand, "-D", ...resolvedPackages];
1046
+ const { stderr, exitCode } = await execFileNoThrow(command, args, { cwd });
1047
+ if (exitCode !== 0) {
1048
+ logger.error(`Failed to install dependencies: ${stderr}`);
1049
+ throw new Error(`Dependency installation failed (exit code ${exitCode})`);
1050
+ }
1051
+ logger.success(`Installed ${resolvedPackages.length} packages`);
1052
+ }
1053
+
1054
+ // src/commands/fmt.ts
1055
+ function registerFmtCommand(program2) {
1056
+ const fmt = program2.command("fmt");
1057
+ fmt.command("init <preset>").description("Initialize formatting config with preset").option("-F, --force", "Force overwrite existing files").option("--no-install", "Skip dependency installation").option("--dry-run", "Preview without writing files").action(
1058
+ async (presetName, options) => {
1059
+ const preset = resolvePreset(FMT_PRESETS, presetName);
1060
+ if (!preset) return;
1061
+ const cwd = process.cwd();
1062
+ const opts = {
1063
+ cwd,
1064
+ force: options.force ?? false,
1065
+ dryRun: options.dryRun ?? false
1066
+ };
1067
+ logger.info(`Initializing fmt preset: ${preset.name}`);
1068
+ logger.info(`Description: ${preset.description}`);
1069
+ const generated = generateAllFmt(preset, opts);
1070
+ if (generated.length === 0) {
1071
+ logger.warn("No files generated");
1072
+ return;
1073
+ }
1074
+ logger.success(`Generated ${generated.length} config file(s)`);
1075
+ if (preset.scripts) {
1076
+ await injectScripts(preset.scripts, opts);
1077
+ }
1078
+ if (preset.dependencies?.dev && options.install !== false) {
1079
+ if (opts.dryRun) {
1080
+ logger.info(`[dry-run] Would install: ${preset.dependencies.dev.join(", ")}`);
1081
+ } else {
1082
+ try {
1083
+ await installDevDeps(preset.dependencies.dev, cwd);
1084
+ } catch {
1085
+ logger.warn("Dependency installation failed. You can install manually.");
1086
+ }
1087
+ }
1088
+ } else if (preset.dependencies?.dev && options.install === false) {
1089
+ logger.info("Dependencies to install:");
1090
+ for (const dep of preset.dependencies.dev) {
1091
+ console.log(` - ${dep}`);
1092
+ }
1093
+ }
1094
+ logger.success("fmt init complete!");
1095
+ }
1096
+ );
1097
+ fmt.command("list").description("List available fmt presets").action(() => {
1098
+ logger.info("Available fmt presets:");
1099
+ for (const p of FMT_PRESETS) {
1100
+ console.log(` ${p.name.padEnd(12)} ${p.description}`);
1101
+ }
1102
+ });
1103
+ }
1104
+ async function injectScripts(scripts, opts) {
1105
+ const pkgPath = path3.join(opts.cwd, "package.json");
1106
+ const pkg = readJson(pkgPath);
1107
+ if (!pkg) {
1108
+ logger.warn("package.json not found, skipping scripts injection");
1109
+ return;
1110
+ }
1111
+ const existingScripts = pkg.scripts ?? {};
1112
+ const pm = detectPackageManager(opts.cwd);
1113
+ const prefix = getRunPrefix(pm);
1114
+ const resolvedScripts = {};
1115
+ for (const [key, value] of Object.entries(scripts)) {
1116
+ resolvedScripts[key] = value.replace(/<pm>/g, prefix);
1117
+ }
1118
+ let added = 0;
1119
+ let skipped = 0;
1120
+ for (const [key, value] of Object.entries(resolvedScripts)) {
1121
+ if (existingScripts[key] !== void 0 && !opts.force) {
1122
+ logger.skip(`script:${key}`, "already exists");
1123
+ skipped++;
1124
+ continue;
1125
+ }
1126
+ if (opts.dryRun) {
1127
+ logger.info(`[dry-run] Would add script: ${key}`);
1128
+ added++;
1129
+ continue;
1130
+ }
1131
+ existingScripts[key] = value;
1132
+ added++;
1133
+ }
1134
+ if (added > 0 && !opts.dryRun) {
1135
+ pkg.scripts = existingScripts;
1136
+ writeJson(pkgPath, pkg);
1137
+ logger.success(`Scripts: ${added} added, ${skipped} skipped`);
1138
+ }
1139
+ }
1140
+
1141
+ // src/utils/version.ts
1142
+ import { existsSync, readFileSync } from "fs";
1143
+ import { dirname, join } from "path";
1144
+ import { fileURLToPath } from "url";
1145
+ var PACKAGE_NAME = "@luxkit/cli";
1146
+ var cachedVersion;
1147
+ function getCurrentVersion() {
1148
+ if (cachedVersion) return cachedVersion;
1149
+ const __dirname = dirname(fileURLToPath(import.meta.url));
1150
+ const candidates = [
1151
+ join(__dirname, "..", "package.json"),
1152
+ join(__dirname, "..", "..", "package.json")
1153
+ ];
1154
+ const pkgPath = candidates.find((p) => existsSync(p));
1155
+ if (!pkgPath) {
1156
+ throw new Error("Cannot locate package.json for version reading");
1157
+ }
1158
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
1159
+ cachedVersion = pkg.version;
1160
+ return cachedVersion;
1161
+ }
1162
+
1163
+ // src/commands/update.ts
1164
+ var GLOBAL_UPDATE_CMDS = {
1165
+ npm: ["npm", ["install", "-g", `${PACKAGE_NAME}@latest`]],
1166
+ bun: ["bun", ["install", "-g", `${PACKAGE_NAME}@latest`]]
1167
+ };
1168
+ function detectGlobalPackageManager() {
1169
+ return process.execPath.toLowerCase().includes("bun") ? "bun" : "npm";
1170
+ }
1171
+ async function fetchLatestVersion() {
1172
+ const { stdout, exitCode } = await execFileNoThrow("npm", ["view", PACKAGE_NAME, "version"]);
1173
+ if (exitCode !== 0 || !stdout) {
1174
+ throw new Error(`Failed to fetch latest version from npm registry.`);
1175
+ }
1176
+ const lines = stdout.split("\n").filter((line) => line.trim().length > 0);
1177
+ return lines[lines.length - 1].trim();
1178
+ }
1179
+ async function performUpdate(pm) {
1180
+ const [command, args] = GLOBAL_UPDATE_CMDS[pm];
1181
+ const { exitCode, stderr } = await execFileNoThrow(command, args);
1182
+ if (exitCode !== 0) {
1183
+ const hint = /EACCES|permission/i.test(stderr) ? "\nTry running with elevated privileges (e.g. sudo)." : "";
1184
+ throw new Error(`Update failed: ${stderr}${hint}`);
1185
+ }
1186
+ }
1187
+ function registerUpdateCommand(program2) {
1188
+ program2.command("update").description("Update @luxkit/cli to the latest version").option("--check", "Only check for updates without installing").action(async (options) => {
1189
+ try {
1190
+ logger.info("Checking for updates...");
1191
+ const current = getCurrentVersion();
1192
+ const latest = await fetchLatestVersion();
1193
+ if (current === latest) {
1194
+ logger.success(`Already up to date (v${current})`);
1195
+ return;
1196
+ }
1197
+ if (options.check) {
1198
+ logger.info(`New version available: v${latest} (current: v${current})`);
1199
+ logger.info(`Run \`lux update\` to update.`);
1200
+ return;
1201
+ }
1202
+ const pm = detectGlobalPackageManager();
1203
+ logger.info(`Updating via ${pm}...`);
1204
+ await performUpdate(pm);
1205
+ logger.success(`Successfully updated to v${latest}`);
1206
+ } catch (err) {
1207
+ const message = err instanceof Error ? err.message : String(err);
1208
+ logger.error(message);
1209
+ logger.warn(`You can also update manually: npm install -g ${PACKAGE_NAME}@latest`);
1210
+ }
1211
+ });
1212
+ }
1213
+
1214
+ // src/presets/vscode/web.ts
1215
+ var webVscode = {
1216
+ name: "web",
1217
+ description: "VSCode config for Vue 3 Web",
1218
+ settings: () => ({
1219
+ // ===== 编辑器爱好设置 =====
1220
+ "editor.tabSize": 2,
1221
+ "editor.detectIndentation": false,
1222
+ "editor.insertSpaces": true,
1223
+ "editor.renderWhitespace": "selection",
1224
+ "editor.guides.indentation": true,
1225
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1226
+ "editor.formatOnSave": true,
1227
+ "editor.codeActionsOnSave": {
1228
+ "source.fixAll.eslint": "explicit",
1229
+ "source.fixAll.stylelint": "explicit",
1230
+ "source.organizeImports": "never"
1231
+ },
1232
+ // 光标与动画
1233
+ "editor.cursorBlinking": "expand",
1234
+ "editor.cursorSmoothCaretAnimation": "on",
1235
+ "editor.largeFileOptimizations": true,
1236
+ // 代码辅助
1237
+ "editor.inlineSuggest.enabled": true,
1238
+ "editor.suggestSelection": "recentlyUsedByPrefix",
1239
+ "editor.acceptSuggestionOnEnter": "smart",
1240
+ "editor.bracketPairColorization.enabled": true,
1241
+ "editor.autoClosingBrackets": "beforeWhitespace",
1242
+ "editor.autoClosingOvertype": "always",
1243
+ // ===== TypeScript 专项优化 =====
1244
+ "js/ts.inlayHints.enumMemberValues.enabled": true,
1245
+ "js/ts.preferences.preferTypeOnlyAutoImports": true,
1246
+ "js/ts.preferences.includePackageJsonAutoImports": "on",
1247
+ "js/ts.preferences.importModuleSpecifier": "relative",
1248
+ "js/ts.suggest.autoImports": true,
1249
+ "js/ts.tsserver.exclude": ["**/node_modules", "**/dist", "**/.turbo"],
1250
+ "js/ts.tsdk.path": "node_modules/typescript/lib",
1251
+ // ===== 语言特定格式化 =====
1252
+ "[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1253
+ "[css]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1254
+ "[scss]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1255
+ "[typescript]": {
1256
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1257
+ "editor.formatOnSave": true
1258
+ },
1259
+ "[javascript]": {
1260
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1261
+ "editor.formatOnSave": true
1262
+ },
1263
+ "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1264
+ "[vue]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1265
+ // ===== 终端配置 =====
1266
+ "terminal.integrated.cursorBlinking": true,
1267
+ "terminal.integrated.tabs.enabled": true,
1268
+ "terminal.integrated.scrollback": 1e4,
1269
+ // ===== 文件排除 =====
1270
+ "files.watcherExclude": {
1271
+ "**/.git/objects/**": true,
1272
+ "**/.git/subtree-cache/**": true,
1273
+ "**/.vscode/**": true,
1274
+ "**/node_modules/**": true,
1275
+ "**/tmp/**": true,
1276
+ "**/dist/**": true
1277
+ },
1278
+ "search.exclude": {
1279
+ "**/node_modules": true,
1280
+ "**/*.log": true,
1281
+ "**/*.log*": true,
1282
+ "**/dist": true,
1283
+ "**/.git": true,
1284
+ "**/.vscode": false,
1285
+ "**/tmp": true,
1286
+ node_modules: true,
1287
+ "**/pnpm-lock.yaml": true
1288
+ },
1289
+ // ===== 文件嵌套(美观优化)=====
1290
+ "explorer.fileNesting.enabled": true,
1291
+ "explorer.fileNesting.expand": false,
1292
+ "explorer.fileNesting.patterns": {
1293
+ "package.json": "pnpm-lock.yaml, .gitignore, .browserslistrc, .npmrc, cspell.json",
1294
+ "eslint.config.mjs": ".prettierignore, .prettierrc, .prettierrc.json, .editorconfig",
1295
+ "tsconfig.json": "tsconfig.*.json",
1296
+ "tailwind.config.js": "postcss.config.js",
1297
+ "vite.config.{js,ts}": "vite.*.{js,ts}",
1298
+ ".env": ".env.*"
1299
+ },
1300
+ // ===== ESLint =====
1301
+ "eslint.validate": [
1302
+ "javascript",
1303
+ "typescript",
1304
+ "javascriptreact",
1305
+ "typescriptreact",
1306
+ "vue",
1307
+ "html",
1308
+ "markdown",
1309
+ "json",
1310
+ "jsonc",
1311
+ "json5"
1312
+ ],
1313
+ // ===== Stylelint =====
1314
+ "stylelint.enable": true,
1315
+ "stylelint.packageManager": "pnpm",
1316
+ "stylelint.validate": ["css", "scss", "vue"],
1317
+ "stylelint.customSyntax": "postcss-html",
1318
+ "stylelint.snippet": ["css", "scss", "vue"],
1319
+ "css.validate": false,
1320
+ "less.validate": false,
1321
+ "scss.validate": false,
1322
+ // ===== CSpell =====
1323
+ "cSpell.language": "en",
1324
+ // ===== 包管理器 =====
1325
+ "npm.packageManager": "pnpm"
1326
+ }),
1327
+ extensions: () => [
1328
+ "vue.volar",
1329
+ "dbaeumer.vscode-eslint",
1330
+ "esbenp.prettier-vscode",
1331
+ "stylelint.vscode-stylelint",
1332
+ "mrmlnc.vscode-scss",
1333
+ "streetsidesoftware.code-spell-checker",
1334
+ "yoavbls.pretty-ts-errors",
1335
+ "editorconfig.editorconfig",
1336
+ "aaron-bond.better-comments",
1337
+ "usernamehw.errorlens",
1338
+ "christian-kohler.path-intellisense",
1339
+ "vscode-icons-team.vscode-icons"
1340
+ ]
1341
+ };
1342
+
1343
+ // src/presets/vscode/electron.ts
1344
+ var electronVscode = {
1345
+ name: "electron",
1346
+ description: "VSCode config for Vue 3 + Electron",
1347
+ settings: () => ({
1348
+ // ===== 编辑器爱好设置 =====
1349
+ "editor.tabSize": 2,
1350
+ "editor.detectIndentation": false,
1351
+ "editor.insertSpaces": true,
1352
+ "editor.renderWhitespace": "selection",
1353
+ "editor.guides.indentation": true,
1354
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1355
+ "editor.formatOnSave": true,
1356
+ "editor.codeActionsOnSave": {
1357
+ "source.fixAll.eslint": "explicit",
1358
+ "source.fixAll.stylelint": "explicit",
1359
+ "source.organizeImports": "never"
1360
+ },
1361
+ "editor.cursorBlinking": "expand",
1362
+ "editor.cursorSmoothCaretAnimation": "on",
1363
+ "editor.largeFileOptimizations": true,
1364
+ "editor.inlineSuggest.enabled": true,
1365
+ "editor.suggestSelection": "recentlyUsedByPrefix",
1366
+ "editor.acceptSuggestionOnEnter": "smart",
1367
+ "editor.bracketPairColorization.enabled": true,
1368
+ "editor.autoClosingBrackets": "beforeWhitespace",
1369
+ "editor.autoClosingOvertype": "always",
1370
+ // ===== TypeScript 专项优化 =====
1371
+ "js/ts.inlayHints.enumMemberValues.enabled": true,
1372
+ "js/ts.preferences.preferTypeOnlyAutoImports": true,
1373
+ "js/ts.preferences.includePackageJsonAutoImports": "on",
1374
+ "js/ts.preferences.importModuleSpecifier": "relative",
1375
+ "js/ts.suggest.autoImports": true,
1376
+ "js/ts.tsserver.exclude": ["**/node_modules", "**/dist", "**/.turbo"],
1377
+ "js/ts.tsdk.path": "node_modules/typescript/lib",
1378
+ // ===== 语言特定格式化 =====
1379
+ "[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1380
+ "[css]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1381
+ "[scss]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1382
+ "[typescript]": {
1383
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1384
+ "editor.formatOnSave": true
1385
+ },
1386
+ "[javascript]": {
1387
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1388
+ "editor.formatOnSave": true
1389
+ },
1390
+ "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1391
+ "[vue]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1392
+ // ===== 终端配置 =====
1393
+ "terminal.integrated.cursorBlinking": true,
1394
+ "terminal.integrated.tabs.enabled": true,
1395
+ "terminal.integrated.scrollback": 1e4,
1396
+ // ===== 文件排除 =====
1397
+ "files.watcherExclude": {
1398
+ "**/.git/objects/**": true,
1399
+ "**/.git/subtree-cache/**": true,
1400
+ "**/.vscode/**": true,
1401
+ "**/node_modules/**": true,
1402
+ "**/tmp/**": true,
1403
+ "**/dist/**": true,
1404
+ "**/release/**": true,
1405
+ "**/out/**": true
1406
+ },
1407
+ "search.exclude": {
1408
+ "**/node_modules": true,
1409
+ "**/*.log": true,
1410
+ "**/*.log*": true,
1411
+ "**/dist": true,
1412
+ "**/release": true,
1413
+ "**/out": true,
1414
+ "**/.git": true,
1415
+ "**/.vscode": false,
1416
+ "**/tmp": true,
1417
+ node_modules: true,
1418
+ "**/pnpm-lock.yaml": true
1419
+ },
1420
+ // ===== 文件嵌套 =====
1421
+ "explorer.fileNesting.enabled": true,
1422
+ "explorer.fileNesting.expand": false,
1423
+ "explorer.fileNesting.patterns": {
1424
+ "package.json": "pnpm-lock.yaml, .gitignore, .browserslistrc, .npmrc, cspell.json",
1425
+ "eslint.config.mjs": ".prettierignore, .prettierrc.json, .editorconfig",
1426
+ "tsconfig.json": "tsconfig.*.json",
1427
+ "tailwind.config.js": "postcss.config.js",
1428
+ "vite.config.{js,ts}": "vite.*.{js,ts}",
1429
+ ".env": ".env.*",
1430
+ "vite.renderer.config.ts": "vite.*.config.ts",
1431
+ "forge.config.ts": "forge.env.d.ts"
1432
+ },
1433
+ // ===== ESLint =====
1434
+ "eslint.validate": [
1435
+ "javascript",
1436
+ "typescript",
1437
+ "javascriptreact",
1438
+ "typescriptreact",
1439
+ "vue",
1440
+ "html",
1441
+ "markdown",
1442
+ "json",
1443
+ "jsonc",
1444
+ "json5"
1445
+ ],
1446
+ // ===== Stylelint =====
1447
+ "stylelint.enable": true,
1448
+ "stylelint.packageManager": "pnpm",
1449
+ "stylelint.validate": ["css", "scss", "vue"],
1450
+ "stylelint.customSyntax": "postcss-html",
1451
+ "stylelint.snippet": ["css", "scss", "vue"],
1452
+ "css.validate": false,
1453
+ "less.validate": false,
1454
+ "scss.validate": false,
1455
+ // ===== CSpell =====
1456
+ "cSpell.language": "en",
1457
+ // ===== 包管理器 =====
1458
+ "npm.packageManager": "pnpm"
1459
+ }),
1460
+ extensions: () => [
1461
+ "vue.volar",
1462
+ "dbaeumer.vscode-eslint",
1463
+ "esbenp.prettier-vscode",
1464
+ "stylelint.vscode-stylelint",
1465
+ "mrmlnc.vscode-scss",
1466
+ "streetsidesoftware.code-spell-checker",
1467
+ "yoavbls.pretty-ts-errors",
1468
+ "editorconfig.editorconfig",
1469
+ "aaron-bond.better-comments",
1470
+ "usernamehw.errorlens",
1471
+ "christian-kohler.path-intellisense",
1472
+ "vscode-icons-team.vscode-icons"
1473
+ ]
1474
+ };
1475
+
1476
+ // src/presets/vscode/uniapp.ts
1477
+ var uniappVscode = {
1478
+ name: "uniapp",
1479
+ description: "VSCode config for UniApp",
1480
+ settings: () => ({
1481
+ // ===== 编辑器爱好设置 =====
1482
+ "editor.tabSize": 2,
1483
+ "editor.detectIndentation": false,
1484
+ "editor.insertSpaces": true,
1485
+ "editor.renderWhitespace": "selection",
1486
+ "editor.guides.indentation": true,
1487
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1488
+ "editor.formatOnSave": true,
1489
+ "editor.codeActionsOnSave": {
1490
+ "source.fixAll.eslint": "explicit",
1491
+ "source.fixAll.stylelint": "explicit",
1492
+ "source.organizeImports": "never"
1493
+ },
1494
+ "editor.cursorBlinking": "expand",
1495
+ "editor.cursorSmoothCaretAnimation": "on",
1496
+ "editor.largeFileOptimizations": true,
1497
+ "editor.inlineSuggest.enabled": true,
1498
+ "editor.suggestSelection": "recentlyUsedByPrefix",
1499
+ "editor.acceptSuggestionOnEnter": "smart",
1500
+ "editor.bracketPairColorization.enabled": true,
1501
+ "editor.autoClosingBrackets": "beforeWhitespace",
1502
+ "editor.autoClosingOvertype": "always",
1503
+ // ===== TypeScript 专项优化 =====
1504
+ "js/ts.inlayHints.enumMemberValues.enabled": true,
1505
+ "js/ts.preferences.preferTypeOnlyAutoImports": true,
1506
+ "js/ts.preferences.includePackageJsonAutoImports": "on",
1507
+ "js/ts.preferences.importModuleSpecifier": "relative",
1508
+ "js/ts.suggest.autoImports": true,
1509
+ "js/ts.tsserver.exclude": ["**/node_modules", "**/dist", "**/unpackage"],
1510
+ "js/ts.tsdk.path": "node_modules/typescript/lib",
1511
+ // ===== 语言特定格式化 =====
1512
+ "[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1513
+ "[css]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1514
+ "[scss]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1515
+ "[typescript]": {
1516
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1517
+ "editor.formatOnSave": true
1518
+ },
1519
+ "[javascript]": {
1520
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1521
+ "editor.formatOnSave": true
1522
+ },
1523
+ "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1524
+ "[vue]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1525
+ // ===== 终端配置 =====
1526
+ "terminal.integrated.cursorBlinking": true,
1527
+ "terminal.integrated.tabs.enabled": true,
1528
+ "terminal.integrated.scrollback": 1e4,
1529
+ // ===== 文件排除 =====
1530
+ "files.watcherExclude": {
1531
+ "**/.git/objects/**": true,
1532
+ "**/.git/subtree-cache/**": true,
1533
+ "**/node_modules/**": true,
1534
+ "**/tmp/**": true,
1535
+ "**/dist/**": true,
1536
+ "**/unpackage/**": true
1537
+ },
1538
+ "search.exclude": {
1539
+ "**/node_modules": true,
1540
+ "**/*.log": true,
1541
+ "**/dist": true,
1542
+ "**/unpackage": true,
1543
+ "**/.git": true,
1544
+ "**/tmp": true,
1545
+ "**/pnpm-lock.yaml": true
1546
+ },
1547
+ // ===== 文件嵌套 =====
1548
+ "explorer.fileNesting.enabled": true,
1549
+ "explorer.fileNesting.expand": false,
1550
+ "explorer.fileNesting.patterns": {
1551
+ "package.json": "pnpm-lock.yaml, .gitignore, manifest.json, pages.json",
1552
+ "eslint.config.mjs": ".prettierignore, .prettierrc.json",
1553
+ "tsconfig.json": "tsconfig.*.json",
1554
+ ".env": ".env.*"
1555
+ },
1556
+ // ===== ESLint =====
1557
+ "eslint.validate": [
1558
+ "javascript",
1559
+ "typescript",
1560
+ "javascriptreact",
1561
+ "typescriptreact",
1562
+ "vue",
1563
+ "html",
1564
+ "markdown",
1565
+ "json",
1566
+ "jsonc",
1567
+ "json5"
1568
+ ],
1569
+ // ===== Stylelint =====
1570
+ "stylelint.enable": true,
1571
+ "stylelint.packageManager": "pnpm",
1572
+ "stylelint.validate": ["css", "scss", "vue"],
1573
+ "stylelint.customSyntax": "postcss-html",
1574
+ "stylelint.snippet": ["css", "scss", "vue"],
1575
+ "css.validate": false,
1576
+ "less.validate": false,
1577
+ "scss.validate": false,
1578
+ // ===== CSpell =====
1579
+ "cSpell.language": "en",
1580
+ // ===== 包管理器 =====
1581
+ "npm.packageManager": "pnpm"
1582
+ }),
1583
+ extensions: () => [
1584
+ "vue.volar",
1585
+ "dbaeumer.vscode-eslint",
1586
+ "esbenp.prettier-vscode",
1587
+ "stylelint.vscode-stylelint",
1588
+ "mrmlnc.vscode-scss",
1589
+ "streetsidesoftware.code-spell-checker",
1590
+ "yoavbls.pretty-ts-errors",
1591
+ "editorconfig.editorconfig",
1592
+ "aaron-bond.better-comments",
1593
+ "usernamehw.errorlens",
1594
+ "christian-kohler.path-intellisense",
1595
+ "vscode-icons-team.vscode-icons"
1596
+ ]
1597
+ };
1598
+
1599
+ // src/presets/vscode/node.ts
1600
+ var nodeVscode = {
1601
+ name: "node",
1602
+ description: "VSCode config for Node.js",
1603
+ settings: () => ({
1604
+ // ===== 编辑器爱好设置 =====
1605
+ "editor.tabSize": 3,
1606
+ "editor.detectIndentation": false,
1607
+ "editor.insertSpaces": true,
1608
+ "editor.renderWhitespace": "selection",
1609
+ "editor.guides.indentation": true,
1610
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1611
+ "editor.formatOnSave": true,
1612
+ "editor.codeActionsOnSave": {
1613
+ "source.fixAll.eslint": "explicit",
1614
+ "source.organizeImports": "never"
1615
+ },
1616
+ "editor.cursorBlinking": "expand",
1617
+ "editor.cursorSmoothCaretAnimation": "on",
1618
+ "editor.largeFileOptimizations": true,
1619
+ "editor.inlineSuggest.enabled": true,
1620
+ "editor.suggestSelection": "recentlyUsedByPrefix",
1621
+ "editor.acceptSuggestionOnEnter": "smart",
1622
+ "editor.bracketPairColorization.enabled": true,
1623
+ "editor.autoClosingBrackets": "beforeWhitespace",
1624
+ "editor.autoClosingOvertype": "always",
1625
+ // ===== TypeScript 专项优化 =====
1626
+ "js/ts.inlayHints.enumMemberValues.enabled": true,
1627
+ "js/ts.preferences.preferTypeOnlyAutoImports": true,
1628
+ "js/ts.preferences.includePackageJsonAutoImports": "on",
1629
+ "js/ts.preferences.importModuleSpecifier": "relative",
1630
+ "js/ts.suggest.autoImports": true,
1631
+ "js/ts.tsserver.exclude": ["**/node_modules", "**/dist"],
1632
+ "js/ts.tsdk.path": "node_modules/typescript/lib",
1633
+ // ===== 语言特定格式化 =====
1634
+ "[typescript]": {
1635
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1636
+ "editor.formatOnSave": true
1637
+ },
1638
+ "[javascript]": {
1639
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1640
+ "editor.formatOnSave": true
1641
+ },
1642
+ "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1643
+ // ===== 终端配置 =====
1644
+ "terminal.integrated.cursorBlinking": true,
1645
+ "terminal.integrated.tabs.enabled": true,
1646
+ "terminal.integrated.scrollback": 1e4,
1647
+ // ===== 文件排除 =====
1648
+ "files.watcherExclude": {
1649
+ "**/.git/objects/**": true,
1650
+ "**/.git/subtree-cache/**": true,
1651
+ "**/node_modules/**": true,
1652
+ "**/tmp/**": true,
1653
+ "**/dist/**": true
1654
+ },
1655
+ "search.exclude": {
1656
+ "**/node_modules": true,
1657
+ "**/*.log": true,
1658
+ "**/dist": true,
1659
+ "**/.git": true,
1660
+ "**/tmp": true,
1661
+ node_modules: true,
1662
+ "**/bun.lock": true
1663
+ },
1664
+ // ===== 文件嵌套 =====
1665
+ "explorer.fileNesting.enabled": true,
1666
+ "explorer.fileNesting.expand": false,
1667
+ "explorer.fileNesting.patterns": {
1668
+ "package.json": "bun.lock, .gitignore, .npmrc, cspell.json",
1669
+ "eslint.config.mjs": ".prettierignore, .prettierrc.json, .editorconfig,.prettierrc",
1670
+ "tsconfig.json": "tsconfig.*.json",
1671
+ ".env": ".env.*"
1672
+ },
1673
+ // ===== ESLint =====
1674
+ "eslint.validate": ["javascript", "typescript", "json", "jsonc", "json5"],
1675
+ // ===== CSpell =====
1676
+ "cSpell.language": "en",
1677
+ // ===== 包管理器 =====
1678
+ "npm.packageManager": "bun"
1679
+ }),
1680
+ extensions: () => [
1681
+ "dbaeumer.vscode-eslint",
1682
+ "esbenp.prettier-vscode",
1683
+ "streetsidesoftware.code-spell-checker",
1684
+ "yoavbls.pretty-ts-errors",
1685
+ "editorconfig.editorconfig",
1686
+ "aaron-bond.better-comments",
1687
+ "usernamehw.errorlens",
1688
+ "christian-kohler.path-intellisense",
1689
+ "vscode-icons-team.vscode-icons"
1690
+ ]
1691
+ };
1692
+
1693
+ // src/presets/vscode/nest.ts
1694
+ var nestVscode = {
1695
+ name: "nest",
1696
+ description: "VSCode config for NestJS",
1697
+ settings: () => ({
1698
+ // ===== 编辑器爱好设置 =====
1699
+ "editor.tabSize": 2,
1700
+ "editor.detectIndentation": false,
1701
+ "editor.insertSpaces": true,
1702
+ "editor.renderWhitespace": "selection",
1703
+ "editor.guides.indentation": true,
1704
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1705
+ "editor.formatOnSave": true,
1706
+ "editor.codeActionsOnSave": {
1707
+ "source.fixAll.eslint": "explicit",
1708
+ "source.organizeImports": "never"
1709
+ },
1710
+ "editor.cursorBlinking": "expand",
1711
+ "editor.cursorSmoothCaretAnimation": "on",
1712
+ "editor.largeFileOptimizations": true,
1713
+ "editor.bracketPairColorization.enabled": true,
1714
+ "editor.autoClosingBrackets": "beforeWhitespace",
1715
+ "editor.autoClosingOvertype": "always",
1716
+ // ===== TypeScript 专项优化 =====
1717
+ "js/ts.inlayHints.enumMemberValues.enabled": true,
1718
+ "js/ts.preferences.preferTypeOnlyAutoImports": true,
1719
+ "js/ts.preferences.includePackageJsonAutoImports": "on",
1720
+ "js/ts.preferences.importModuleSpecifier": "relative",
1721
+ "js/ts.suggest.autoImports": true,
1722
+ "js/ts.tsserver.exclude": ["**/node_modules", "**/dist", "**/.turbo"],
1723
+ "js/ts.tsdk.path": "node_modules/typescript/lib",
1724
+ // ===== 语言特定格式化 =====
1725
+ "[typescript]": {
1726
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1727
+ "editor.formatOnSave": true
1728
+ },
1729
+ "[javascript]": {
1730
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
1731
+ "editor.formatOnSave": true
1732
+ },
1733
+ "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
1734
+ // ===== 终端配置 =====
1735
+ "terminal.integrated.cursorBlinking": true,
1736
+ "terminal.integrated.tabs.enabled": true,
1737
+ "terminal.integrated.scrollback": 1e4,
1738
+ // ===== 文件排除 =====
1739
+ "files.watcherExclude": {
1740
+ "**/.git/objects/**": true,
1741
+ "**/.git/subtree-cache/**": true,
1742
+ "**/node_modules/**": true,
1743
+ "**/tmp/**": true,
1744
+ "**/dist/**": true
1745
+ },
1746
+ "search.exclude": {
1747
+ "**/node_modules": true,
1748
+ "**/*.log": true,
1749
+ "**/dist": true,
1750
+ "**/.git": true,
1751
+ "**/tmp": true,
1752
+ "**/pnpm-lock.yaml": true
1753
+ },
1754
+ // ===== 文件嵌套 =====
1755
+ "explorer.fileNesting.enabled": true,
1756
+ "explorer.fileNesting.expand": false,
1757
+ "explorer.fileNesting.patterns": {
1758
+ "package.json": "pnpm-lock.yaml, .gitignore, .npmrc, nest-cli.json",
1759
+ "eslint.config.mjs": ".prettierignore, .prettierrc.json, .editorconfig",
1760
+ "tsconfig.json": "tsconfig.*.json",
1761
+ ".env": ".env.*",
1762
+ "*.controller.ts": "$(capture).controller.spec.ts",
1763
+ "*.service.ts": "$(capture).service.spec.ts",
1764
+ "*.module.ts": "$(capture).module.spec.ts"
1765
+ },
1766
+ // ===== ESLint =====
1767
+ "eslint.validate": [
1768
+ "javascript",
1769
+ "typescript",
1770
+ "javascriptreact",
1771
+ "typescriptreact",
1772
+ "html",
1773
+ "markdown",
1774
+ "json",
1775
+ "jsonc",
1776
+ "json5"
1777
+ ],
1778
+ // ===== CSpell =====
1779
+ "cSpell.language": "en",
1780
+ // ===== 包管理器 =====
1781
+ "npm.packageManager": "pnpm"
1782
+ }),
1783
+ extensions: () => [
1784
+ "dbaeumer.vscode-eslint",
1785
+ "esbenp.prettier-vscode",
1786
+ "streetsidesoftware.code-spell-checker",
1787
+ "yoavbls.pretty-ts-errors",
1788
+ "editorconfig.editorconfig",
1789
+ "firsttris.vscode-jest-runner",
1790
+ "aaron-bond.better-comments",
1791
+ "usernamehw.errorlens",
1792
+ "christian-kohler.path-intellisense",
1793
+ "vscode-icons-team.vscode-icons"
1794
+ ]
1795
+ };
1796
+
1797
+ // src/presets/vscode/go.ts
1798
+ var goVscode = {
1799
+ name: "go",
1800
+ description: "VSCode config for Go",
1801
+ settings: () => ({
1802
+ // Editor basics — Go uses tabs, tabSize 4
1803
+ "editor.formatOnSave": true,
1804
+ "editor.defaultFormatter": "golang.go",
1805
+ "editor.tabSize": 4,
1806
+ "editor.insertSpaces": false,
1807
+ "editor.detectIndentation": false,
1808
+ "editor.codeActionsOnSave": {
1809
+ "source.organizeImports": "explicit"
1810
+ },
1811
+ // Go-specific
1812
+ "go.useLanguageServer": true,
1813
+ "go.lintTool": "staticcheck",
1814
+ "go.lintOnSave": "package",
1815
+ "go.formatTool": "gopls",
1816
+ "go.vetOnSave": "package",
1817
+ "go.buildOnSave": "off",
1818
+ "go.coverMode": "atomic",
1819
+ "go.testFlags": ["-v", "-count=1"],
1820
+ "go.playground": {
1821
+ openbrowser: false,
1822
+ share: false
1823
+ },
1824
+ // CSpell
1825
+ "cSpell.language": "en"
1826
+ }),
1827
+ extensions: () => ["golang.go", "streetsidesoftware.code-spell-checker"]
1828
+ };
1829
+
1830
+ // src/presets/vscode/index.ts
1831
+ var VSCODE_PRESETS = [
1832
+ webVscode,
1833
+ electronVscode,
1834
+ uniappVscode,
1835
+ nodeVscode,
1836
+ nestVscode,
1837
+ goVscode
1838
+ ];
1839
+
1840
+ // src/core/merge-settings.ts
1841
+ var USER_PRIORITY_KEYS = /* @__PURE__ */ new Set([
1842
+ // Cursor/animation
1843
+ "editor.cursorBlinking",
1844
+ "editor.cursorSmoothCaretAnimation",
1845
+ "editor.renderWhitespace",
1846
+ "editor.guides.indentation",
1847
+ "editor.largeFileOptimizations",
1848
+ // Theme/appearance
1849
+ "workbench.iconTheme",
1850
+ "workbench.colorTheme",
1851
+ // Suggestions
1852
+ "editor.inlineSuggest.enabled",
1853
+ "editor.suggestSelection",
1854
+ "editor.acceptSuggestionOnEnter",
1855
+ "editor.bracketPairColorization.enabled",
1856
+ "editor.autoClosingBrackets",
1857
+ "editor.autoClosingOvertype"
1858
+ ]);
1859
+ function mergeVscodeSettings(preset, existing) {
1860
+ const result = { ...existing };
1861
+ for (const [key, presetVal] of Object.entries(preset)) {
1862
+ const existingVal = existing[key];
1863
+ if (existingVal === void 0) {
1864
+ result[key] = presetVal;
1865
+ continue;
1866
+ }
1867
+ if (USER_PRIORITY_KEYS.has(key)) {
1868
+ continue;
1869
+ }
1870
+ if (isPlainObject(presetVal) && isPlainObject(existingVal)) {
1871
+ result[key] = mergeVscodeSettings(
1872
+ presetVal,
1873
+ existingVal
1874
+ );
1875
+ continue;
1876
+ }
1877
+ result[key] = presetVal;
1878
+ }
1879
+ return result;
1880
+ }
1881
+ function isPlainObject(val) {
1882
+ return typeof val === "object" && val !== null && !Array.isArray(val);
1883
+ }
1884
+
1885
+ // src/generators/vscode.ts
1886
+ function generateVscodeSettings(preset, opts) {
1887
+ const settingsPath = `${opts.cwd}/.vscode/settings.json`;
1888
+ const presetSettings = preset.settings();
1889
+ if (opts.dryRun) {
1890
+ logger.info(`[dry-run] Would merge .vscode/settings.json`);
1891
+ return true;
1892
+ }
1893
+ const existingSettings = readJson(settingsPath);
1894
+ if (existingSettings) {
1895
+ const backupPath = `${settingsPath}.bak`;
1896
+ if (!fileExists(backupPath)) {
1897
+ writeFile(backupPath, JSON.stringify(existingSettings, null, 2) + "\n");
1898
+ logger.info(`Backed up .vscode/settings.json \u2192 settings.json.bak`);
1899
+ }
1900
+ const merged = mergeVscodeSettings(presetSettings, existingSettings);
1901
+ writeJson(settingsPath, merged);
1902
+ logger.overwrite(".vscode/settings.json");
1903
+ } else {
1904
+ writeJson(settingsPath, presetSettings);
1905
+ logger.create(".vscode/settings.json");
1906
+ }
1907
+ return true;
1908
+ }
1909
+ function generateVscodeExtensions(preset, opts) {
1910
+ const extensionsPath = `${opts.cwd}/.vscode/extensions.json`;
1911
+ const extensions = preset.extensions();
1912
+ if (opts.dryRun) {
1913
+ logger.info(`[dry-run] Would create .vscode/extensions.json`);
1914
+ return true;
1915
+ }
1916
+ writeJson(extensionsPath, { recommendations: extensions });
1917
+ logger.create(".vscode/extensions.json");
1918
+ return true;
1919
+ }
1920
+ function generateAllVscode(preset, opts) {
1921
+ const generated = [];
1922
+ if (generateVscodeSettings(preset, opts)) generated.push(".vscode/settings.json");
1923
+ if (generateVscodeExtensions(preset, opts)) generated.push(".vscode/extensions.json");
1924
+ return generated;
1925
+ }
1926
+
1927
+ // src/commands/vscode.ts
1928
+ function registerVscodeCommand(program2) {
1929
+ const vscode = program2.command("vscode");
1930
+ vscode.command("init <preset>").description("Initialize VSCode config with preset").option("-F, --force", "Force overwrite existing files").option("--dry-run", "Preview without writing files").action(async (presetName, options) => {
1931
+ const preset = resolvePreset(VSCODE_PRESETS, presetName);
1932
+ if (!preset) return;
1933
+ const cwd = process.cwd();
1934
+ const opts = {
1935
+ cwd,
1936
+ force: options.force ?? false,
1937
+ dryRun: options.dryRun ?? false
1938
+ };
1939
+ logger.info(`Initializing vscode preset: ${preset.name}`);
1940
+ logger.info(`Description: ${preset.description}`);
1941
+ const generated = generateAllVscode(preset, opts);
1942
+ if (generated.length === 0) {
1943
+ logger.warn("No files generated");
1944
+ return;
1945
+ }
1946
+ logger.success(`Generated ${generated.length} config file(s)`);
1947
+ logger.success("vscode init complete!");
1948
+ });
1949
+ vscode.command("list").description("List available vscode presets").action(() => {
1950
+ logger.info("Available vscode presets:");
1951
+ for (const p of VSCODE_PRESETS) {
1952
+ console.log(` ${p.name.padEnd(12)} ${p.description}`);
1953
+ }
1954
+ });
1955
+ }
1956
+
1957
+ // src/commands/vpn.ts
1958
+ import { spawnSync } from "child_process";
1959
+ var DEFAULT_PROXY = "http://127.0.0.1:9876";
1960
+ function buildCommands(shell, httpProxy, socksProxy) {
1961
+ if (shell === "cmd") {
1962
+ return [
1963
+ `set https_proxy=${httpProxy}`,
1964
+ `set http_proxy=${httpProxy}`,
1965
+ `set all_proxy=${socksProxy}`
1966
+ ].join("\r\n");
1967
+ }
1968
+ return [
1969
+ `$env:https_proxy="${httpProxy}"`,
1970
+ `$env:http_proxy="${httpProxy}"`,
1971
+ `$env:all_proxy="${socksProxy}"`
1972
+ ].join("\r\n");
1973
+ }
1974
+ function copyToClipboard(text) {
1975
+ const result = spawnSync("clip", [], { input: text, stdio: ["pipe", "ignore", "ignore"] });
1976
+ return result.status === 0;
1977
+ }
1978
+ function parseProxy(proxy) {
1979
+ const url = new URL(proxy.includes("://") ? proxy : `http://${proxy}`);
1980
+ return {
1981
+ httpProxy: url.href,
1982
+ socksProxy: `socks5://${url.hostname}:${url.port}`
1983
+ };
1984
+ }
1985
+ var SHELL_LABELS = {
1986
+ cmd: "CMD",
1987
+ pw: "PowerShell"
1988
+ };
1989
+ function handleCopy(shell, proxy) {
1990
+ const { httpProxy, socksProxy } = parseProxy(proxy);
1991
+ const commands = buildCommands(shell, httpProxy, socksProxy);
1992
+ if (copyToClipboard(commands)) {
1993
+ logger.success(`\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F\uFF0CCtrl+V \u7C98\u8D34\u5230 ${SHELL_LABELS[shell]} \u5373\u53EF`);
1994
+ } else {
1995
+ logger.error("\u590D\u5236\u5230\u526A\u8D34\u677F\u5931\u8D25");
1996
+ console.log(commands);
1997
+ }
1998
+ }
1999
+ function registerVpnCommand(program2) {
2000
+ const vpn = program2.command("vpn");
2001
+ vpn.command("cmd").description("Copy CMD proxy commands to clipboard").option("--proxy <addr>", "Proxy address", DEFAULT_PROXY).action((options) => handleCopy("cmd", options.proxy));
2002
+ vpn.command("pw").description("Copy PowerShell proxy commands to clipboard").option("--proxy <addr>", "Proxy address", DEFAULT_PROXY).action((options) => handleCopy("pw", options.proxy));
2003
+ }
2004
+
2005
+ // src/index.ts
2006
+ program.name("lux").description("One-click project formatting & VSCode config CLI").version(getCurrentVersion());
2007
+ registerFmtCommand(program);
2008
+ registerVscodeCommand(program);
2009
+ registerVpnCommand(program);
2010
+ registerUpdateCommand(program);
2011
+ program.parse();