@archpublicwebsite/eslint-config 1.0.5 → 1.0.7

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
@@ -41,8 +41,38 @@ On install, this package automatically sets up in your project root:
41
41
  - `.hooks/post-commit`
42
42
  - `eslint.config.mjs` (if not present)
43
43
  - `.prettierrc` plugin entry for `prettier-plugin-tailwindcss`
44
+ - `.vscode/settings.json` – ESLint flat-config settings so VS Code reads the config
45
+ - `.vscode/extensions.json` – recommended extensions (ESLint, Prettier, Volar)
44
46
  - `git config core.hooksPath .hooks` (when in a git repo)
45
47
 
48
+ ### VS Code integration
49
+
50
+ On install, `.vscode/settings.json` is created or merged with these settings:
51
+
52
+ ```json
53
+ {
54
+ "eslint.useFlatConfig": true,
55
+ "eslint.validate": [
56
+ "javascript", "javascriptreact",
57
+ "typescript", "typescriptreact",
58
+ "vue", "json", "jsonc", "markdown"
59
+ ],
60
+ "editor.codeActionsOnSave": {
61
+ "source.fixAll.eslint": "explicit",
62
+ "source.organizeImports": "never"
63
+ },
64
+ "editor.formatOnSave": false
65
+ }
66
+ ```
67
+
68
+ If `.vscode/settings.json` already exists, your existing settings are preserved — only the ESLint-related keys are added or updated.
69
+
70
+ You can also re-run it manually:
71
+
72
+ ```bash
73
+ node node_modules/@archpublicwebsite/eslint-config/tools/setup/install.mjs
74
+ ```
75
+
46
76
  ## What this package provides
47
77
 
48
78
  - `eslint.config.mjs` builder via `createArchipelagoConfig`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archpublicwebsite/eslint-config",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "author": "Archipelago International",
5
5
  "description": "Reusable ESLint flat config and git-hook toolkit for Archipelago projects",
6
6
  "type": "module",
@@ -28,7 +28,8 @@
28
28
  "eslint-config",
29
29
  "flat-config",
30
30
  "vue",
31
- "git-hooks"
31
+ "git-hooks",
32
+ "vscode"
32
33
  ],
33
34
  "private": false,
34
35
  "engines": {
@@ -1,6 +1,7 @@
1
1
  import { execSync } from 'node:child_process'
2
2
  import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
3
3
  import { join } from 'node:path'
4
+ import { ensureVscodeSettings } from './vscode.mjs'
4
5
 
5
6
  function getProjectRoot() {
6
7
  const root = process.env.INIT_CWD || process.cwd()
@@ -109,6 +110,36 @@ function ensureHooksPath(projectRoot) {
109
110
  }
110
111
  }
111
112
 
113
+ function ensureVscodeExtensions(projectRoot) {
114
+ const vscodeDir = join(projectRoot, '.vscode')
115
+ const extPath = join(vscodeDir, 'extensions.json')
116
+
117
+ if (!existsSync(vscodeDir))
118
+ mkdirSync(vscodeDir, { recursive: true })
119
+
120
+ const recommended = [
121
+ 'dbaeumer.vscode-eslint',
122
+ 'esbenp.prettier-vscode',
123
+ 'vue.volar',
124
+ ]
125
+
126
+ let current = { recommendations: [] }
127
+ if (existsSync(extPath)) {
128
+ try {
129
+ current = JSON.parse(readFileSync(extPath, 'utf8'))
130
+ if (!Array.isArray(current.recommendations))
131
+ current.recommendations = []
132
+ }
133
+ catch {
134
+ current = { recommendations: [] }
135
+ }
136
+ }
137
+
138
+ const merged = [...new Set([...current.recommendations, ...recommended])]
139
+ current.recommendations = merged
140
+ writeFileSync(extPath, `${JSON.stringify(current, null, 2)}\n`, 'utf8')
141
+ }
142
+
112
143
  function main() {
113
144
  const projectRoot = getProjectRoot()
114
145
  if (!projectRoot)
@@ -118,6 +149,8 @@ function main() {
118
149
  ensureHooksPath(projectRoot)
119
150
  ensureEslintConfig(projectRoot)
120
151
  ensurePrettierConfig(projectRoot)
152
+ ensureVscodeSettings(projectRoot)
153
+ ensureVscodeExtensions(projectRoot)
121
154
  }
122
155
 
123
156
  main()
@@ -0,0 +1,119 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+
4
+ /**
5
+ * VS Code settings required for ESLint flat config to work properly.
6
+ * These tell the ESLint extension to use flat config mode and validate
7
+ * the correct file types.
8
+ */
9
+ const VSCODE_ESLINT_SETTINGS = {
10
+ // Use flat config mode (required for eslint.config.mjs)
11
+ 'eslint.useFlatConfig': true,
12
+
13
+ // Enable ESLint for these languages
14
+ 'eslint.validate': [
15
+ 'javascript',
16
+ 'javascriptreact',
17
+ 'typescript',
18
+ 'typescriptreact',
19
+ 'vue',
20
+ 'json',
21
+ 'jsonc',
22
+ 'markdown',
23
+ ],
24
+
25
+ // Auto-fix on save via ESLint
26
+ 'editor.codeActionsOnSave': {
27
+ 'source.fixAll.eslint': 'explicit',
28
+ 'source.organizeImports': 'never',
29
+ },
30
+
31
+ // Let ESLint handle formatting instead of the built-in formatter
32
+ 'editor.formatOnSave': false,
33
+
34
+ // Disable the default VS Code JSON formatter for files ESLint handles
35
+ '[json]': {
36
+ 'editor.defaultFormatter': 'dbaeumer.vscode-eslint',
37
+ },
38
+ '[jsonc]': {
39
+ 'editor.defaultFormatter': 'dbaeumer.vscode-eslint',
40
+ },
41
+
42
+ // Git commit message validation (50/72 formatting)
43
+ 'git.inputValidation': true,
44
+ 'git.inputValidationSubjectLength': 50,
45
+ 'git.inputValidationLength': 72,
46
+
47
+ // Editor rules for git commit editor
48
+ '[git-commit]': {
49
+ 'editor.rulers': [50, 72],
50
+ 'editor.wordWrap': 'wordWrapColumn',
51
+ 'editor.wordWrapColumn': 72,
52
+ },
53
+
54
+ // Editor rules for SCM input box (VS Code 1.86+)
55
+ '[scminput]': {
56
+ 'editor.rulers': [50, 72],
57
+ 'editor.wordWrap': 'wordWrapColumn',
58
+ 'editor.wordWrapColumn': 72,
59
+ },
60
+ }
61
+
62
+ /**
63
+ * Deep-merge source into target. Arrays are replaced, not concatenated.
64
+ * Only plain objects are recursed into.
65
+ */
66
+ function deepMerge(target, source) {
67
+ const result = { ...target }
68
+ for (const key of Object.keys(source)) {
69
+ const srcVal = source[key]
70
+ const tgtVal = result[key]
71
+ if (
72
+ srcVal !== null
73
+ && typeof srcVal === 'object'
74
+ && !Array.isArray(srcVal)
75
+ && tgtVal !== null
76
+ && typeof tgtVal === 'object'
77
+ && !Array.isArray(tgtVal)
78
+ ) {
79
+ result[key] = deepMerge(tgtVal, srcVal)
80
+ }
81
+ else {
82
+ result[key] = srcVal
83
+ }
84
+ }
85
+ return result
86
+ }
87
+
88
+ /**
89
+ * Ensure `.vscode/settings.json` contains the ESLint flat-config settings.
90
+ * - If the file doesn't exist, create it with just the ESLint settings.
91
+ * - If it exists, deep-merge the ESLint settings without removing existing user settings.
92
+ *
93
+ * @param {string} projectRoot - Absolute path to the consuming project root.
94
+ */
95
+ export function ensureVscodeSettings(projectRoot) {
96
+ const vscodeDir = join(projectRoot, '.vscode')
97
+ const settingsPath = join(vscodeDir, 'settings.json')
98
+
99
+ if (!existsSync(vscodeDir)) {
100
+ mkdirSync(vscodeDir, { recursive: true })
101
+ }
102
+
103
+ let current = {}
104
+ if (existsSync(settingsPath)) {
105
+ try {
106
+ const raw = readFileSync(settingsPath, 'utf8')
107
+ current = JSON.parse(raw)
108
+ }
109
+ catch {
110
+ // File exists but is not valid JSON – back it up and start fresh
111
+ const backupPath = `${settingsPath}.backup`
112
+ writeFileSync(backupPath, readFileSync(settingsPath, 'utf8'), 'utf8')
113
+ current = {}
114
+ }
115
+ }
116
+
117
+ const merged = deepMerge(current, VSCODE_ESLINT_SETTINGS)
118
+ writeFileSync(settingsPath, `${JSON.stringify(merged, null, 2)}\n`, 'utf8')
119
+ }