@archpublicwebsite/eslint-config 1.0.10 → 1.0.15

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
@@ -1,53 +1,80 @@
1
- # eslint-config
1
+ # @archpublicwebsite/eslint-config
2
2
 
3
- Reusable ESLint + Git hooks toolkit for Nuxt/Vue projects.
3
+ Reusable ESLint flat config and git-hook toolkit for Archipelago projects.
4
4
 
5
- ## Publish
5
+ ## What this package includes
6
+
7
+ This package ships a ready-to-use flat config plus setup scripts for local project automation:
8
+
9
+ - `createArchipelagoConfig()` for building an ESLint flat config
10
+ - Git hook scripts for pre-commit and commit-message enforcement
11
+ - Setup automation that bootstraps the consumer project
12
+ - VS Code settings updates for the recommended linting workflow
13
+
14
+ ## Features
15
+
16
+ - Flat config based on `@antfu/eslint-config`
17
+ - Vue, TypeScript, Tailwind, and Nuxt-friendly defaults
18
+ - Git hooks for consistent formatting and commit validation
19
+ - Prettier remains available for editor guidance, but the global `format/prettier` bridge is disabled to avoid flat-config parser conflicts
20
+ - Automatic project setup on install
21
+ - Works with the Archipelago repo style rules
22
+
23
+ ## Requirements
24
+
25
+ Consumer projects should have these tools available when using the full setup:
6
26
 
7
27
  ```bash
8
- cd packages/eslint-config
9
- pnpm version patch
10
- npm publish --access public
28
+ pnpm add -D eslint prettier lint-staged turbo
11
29
  ```
12
30
 
13
- Quick checks before publish:
31
+ ## Installation
14
32
 
15
- - Ensure `.npmrc` points to public npm registry.
16
- - Run `npm pack --dry-run` and verify only `eslint.config.mjs`, `tools/`, and `README.md` are included.
33
+ ```bash
34
+ pnpm add -D @archpublicwebsite/eslint-config
35
+ ```
17
36
 
18
- ## Install
37
+ ## Usage
19
38
 
20
- ```bash
21
- pnpm add -Dw eslint-config
39
+ Create or update the root `eslint.config.mjs`:
40
+
41
+ ```js
42
+ import { createArchipelagoConfig } from '@archpublicwebsite/eslint-config'
43
+
44
+ export default createArchipelagoConfig()
22
45
  ```
23
46
 
24
- ### Required dependencies (consumer project)
47
+ Override rules when your project needs to diverge from the shared defaults:
25
48
 
26
- This toolkit expects these dev dependencies to exist in the project that installs it:
49
+ ```js
50
+ import { createArchipelagoConfig } from '@archpublicwebsite/eslint-config'
27
51
 
28
- ```bash
29
- pnpm add -D lint-staged prettier turbo
52
+ export default createArchipelagoConfig({
53
+ name: 'project/overrides',
54
+ rules: {
55
+ 'no-console': 'off',
56
+ 'vue/max-attributes-per-line': 'off',
57
+ },
58
+ })
30
59
  ```
31
60
 
32
- - `lint-staged` is used by the generated `pre-commit` hook.
33
- - `prettier` is used by the `lint:fix` flow.
34
- - `turbo` is used by the required `lint:check` / `lint:fix` scripts.
61
+ ## What the setup does
35
62
 
36
- On install, this package automatically sets up in your project root:
63
+ On install or when you run the setup script manually, the package prepares the consumer project with:
37
64
 
38
65
  - `.hooks/pre-commit`
39
66
  - `.hooks/prepare-commit-msg`
40
67
  - `.hooks/commit-msg`
41
68
  - `.hooks/post-commit`
42
- - `eslint.config.mjs` (if not present)
69
+ - `eslint.config.mjs` when one does not already exist
43
70
  - `.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)
46
- - `git config core.hooksPath .hooks` (when in a git repo)
71
+ - `.vscode/settings.json` with ESLint flat-config settings
72
+ - `.vscode/extensions.json` with recommended extensions
73
+ - `git config core.hooksPath .hooks` when the project is a Git repository
47
74
 
48
- ### VS Code integration
75
+ ## VS Code integration
49
76
 
50
- On install, `.vscode/settings.json` is created or merged with these settings:
77
+ The setup merges ESLint-related settings into `.vscode/settings.json`:
51
78
 
52
79
  ```json
53
80
  {
@@ -65,100 +92,88 @@ On install, `.vscode/settings.json` is created or merged with these settings:
65
92
  }
66
93
  ```
67
94
 
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:
95
+ Existing settings are preserved. Only the ESLint-related keys are added or updated.
71
96
 
72
- ```bash
73
- node node_modules/@archpublicwebsite/eslint-config/tools/setup/install.mjs
74
- ```
97
+ ## Public API
75
98
 
76
- ## What this package provides
99
+ The package exports:
77
100
 
78
- - `eslint.config.mjs` builder via `createArchipelagoConfig`
79
- - Reusable git hook handlers in `tools/git-hooks/`
80
- - `pre-commit.mjs`
81
- - `prepare-commit-msg.mjs`
82
- - `commit-msg.mjs`
83
- - `post-commit.mjs`
84
- - `generate-commit-message.mjs`
85
- - `verify-commit-message.mjs`
86
- - `tools/setup/install.mjs` automatic project bootstrap
101
+ - `createArchipelagoConfig`
102
+ - setup scripts under `tools/`
87
103
 
88
- ## ESLint usage
104
+ ## AI Implementation Guide
89
105
 
90
- Auto-generated `eslint.config.mjs` uses this package directly:
106
+ If you are extending or regenerating this package, keep the workflow explicit:
91
107
 
92
- ```js
93
- import { createArchipelagoConfig } from 'eslint-config'
108
+ 1. Update `eslint.config.mjs` when shared lint rules change.
109
+ 2. Update `tools/setup/install.mjs` when install-time bootstrap behavior changes.
110
+ 3. Update `tools/git-hooks/` when hook behavior changes.
111
+ 4. Keep the package export map aligned with the public API.
112
+ 5. Document any new consumer dependency that the setup expects.
94
113
 
95
- export default createArchipelagoConfig()
96
- ```
114
+ ### AI-friendly implementation notes
97
115
 
98
- ### Override rules
116
+ - Use `createArchipelagoConfig()` in the consumer project, not the internal setup scripts.
117
+ - Keep root scripts in sync with the hook and lint expectations.
118
+ - Re-run the package setup flow when changing VS Code or hook behavior.
119
+ - Prefer explicit examples that show what the consumer project should add.
99
120
 
100
- You can override any rule in your root `eslint.config.mjs`:
121
+ ## Manual setup
101
122
 
102
- ```js
103
- import { createArchipelagoConfig } from 'eslint-config'
104
-
105
- export default createArchipelagoConfig({
106
- name: 'project/overrides',
107
- rules: {
108
- 'no-console': 'off',
109
- 'vue/max-attributes-per-line': 'off',
110
- },
111
- })
112
- ```
113
-
114
- ## Manual setup (optional)
115
-
116
- Automatic setup is the default. If needed, you can still run setup manually:
123
+ If you need to rerun the bootstrap manually:
117
124
 
118
125
  ```bash
119
- node node_modules/eslint-config/tools/setup/install.mjs
126
+ node node_modules/@archpublicwebsite/eslint-config/tools/setup/install.mjs
120
127
  ```
121
128
 
122
129
  ## Hook wrappers reference
123
130
 
124
- Root `.hooks` scripts should delegate to installed package path:
125
-
126
- - `.hooks/pre-commit`
131
+ Root `.hooks` scripts should delegate to the installed package path:
127
132
 
128
133
  ```bash
129
134
  #!/usr/bin/env bash
130
135
  set -euo pipefail
131
136
  cd "$(git rev-parse --show-toplevel)"
132
- node node_modules/eslint-config/tools/git-hooks/pre-commit.mjs
137
+ node node_modules/@archpublicwebsite/eslint-config/tools/git-hooks/pre-commit.mjs
133
138
  ```
134
139
 
135
- - `.hooks/prepare-commit-msg`
136
-
137
140
  ```bash
138
141
  #!/usr/bin/env bash
139
142
  set -euo pipefail
140
143
  cd "$(git rev-parse --show-toplevel)"
141
- node node_modules/eslint-config/tools/git-hooks/prepare-commit-msg.mjs "$@"
144
+ node node_modules/@archpublicwebsite/eslint-config/tools/git-hooks/prepare-commit-msg.mjs "$@"
142
145
  ```
143
146
 
144
- - `.hooks/commit-msg`
145
-
146
147
  ```bash
147
148
  #!/usr/bin/env bash
148
149
  set -euo pipefail
149
150
  cd "$(git rev-parse --show-toplevel)"
150
- node node_modules/eslint-config/tools/git-hooks/commit-msg.mjs "$1"
151
+ node node_modules/@archpublicwebsite/eslint-config/tools/git-hooks/commit-msg.mjs "$1"
151
152
  ```
152
153
 
153
- - `.hooks/post-commit`
154
-
155
154
  ```bash
156
155
  #!/usr/bin/env bash
157
156
  set -euo pipefail
158
157
  cd "$(git rev-parse --show-toplevel)"
159
- node node_modules/eslint-config/tools/git-hooks/post-commit.mjs
158
+ node node_modules/@archpublicwebsite/eslint-config/tools/git-hooks/post-commit.mjs
160
159
  ```
161
160
 
161
+ ## Publish
162
+
163
+ ```bash
164
+ cd packages/eslint-config
165
+ pnpm version patch
166
+ npm publish --access public
167
+ ```
168
+
169
+ Before publish, run:
170
+
171
+ ```bash
172
+ npm pack --dry-run
173
+ ```
174
+
175
+ Make sure the tarball contains only the intended public files: `eslint.config.mjs`, `tools/`, and `README.md`.
176
+
162
177
  ## Required root scripts
163
178
 
164
179
  ```json
@@ -173,3 +188,11 @@ node node_modules/eslint-config/tools/git-hooks/post-commit.mjs
173
188
  }
174
189
  }
175
190
  ```
191
+
192
+ ## Verification
193
+
194
+ After making config changes, validate the package by checking the installed consumer workflow or by running the setup script in a test project.
195
+
196
+ ## License
197
+
198
+ MIT
package/eslint.config.mjs CHANGED
@@ -1,15 +1,23 @@
1
1
  import antfu from '@antfu/eslint-config'
2
- import perfectionistNatural from 'eslint-plugin-perfectionist'
3
2
  import tailwind from 'eslint-plugin-tailwindcss'
4
3
 
5
4
  export function createArchipelagoConfig(...overrides) {
6
5
  return antfu(
7
6
  {
8
- formatters: true,
9
- stylistic: true,
7
+ // Disable CSS/HTML/Markdown formatters — we only use @stylistic rules
8
+ formatters: false,
9
+ // Canonical style: no semicolons, single quotes, 2-space indent
10
+ // antfu propagates these to ALL related rules (semi, member-delimiter, etc.)
11
+ stylistic: {
12
+ semi: false,
13
+ quotes: 'single',
14
+ indent: 2,
15
+ },
10
16
  vue: true,
11
17
  typescript: true,
12
18
  },
19
+
20
+ // ── Global ignores ────────────────────────────────────────────────────────
13
21
  {
14
22
  name: 'archipelago/ignores',
15
23
  ignores: [
@@ -21,43 +29,47 @@ export function createArchipelagoConfig(...overrides) {
21
29
  '**/coverage/**',
22
30
  '**/.next/**',
23
31
  '**/public/**',
32
+ '**/*.d.ts',
24
33
  ],
25
34
  },
35
+
36
+ // ── Tailwind ──────────────────────────────────────────────────────────────
26
37
  ...tailwind.configs['flat/recommended'],
27
- {
28
- name: 'archipelago/perfectionist',
29
- plugins: {
30
- perfectionistNatural,
31
- },
32
- rules: {
33
- 'import/order': 'off',
34
- 'sort-imports': 'off',
35
- 'perfectionist/sort-imports': ['warn', {
36
- type: 'alphabetical',
37
- }],
38
- 'perfectionist/sort-exports': ['warn', {
39
- type: 'alphabetical',
40
- }],
41
- 'perfectionist/sort-named-imports': ['warn', {
42
- type: 'alphabetical',
43
- }],
44
- 'perfectionist/sort-named-exports': ['warn', {
45
- type: 'alphabetical',
46
- }],
47
- },
48
- },
38
+
39
+ // ── Canonical rules ───────────────────────────────────────────────────────
49
40
  {
50
41
  name: 'archipelago/rules',
51
42
  rules: {
52
- 'comma-dangle': ['warn', 'always-multiline'],
53
- 'no-console': 'warn',
54
- 'max-statements-per-line': 'warn',
55
- 'tailwindcss/no-custom-classname': 'off',
43
+ // Disable the global Prettier bridge rule here because it requires a
44
+ // parser per file type and creates validation conflicts in flat config.
45
+ 'format/prettier': 'off',
46
+
47
+ // ── Anti-loop: disable rules that fight @stylistic equivalents ─────────
48
+ 'object-curly-newline': 'off',
49
+ 'style/object-curly-newline': 'off',
50
+ 'style/operator-linebreak': 'off',
51
+ 'style/indent': 'off',
52
+ 'style/indent-binary-ops': 'off',
53
+ 'max-statements-per-line': 'off',
54
+ 'antfu/consistent-list-newline': 'off',
55
+ 'antfu/consistent-chaining': 'off',
56
+ 'antfu/if-newline': 'off',
57
+ 'antfu/no-import-dist': 'off',
58
+
59
+ // ── Vue ──────────────────────────────────────────────────────────────
56
60
  'vue/multi-word-component-names': 'off',
57
61
  'vue/no-required-prop-with-default': 'off',
58
62
  'vue/html-self-closing': 'off',
59
63
  'vue/html-closing-bracket-spacing': 'off',
60
64
  'vue/no-multiple-template-root': 'off',
65
+ 'vue/attributes-order': 'off',
66
+ 'vue/singleline-html-element-content-newline': 'off',
67
+ 'vue/html-closing-bracket-newline': 'off',
68
+ 'vue/html-indent': 'off',
69
+ 'vue/no-useless-v-bind': 'off',
70
+ 'vue/prefer-separate-static-class': 'off',
71
+ 'vue/attribute-hyphenation': 'off',
72
+ 'vue/define-macros-order': 'off',
61
73
  'vue/max-attributes-per-line': ['error', {
62
74
  singleline: 3,
63
75
  multiline: 1,
@@ -72,12 +84,71 @@ export function createArchipelagoConfig(...overrides) {
72
84
  ignoreHTMLAttributeValues: true,
73
85
  ignoreHTMLTextContents: true,
74
86
  }],
75
- 'object-curly-newline': ['warn', {
76
- ImportDeclaration: { multiline: true, minProperties: 3 },
87
+
88
+ // ── TypeScript ───────────────────────────────────────────────────────
89
+ 'ts/no-use-before-define': 'off',
90
+ 'ts/no-empty-object-type': 'off',
91
+ 'ts/no-explicit-any': 'warn',
92
+ 'ts/no-var-requires': 'warn',
93
+ 'ts/consistent-type-imports': ['error', {
94
+ prefer: 'type-imports',
95
+ fixStyle: 'inline-type-imports',
77
96
  }],
78
- 'format/prettier': 'warn',
97
+
98
+ // ── Import ordering ──────────────────────────────────────────────────
99
+ 'import/order': 'off',
100
+ 'import/newline-after-import': 'off',
101
+ 'import/consistent-type-specifier-style': 'off',
102
+ 'perfectionist/sort-imports': 'off',
103
+ 'perfectionist/sort-exports': 'off',
104
+ 'perfectionist/sort-named-imports': 'off',
105
+ 'perfectionist/sort-named-exports': 'off',
106
+
107
+ // ── Tailwind ─────────────────────────────────────────────────────────
108
+ 'tailwindcss/no-custom-classname': 'off',
109
+ 'tailwindcss/migration-from-tailwind-2': 'off',
110
+ 'tailwindcss/enforces-shorthand': 'off',
111
+
112
+ // ── Misc ─────────────────────────────────────────────────────────────
113
+ 'no-console': 'warn',
114
+ 'no-alert': 'off',
115
+ 'jsonc/sort-keys': 'off',
116
+ 'jsonc/sort-array-values': 'off',
117
+ 'regexp/no-unused-capturing-group': 'off',
118
+ 'regexp/optimal-quantifier-concatenation': 'off',
119
+ 'regexp/no-super-linear-backtracking': 'off',
120
+ 'regexp/negation': 'off',
121
+ 'node/prefer-global/process': 'off',
122
+ 'unicorn/prefer-number-properties': 'off',
123
+ 'unicorn/new-for-builtins': 'off',
79
124
  },
80
125
  },
126
+
127
+ // ── Package-level overrides (matches user's packages/** pattern) ──────────
128
+ {
129
+ name: 'archipelago/packages',
130
+ files: ['packages/**/*.{js,ts,vue}'],
131
+ rules: {
132
+ 'vue/multi-word-component-names': 'off',
133
+ },
134
+ },
135
+
136
+ // ── Nuxt app overrides ────────────────────────────────────────────────────
137
+ {
138
+ name: 'archipelago/nuxt',
139
+ files: [
140
+ 'apps/nuxt-web/components/**/*.{js,ts,vue}',
141
+ 'apps/nuxt-web/pages/**/*.{js,ts,vue}',
142
+ 'apps/nuxt-web/layouts/**/*.{js,ts,vue}',
143
+ 'apps/nuxt-web/composables/**/*.{js,ts}',
144
+ 'apps/nuxt-web/constants/**/*.{js,ts}',
145
+ ],
146
+ rules: {
147
+ 'vue/multi-word-component-names': 'off',
148
+ 'ts/no-explicit-any': 'warn',
149
+ },
150
+ },
151
+
81
152
  ...overrides,
82
153
  )
83
154
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@archpublicwebsite/eslint-config",
3
- "version": "1.0.10",
4
- "author": "Archipelago International",
3
+ "version": "1.0.15",
4
+ "author": "Archipelago Hotels",
5
5
  "description": "Reusable ESLint flat config and git-hook toolkit for Archipelago projects",
6
6
  "type": "module",
7
7
  "main": "./eslint.config.mjs",
@@ -47,13 +47,15 @@
47
47
  "dependencies": {
48
48
  "@antfu/eslint-config": "^4.12.0",
49
49
  "@unocss/eslint-config": "^66.5.3",
50
- "eslint": "^9.0.0",
50
+ "eslint": "^9.39.4",
51
+ "prettier": "^3.8.3",
51
52
  "eslint-plugin-format": "^1.0.1",
52
53
  "eslint-plugin-perfectionist": "^4.10.1",
53
54
  "eslint-plugin-tailwindcss": "^3.17.3",
54
55
  "prettier-plugin-tailwindcss": "^0.6.14"
55
56
  },
56
57
  "publishConfig": {
57
- "access": "public"
58
+ "access": "public",
59
+ "provenance": false
58
60
  }
59
61
  }
@@ -2,7 +2,7 @@ import { readFileSync } from 'node:fs'
2
2
 
3
3
  export function isValidCommitMessage(message) {
4
4
  const releaseRE = /^v\d/
5
- const commitRE = /^(revert: )?(feat|fix|docs|refactor|perf|test|build|ci|chore|style|types|workflow|release|deps)(\([a-z0-9-]+\))?: \S.{0,49}$/
5
+ const commitRE = /^(revert: )?(feat|fix|docs|refactor|perf|test|build|ci|chore|style|types|workflow|release|deps)(\([a-z0-9-]+\))?: \S.*$/
6
6
  return releaseRE.test(message) || commitRE.test(message)
7
7
  }
8
8
 
@@ -13,10 +13,17 @@ function getCommitSubject(rawMessage) {
13
13
  .find(line => line && !line.startsWith('#')) || ''
14
14
  }
15
15
 
16
+ function isSkippableCommitSubject(subject) {
17
+ return !subject || subject.startsWith('Merge ') || subject.startsWith('fixup! ') || subject.startsWith('squash! ')
18
+ }
19
+
16
20
  export function verifyCommitMessageFile(messageFilePath) {
17
21
  const rawMessage = readFileSync(messageFilePath, 'utf-8')
18
22
  const subject = getCommitSubject(rawMessage)
19
23
 
24
+ if (isSkippableCommitSubject(subject))
25
+ return
26
+
20
27
  if (isValidCommitMessage(subject))
21
28
  return
22
29
 
@@ -25,13 +32,12 @@ export function verifyCommitMessageFile(messageFilePath) {
25
32
  'fix: handle events on blur (close #28)',
26
33
  ]
27
34
 
28
- console.error('\nERROR: invalid commit message format.\n')
29
- console.error('Required format: <type>(optional-scope): <description>')
30
- console.error('Description max length: 50 characters\n')
31
- console.error('Examples:')
32
- examples.forEach(example => console.error(` - ${example}`))
33
- console.error('\nSee README.md (Auto commit message flow) for details.\n')
34
- process.exit(1)
35
+ console.warn('\nSUGGESTION: conventional commit format is recommended.\n')
36
+ console.warn('Required format: <type>(optional-scope): <description>')
37
+ console.warn('Suggested subject length: around 100 characters\n')
38
+ console.warn('Examples:')
39
+ examples.forEach(example => console.warn(` - ${example}`))
40
+ console.warn('\nSee README.md (Auto commit message flow) for details.\n')
35
41
  }
36
42
 
37
43
  if (import.meta.url === `file://${process.argv[1]}`) {
@@ -41,23 +41,23 @@ const VSCODE_ESLINT_SETTINGS = {
41
41
  'editor.defaultFormatter': 'dbaeumer.vscode-eslint',
42
42
  },
43
43
 
44
- // Git commit message validation (50/72 formatting)
45
- 'git.inputValidation': true,
46
- 'git.inputValidationSubjectLength': 50,
47
- 'git.inputValidationLength': 72,
44
+ // Keep commit message rules as guidance only, not strict blocking.
45
+ 'git.inputValidation': false,
46
+ 'git.inputValidationSubjectLength': 100,
47
+ 'git.inputValidationLength': 120,
48
48
 
49
49
  // Editor rules for git commit editor
50
50
  '[git-commit]': {
51
- 'editor.rulers': [50, 72],
51
+ 'editor.rulers': [100, 120],
52
52
  'editor.wordWrap': 'wordWrapColumn',
53
- 'editor.wordWrapColumn': 72,
53
+ 'editor.wordWrapColumn': 120,
54
54
  },
55
55
 
56
56
  // Editor rules for SCM input box (VS Code 1.86+)
57
57
  '[scminput]': {
58
- 'editor.rulers': [50, 72],
58
+ 'editor.rulers': [100, 120],
59
59
  'editor.wordWrap': 'wordWrapColumn',
60
- 'editor.wordWrapColumn': 72,
60
+ 'editor.wordWrapColumn': 120,
61
61
  },
62
62
  }
63
63