@archpublicwebsite/eslint-config 1.0.10 → 1.0.13

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,79 @@
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
+ - Automatic project setup on install
20
+ - Works with the Archipelago repo style rules
21
+
22
+ ## Requirements
23
+
24
+ Consumer projects should have these tools available when using the full setup:
6
25
 
7
26
  ```bash
8
- cd packages/eslint-config
9
- pnpm version patch
10
- npm publish --access public
27
+ pnpm add -D eslint prettier lint-staged turbo
11
28
  ```
12
29
 
13
- Quick checks before publish:
30
+ ## Installation
14
31
 
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.
32
+ ```bash
33
+ pnpm add -D @archpublicwebsite/eslint-config
34
+ ```
17
35
 
18
- ## Install
36
+ ## Usage
19
37
 
20
- ```bash
21
- pnpm add -Dw eslint-config
38
+ Create or update the root `eslint.config.mjs`:
39
+
40
+ ```js
41
+ import { createArchipelagoConfig } from '@archpublicwebsite/eslint-config'
42
+
43
+ export default createArchipelagoConfig()
22
44
  ```
23
45
 
24
- ### Required dependencies (consumer project)
46
+ Override rules when your project needs to diverge from the shared defaults:
25
47
 
26
- This toolkit expects these dev dependencies to exist in the project that installs it:
48
+ ```js
49
+ import { createArchipelagoConfig } from '@archpublicwebsite/eslint-config'
27
50
 
28
- ```bash
29
- pnpm add -D lint-staged prettier turbo
51
+ export default createArchipelagoConfig({
52
+ name: 'project/overrides',
53
+ rules: {
54
+ 'no-console': 'off',
55
+ 'vue/max-attributes-per-line': 'off',
56
+ },
57
+ })
30
58
  ```
31
59
 
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.
60
+ ## What the setup does
35
61
 
36
- On install, this package automatically sets up in your project root:
62
+ On install or when you run the setup script manually, the package prepares the consumer project with:
37
63
 
38
64
  - `.hooks/pre-commit`
39
65
  - `.hooks/prepare-commit-msg`
40
66
  - `.hooks/commit-msg`
41
67
  - `.hooks/post-commit`
42
- - `eslint.config.mjs` (if not present)
68
+ - `eslint.config.mjs` when one does not already exist
43
69
  - `.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)
70
+ - `.vscode/settings.json` with ESLint flat-config settings
71
+ - `.vscode/extensions.json` with recommended extensions
72
+ - `git config core.hooksPath .hooks` when the project is a Git repository
47
73
 
48
- ### VS Code integration
74
+ ## VS Code integration
49
75
 
50
- On install, `.vscode/settings.json` is created or merged with these settings:
76
+ The setup merges ESLint-related settings into `.vscode/settings.json`:
51
77
 
52
78
  ```json
53
79
  {
@@ -65,100 +91,88 @@ On install, `.vscode/settings.json` is created or merged with these settings:
65
91
  }
66
92
  ```
67
93
 
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:
94
+ Existing settings are preserved. Only the ESLint-related keys are added or updated.
71
95
 
72
- ```bash
73
- node node_modules/@archpublicwebsite/eslint-config/tools/setup/install.mjs
74
- ```
96
+ ## Public API
75
97
 
76
- ## What this package provides
98
+ The package exports:
77
99
 
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
100
+ - `createArchipelagoConfig`
101
+ - setup scripts under `tools/`
87
102
 
88
- ## ESLint usage
103
+ ## AI Implementation Guide
89
104
 
90
- Auto-generated `eslint.config.mjs` uses this package directly:
105
+ If you are extending or regenerating this package, keep the workflow explicit:
91
106
 
92
- ```js
93
- import { createArchipelagoConfig } from 'eslint-config'
107
+ 1. Update `eslint.config.mjs` when shared lint rules change.
108
+ 2. Update `tools/setup/install.mjs` when install-time bootstrap behavior changes.
109
+ 3. Update `tools/git-hooks/` when hook behavior changes.
110
+ 4. Keep the package export map aligned with the public API.
111
+ 5. Document any new consumer dependency that the setup expects.
94
112
 
95
- export default createArchipelagoConfig()
96
- ```
113
+ ### AI-friendly implementation notes
97
114
 
98
- ### Override rules
115
+ - Use `createArchipelagoConfig()` in the consumer project, not the internal setup scripts.
116
+ - Keep root scripts in sync with the hook and lint expectations.
117
+ - Re-run the package setup flow when changing VS Code or hook behavior.
118
+ - Prefer explicit examples that show what the consumer project should add.
99
119
 
100
- You can override any rule in your root `eslint.config.mjs`:
120
+ ## Manual setup
101
121
 
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:
122
+ If you need to rerun the bootstrap manually:
117
123
 
118
124
  ```bash
119
- node node_modules/eslint-config/tools/setup/install.mjs
125
+ node node_modules/@archpublicwebsite/eslint-config/tools/setup/install.mjs
120
126
  ```
121
127
 
122
128
  ## Hook wrappers reference
123
129
 
124
- Root `.hooks` scripts should delegate to installed package path:
125
-
126
- - `.hooks/pre-commit`
130
+ Root `.hooks` scripts should delegate to the installed package path:
127
131
 
128
132
  ```bash
129
133
  #!/usr/bin/env bash
130
134
  set -euo pipefail
131
135
  cd "$(git rev-parse --show-toplevel)"
132
- node node_modules/eslint-config/tools/git-hooks/pre-commit.mjs
136
+ node node_modules/@archpublicwebsite/eslint-config/tools/git-hooks/pre-commit.mjs
133
137
  ```
134
138
 
135
- - `.hooks/prepare-commit-msg`
136
-
137
139
  ```bash
138
140
  #!/usr/bin/env bash
139
141
  set -euo pipefail
140
142
  cd "$(git rev-parse --show-toplevel)"
141
- node node_modules/eslint-config/tools/git-hooks/prepare-commit-msg.mjs "$@"
143
+ node node_modules/@archpublicwebsite/eslint-config/tools/git-hooks/prepare-commit-msg.mjs "$@"
142
144
  ```
143
145
 
144
- - `.hooks/commit-msg`
145
-
146
146
  ```bash
147
147
  #!/usr/bin/env bash
148
148
  set -euo pipefail
149
149
  cd "$(git rev-parse --show-toplevel)"
150
- node node_modules/eslint-config/tools/git-hooks/commit-msg.mjs "$1"
150
+ node node_modules/@archpublicwebsite/eslint-config/tools/git-hooks/commit-msg.mjs "$1"
151
151
  ```
152
152
 
153
- - `.hooks/post-commit`
154
-
155
153
  ```bash
156
154
  #!/usr/bin/env bash
157
155
  set -euo pipefail
158
156
  cd "$(git rev-parse --show-toplevel)"
159
- node node_modules/eslint-config/tools/git-hooks/post-commit.mjs
157
+ node node_modules/@archpublicwebsite/eslint-config/tools/git-hooks/post-commit.mjs
160
158
  ```
161
159
 
160
+ ## Publish
161
+
162
+ ```bash
163
+ cd packages/eslint-config
164
+ pnpm version patch
165
+ npm publish --access public
166
+ ```
167
+
168
+ Before publish, run:
169
+
170
+ ```bash
171
+ npm pack --dry-run
172
+ ```
173
+
174
+ Make sure the tarball contains only the intended public files: `eslint.config.mjs`, `tools/`, and `README.md`.
175
+
162
176
  ## Required root scripts
163
177
 
164
178
  ```json
@@ -173,3 +187,11 @@ node node_modules/eslint-config/tools/git-hooks/post-commit.mjs
173
187
  }
174
188
  }
175
189
  ```
190
+
191
+ ## Verification
192
+
193
+ After making config changes, validate the package by checking the installed consumer workflow or by running the setup script in a test project.
194
+
195
+ ## License
196
+
197
+ 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,54 @@ 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
+ // format/prettier is loaded by antfu internals even with formatters:false.
44
+ // Configure it to AGREE with our style so it never conflicts with
45
+ // style/quotes and style/semi → eliminates circular fix warnings.
46
+ 'format/prettier': ['warn', {
47
+ singleQuote: true,
48
+ semi: false,
49
+ printWidth: 120,
50
+ trailingComma: 'all',
51
+ arrowParens: 'avoid',
52
+ }],
53
+
54
+ // ── Anti-loop: disable rules that fight @stylistic equivalents ─────────
55
+ 'object-curly-newline': 'off',
56
+ 'style/object-curly-newline': 'off',
57
+ 'style/operator-linebreak': 'off',
58
+ 'style/indent': 'off',
59
+ 'style/indent-binary-ops': 'off',
60
+ 'max-statements-per-line': 'off',
61
+ 'antfu/consistent-list-newline': 'off',
62
+ 'antfu/consistent-chaining': 'off',
63
+ 'antfu/if-newline': 'off',
64
+ 'antfu/no-import-dist': 'off',
65
+
66
+ // ── Vue ──────────────────────────────────────────────────────────────
56
67
  'vue/multi-word-component-names': 'off',
57
68
  'vue/no-required-prop-with-default': 'off',
58
69
  'vue/html-self-closing': 'off',
59
70
  'vue/html-closing-bracket-spacing': 'off',
60
71
  'vue/no-multiple-template-root': 'off',
72
+ 'vue/attributes-order': 'off',
73
+ 'vue/singleline-html-element-content-newline': 'off',
74
+ 'vue/html-closing-bracket-newline': 'off',
75
+ 'vue/html-indent': 'off',
76
+ 'vue/no-useless-v-bind': 'off',
77
+ 'vue/prefer-separate-static-class': 'off',
78
+ 'vue/attribute-hyphenation': 'off',
79
+ 'vue/define-macros-order': 'off',
61
80
  'vue/max-attributes-per-line': ['error', {
62
81
  singleline: 3,
63
82
  multiline: 1,
@@ -72,12 +91,71 @@ export function createArchipelagoConfig(...overrides) {
72
91
  ignoreHTMLAttributeValues: true,
73
92
  ignoreHTMLTextContents: true,
74
93
  }],
75
- 'object-curly-newline': ['warn', {
76
- ImportDeclaration: { multiline: true, minProperties: 3 },
94
+
95
+ // ── TypeScript ───────────────────────────────────────────────────────
96
+ 'ts/no-use-before-define': 'off',
97
+ 'ts/no-empty-object-type': 'off',
98
+ 'ts/no-explicit-any': 'warn',
99
+ 'ts/no-var-requires': 'warn',
100
+ 'ts/consistent-type-imports': ['error', {
101
+ prefer: 'type-imports',
102
+ fixStyle: 'inline-type-imports',
77
103
  }],
78
- 'format/prettier': 'warn',
104
+
105
+ // ── Import ordering ──────────────────────────────────────────────────
106
+ 'import/order': 'off',
107
+ 'import/newline-after-import': 'off',
108
+ 'import/consistent-type-specifier-style': 'off',
109
+ 'perfectionist/sort-imports': 'off',
110
+ 'perfectionist/sort-exports': 'off',
111
+ 'perfectionist/sort-named-imports': 'off',
112
+ 'perfectionist/sort-named-exports': 'off',
113
+
114
+ // ── Tailwind ─────────────────────────────────────────────────────────
115
+ 'tailwindcss/no-custom-classname': 'off',
116
+ 'tailwindcss/migration-from-tailwind-2': 'off',
117
+ 'tailwindcss/enforces-shorthand': 'off',
118
+
119
+ // ── Misc ─────────────────────────────────────────────────────────────
120
+ 'no-console': 'warn',
121
+ 'no-alert': 'off',
122
+ 'jsonc/sort-keys': 'off',
123
+ 'jsonc/sort-array-values': 'off',
124
+ 'regexp/no-unused-capturing-group': 'off',
125
+ 'regexp/optimal-quantifier-concatenation': 'off',
126
+ 'regexp/no-super-linear-backtracking': 'off',
127
+ 'regexp/negation': 'off',
128
+ 'node/prefer-global/process': 'off',
129
+ 'unicorn/prefer-number-properties': 'off',
130
+ 'unicorn/new-for-builtins': 'off',
131
+ },
132
+ },
133
+
134
+ // ── Package-level overrides (matches user's packages/** pattern) ──────────
135
+ {
136
+ name: 'archipelago/packages',
137
+ files: ['packages/**/*.{js,ts,vue}'],
138
+ rules: {
139
+ 'vue/multi-word-component-names': 'off',
140
+ },
141
+ },
142
+
143
+ // ── Nuxt app overrides ────────────────────────────────────────────────────
144
+ {
145
+ name: 'archipelago/nuxt',
146
+ files: [
147
+ 'apps/nuxt-web/components/**/*.{js,ts,vue}',
148
+ 'apps/nuxt-web/pages/**/*.{js,ts,vue}',
149
+ 'apps/nuxt-web/layouts/**/*.{js,ts,vue}',
150
+ 'apps/nuxt-web/composables/**/*.{js,ts}',
151
+ 'apps/nuxt-web/constants/**/*.{js,ts}',
152
+ ],
153
+ rules: {
154
+ 'vue/multi-word-component-names': 'off',
155
+ 'ts/no-explicit-any': 'warn',
79
156
  },
80
157
  },
158
+
81
159
  ...overrides,
82
160
  )
83
161
  }
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.13",
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