@archpublicwebsite/eslint-config 1.0.7 → 1.0.9

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
@@ -61,7 +61,7 @@ On install, `.vscode/settings.json` is created or merged with these settings:
61
61
  "source.fixAll.eslint": "explicit",
62
62
  "source.organizeImports": "never"
63
63
  },
64
- "editor.formatOnSave": false
64
+ "editor.formatOnSave": true
65
65
  }
66
66
  ```
67
67
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archpublicwebsite/eslint-config",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "author": "Archipelago International",
5
5
  "description": "Reusable ESLint flat config and git-hook toolkit for Archipelago projects",
6
6
  "type": "module",
@@ -7,7 +7,8 @@ const source = process.argv[3] || ''
7
7
  if (!messageFile)
8
8
  process.exit(0)
9
9
 
10
- if (['merge', 'squash', 'commit', 'message'].includes(source))
10
+ // Skip auto-generation only for flows where Git already supplies a meaningful message.
11
+ if (['merge', 'squash', 'commit'].includes(source))
11
12
  process.exit(0)
12
13
 
13
14
  const currentMessage = readFileSync(messageFile, 'utf-8')
@@ -6,9 +6,18 @@ export function isValidCommitMessage(message) {
6
6
  return releaseRE.test(message) || commitRE.test(message)
7
7
  }
8
8
 
9
+ function getCommitSubject(rawMessage) {
10
+ return rawMessage
11
+ .split('\n')
12
+ .map(line => line.trim())
13
+ .find(line => line && !line.startsWith('#')) || ''
14
+ }
15
+
9
16
  export function verifyCommitMessageFile(messageFilePath) {
10
- const message = readFileSync(messageFilePath, 'utf-8').trim()
11
- if (isValidCommitMessage(message))
17
+ const rawMessage = readFileSync(messageFilePath, 'utf-8')
18
+ const subject = getCommitSubject(rawMessage)
19
+
20
+ if (isValidCommitMessage(subject))
12
21
  return
13
22
 
14
23
  const examples = [
@@ -21,7 +30,7 @@ export function verifyCommitMessageFile(messageFilePath) {
21
30
  console.error('Description max length: 50 characters\n')
22
31
  console.error('Examples:')
23
32
  examples.forEach(example => console.error(` - ${example}`))
24
- console.error('\nSee .github/commit-convention.md for details.\n')
33
+ console.error('\nSee README.md (Auto commit message flow) for details.\n')
25
34
  process.exit(1)
26
35
  }
27
36
 
@@ -3,6 +3,12 @@ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'n
3
3
  import { join } from 'node:path'
4
4
  import { ensureVscodeSettings } from './vscode.mjs'
5
5
 
6
+ const TAG = '[@archpublicwebsite/eslint-config]'
7
+
8
+ function log(msg) {
9
+ console.log(`${TAG} ${msg}`)
10
+ }
11
+
6
12
  function getProjectRoot() {
7
13
  const root = process.env.INIT_CWD || process.cwd()
8
14
  if (!existsSync(join(root, 'package.json')))
@@ -10,18 +16,91 @@ function getProjectRoot() {
10
16
  return root
11
17
  }
12
18
 
13
- function ensureDir(path) {
14
- if (!existsSync(path))
15
- mkdirSync(path, { recursive: true })
19
+ function ensureDir(dirPath) {
20
+ if (!existsSync(dirPath))
21
+ mkdirSync(dirPath, { recursive: true })
16
22
  }
17
23
 
18
- function writeIfMissing(path, content) {
19
- if (existsSync(path))
24
+ function writeIfMissing(filePath, content) {
25
+ if (existsSync(filePath))
20
26
  return false
21
- writeFileSync(path, content, 'utf8')
27
+ writeFileSync(filePath, content, 'utf8')
22
28
  return true
23
29
  }
24
30
 
31
+ // ─── .editorconfig ──────────────────────────────────────────────────────────
32
+
33
+ function ensureEditorConfig(projectRoot) {
34
+ const editorConfigPath = join(projectRoot, '.editorconfig')
35
+ const content = `# EditorConfig — consistent coding style across editors
36
+ # https://editorconfig.org
37
+
38
+ root = true
39
+
40
+ [*]
41
+ charset = utf-8
42
+ end_of_line = lf
43
+ indent_style = space
44
+ indent_size = 2
45
+ insert_final_newline = true
46
+ trim_trailing_whitespace = true
47
+
48
+ [*.md]
49
+ trim_trailing_whitespace = false
50
+
51
+ [*.{yml,yaml}]
52
+ indent_size = 2
53
+
54
+ [Makefile]
55
+ indent_style = tab
56
+ `
57
+ if (writeIfMissing(editorConfigPath, content))
58
+ log('Created .editorconfig')
59
+ }
60
+
61
+ // ─── .eslint-user-ignore ────────────────────────────────────────────────────
62
+
63
+ function ensureEslintUserIgnore(projectRoot) {
64
+ const ignorePath = join(projectRoot, '.eslint-user-ignore')
65
+ const content = `# User-overridable ESLint ignore rules
66
+ #
67
+ # Remove a line to include it again, or add your own patterns.
68
+ # Uses standard glob/gitignore-style patterns.
69
+
70
+ # Ignore document formats
71
+ *.doc
72
+ *.docx
73
+
74
+ # Ignore markdown files
75
+ *.md
76
+
77
+ # Optional examples:
78
+ # docs/**
79
+ # *.pdf
80
+ `
81
+ if (writeIfMissing(ignorePath, content))
82
+ log('Created .eslint-user-ignore')
83
+ }
84
+
85
+ // ─── eslint.config.mjs ─────────────────────────────────────────────────────
86
+
87
+ function ensureEslintConfig(projectRoot) {
88
+ const eslintConfigPath = join(projectRoot, 'eslint.config.mjs')
89
+ const content = `import { createArchipelagoConfig } from '@archpublicwebsite/eslint-config'
90
+
91
+ export default createArchipelagoConfig({
92
+ name: 'project/overrides',
93
+ rules: {
94
+ // Add your project overrides here
95
+ },
96
+ })
97
+ `
98
+ if (writeIfMissing(eslintConfigPath, content))
99
+ log('Created eslint.config.mjs')
100
+ }
101
+
102
+ // ─── .prettierrc ────────────────────────────────────────────────────────────
103
+
25
104
  function ensurePrettierConfig(projectRoot) {
26
105
  const prettierPath = join(projectRoot, '.prettierrc')
27
106
  const defaults = {
@@ -36,6 +115,7 @@ function ensurePrettierConfig(projectRoot) {
36
115
 
37
116
  if (!existsSync(prettierPath)) {
38
117
  writeFileSync(prettierPath, `${JSON.stringify(defaults, null, 2)}\n`, 'utf8')
118
+ log('Created .prettierrc')
39
119
  return
40
120
  }
41
121
 
@@ -49,17 +129,14 @@ function ensurePrettierConfig(projectRoot) {
49
129
  if (typeof current.semi !== 'boolean')
50
130
  current.semi = false
51
131
  writeFileSync(prettierPath, `${JSON.stringify(current, null, 2)}\n`, 'utf8')
132
+ log('Updated .prettierrc')
52
133
  }
53
134
  catch {
54
135
  // Keep existing file untouched if it is not JSON.
55
136
  }
56
137
  }
57
138
 
58
- function ensureEslintConfig(projectRoot) {
59
- const eslintConfigPath = join(projectRoot, 'eslint.config.mjs')
60
- const content = `import { createArchipelagoConfig } from 'eslint-config'\n\nexport default createArchipelagoConfig({\n name: 'project/overrides',\n rules: {\n // Add your project overrides here\n },\n})\n`
61
- writeIfMissing(eslintConfigPath, content)
62
- }
139
+ // ─── .hooks ─────────────────────────────────────────────────────────────────
63
140
 
64
141
  function ensureHooks(projectRoot) {
65
142
  const hooksDir = join(projectRoot, '.hooks')
@@ -70,33 +147,38 @@ function ensureHooks(projectRoot) {
70
147
  set -euo pipefail
71
148
 
72
149
  cd "$(git rev-parse --show-toplevel)"
73
- node node_modules/eslint-config/tools/git-hooks/pre-commit.mjs
150
+ node node_modules/@archpublicwebsite/eslint-config/tools/git-hooks/pre-commit.mjs
74
151
  `,
75
152
  'prepare-commit-msg': `#!/usr/bin/env bash
76
153
  set -euo pipefail
77
154
 
78
155
  cd "$(git rev-parse --show-toplevel)"
79
- node node_modules/eslint-config/tools/git-hooks/prepare-commit-msg.mjs "$@"
156
+ node node_modules/@archpublicwebsite/eslint-config/tools/git-hooks/prepare-commit-msg.mjs "$@"
80
157
  `,
81
158
  'commit-msg': `#!/usr/bin/env bash
82
159
  set -euo pipefail
83
160
 
84
161
  cd "$(git rev-parse --show-toplevel)"
85
- node node_modules/eslint-config/tools/git-hooks/commit-msg.mjs "$1"
162
+ node node_modules/@archpublicwebsite/eslint-config/tools/git-hooks/commit-msg.mjs "$1"
86
163
  `,
87
164
  'post-commit': `#!/usr/bin/env bash
88
165
  set -euo pipefail
89
166
 
90
167
  cd "$(git rev-parse --show-toplevel)"
91
- node node_modules/eslint-config/tools/git-hooks/post-commit.mjs
168
+ node node_modules/@archpublicwebsite/eslint-config/tools/git-hooks/post-commit.mjs
92
169
  `,
93
170
  }
94
171
 
172
+ let created = false
95
173
  Object.entries(hooks).forEach(([name, content]) => {
96
- const path = join(hooksDir, name)
97
- if (writeIfMissing(path, content))
98
- chmodSync(path, 0o755)
174
+ const hookPath = join(hooksDir, name)
175
+ if (writeIfMissing(hookPath, content)) {
176
+ chmodSync(hookPath, 0o755)
177
+ created = true
178
+ }
99
179
  })
180
+ if (created)
181
+ log('Created .hooks/ (pre-commit, prepare-commit-msg, commit-msg, post-commit)')
100
182
  }
101
183
 
102
184
  function ensureHooksPath(projectRoot) {
@@ -104,18 +186,20 @@ function ensureHooksPath(projectRoot) {
104
186
  return
105
187
  try {
106
188
  execSync('git config core.hooksPath .hooks', { cwd: projectRoot, stdio: 'ignore' })
189
+ log('Set git core.hooksPath → .hooks')
107
190
  }
108
191
  catch {
109
192
  // Ignore setup failures in non-git contexts.
110
193
  }
111
194
  }
112
195
 
196
+ // ─── .vscode/extensions.json ────────────────────────────────────────────────
197
+
113
198
  function ensureVscodeExtensions(projectRoot) {
114
199
  const vscodeDir = join(projectRoot, '.vscode')
115
200
  const extPath = join(vscodeDir, 'extensions.json')
116
201
 
117
- if (!existsSync(vscodeDir))
118
- mkdirSync(vscodeDir, { recursive: true })
202
+ ensureDir(vscodeDir)
119
203
 
120
204
  const recommended = [
121
205
  'dbaeumer.vscode-eslint',
@@ -138,19 +222,28 @@ function ensureVscodeExtensions(projectRoot) {
138
222
  const merged = [...new Set([...current.recommendations, ...recommended])]
139
223
  current.recommendations = merged
140
224
  writeFileSync(extPath, `${JSON.stringify(current, null, 2)}\n`, 'utf8')
225
+ log('Created/updated .vscode/extensions.json')
141
226
  }
142
227
 
228
+ // ─── main ───────────────────────────────────────────────────────────────────
229
+
143
230
  function main() {
144
231
  const projectRoot = getProjectRoot()
145
232
  if (!projectRoot)
146
233
  return
147
234
 
148
- ensureHooks(projectRoot)
149
- ensureHooksPath(projectRoot)
235
+ log('Setting up project...')
236
+
237
+ ensureEditorConfig(projectRoot)
238
+ ensureEslintUserIgnore(projectRoot)
150
239
  ensureEslintConfig(projectRoot)
151
240
  ensurePrettierConfig(projectRoot)
241
+ ensureHooks(projectRoot)
242
+ ensureHooksPath(projectRoot)
152
243
  ensureVscodeSettings(projectRoot)
153
244
  ensureVscodeExtensions(projectRoot)
245
+
246
+ log('Setup complete ✓')
154
247
  }
155
248
 
156
249
  main()
@@ -1,6 +1,8 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
2
2
  import { join } from 'node:path'
3
3
 
4
+ const TAG = '[@archpublicwebsite/eslint-config]'
5
+
4
6
  /**
5
7
  * VS Code settings required for ESLint flat config to work properly.
6
8
  * These tell the ESLint extension to use flat config mode and validate
@@ -29,7 +31,7 @@ const VSCODE_ESLINT_SETTINGS = {
29
31
  },
30
32
 
31
33
  // Let ESLint handle formatting instead of the built-in formatter
32
- 'editor.formatOnSave': false,
34
+ 'editor.formatOnSave': true,
33
35
 
34
36
  // Disable the default VS Code JSON formatter for files ESLint handles
35
37
  '[json]': {
@@ -116,4 +118,5 @@ export function ensureVscodeSettings(projectRoot) {
116
118
 
117
119
  const merged = deepMerge(current, VSCODE_ESLINT_SETTINGS)
118
120
  writeFileSync(settingsPath, `${JSON.stringify(merged, null, 2)}\n`, 'utf8')
121
+ console.log(`${TAG} Created/updated .vscode/settings.json`)
119
122
  }