@lewishowles/lint-config 0.4.0 → 0.6.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.0: 2026-09-21
4
+
5
+ ### Changes
6
+
7
+ - Breaking: replace `comments/line-comments`, `comments/max-line-length`, `comments/sentence-punctuation`, `comments/block-comments`, `comments/jsdoc-tag-formatting`, and `comments/placement` with a single `comments/formatting` rule. Remove the old rule IDs from your configuration; `comments.json` already enables `comments/formatting`.
8
+ - Breaking: `base` now reports an error when statements of different kinds, such as a declaration followed by a function call, have no blank line between them, and when consecutive `const` or `let` declarations are separated by a blank line. Run `--fix` once to update existing code.
9
+ - `comments/formatting` moves trailing line comments onto their own line above the code.
10
+
11
+ ### Fixes
12
+
13
+ - `comments/formatting`: refill comment lines that were wrapped before the 80-column limit.
14
+ - `comments/variable-declarations`: skip the line-comment requirement for `const` declarations assigned to arrow functions or function expressions.
15
+
16
+ ## 0.5.0: 2026-09-11
17
+
18
+ ### Changes
19
+
20
+ - `comments/variable-declarations`: add a `rootOnly` option; `comments.json` enables it for test files so only root-level variables need comments there. If you override `comments.json` rules, concatenate the test-file override (see README).
21
+
22
+ ### Fixes
23
+
24
+ - Measure comment width in display columns, with tabs counted as four, so indented comments wrap and validate against the visible 80-column limit.
25
+
3
26
  ## 0.4.0: 2026-08-28
4
27
 
5
28
  ### New rules
package/README.md CHANGED
@@ -49,7 +49,7 @@ The Vue layer extends `base.json` internally, so you only need to extend `vue.js
49
49
 
50
50
  ### Comment formatting (optional)
51
51
 
52
- Add the comments layer alongside the base or Vue layer to enforce the comment-formatting rules, variable-declaration documentation, JSDoc on named functions and first-level object methods, documentation directly after each Vue `<script setup>` opening tag, and block comments for runtime `defineProps` properties:
52
+ Add the comments layer alongside the base or Vue layer to enforce the comment-formatting rules, including moving trailing line comments onto their own line, variable-declaration documentation, JSDoc on named functions and first-level object methods, documentation directly after each Vue `<script setup>` opening tag, and block comments for runtime `defineProps` properties:
53
53
 
54
54
  ```json
55
55
  {
@@ -73,7 +73,7 @@ The Vue component rule reads the raw `.vue` file because Oxlint's JS Plugin API
73
73
  }
74
74
  ],
75
75
  "rules": {
76
- "comments/line-comments": "error"
76
+ "comments/formatting": "error"
77
77
  }
78
78
  }
79
79
  ```
@@ -92,13 +92,45 @@ The `comments/configured-api-calls` rule requires an immediately preceding line
92
92
  }
93
93
  ```
94
94
 
95
+ The `comments/variable-declarations` rule accepts a `rootOnly` option to require comments only before root-level `const`, `let`, and `using` declarations. The comments layer already enables `rootOnly` for test files matched by `**/*.test.*`, `**/*.spec.*`, and `**/test/**`; other files keep the default of `false`. Override it for another scope or to change the behaviour:
96
+
97
+ ```json
98
+ {
99
+ "rules": {
100
+ "comments/variable-declarations": ["error", { "rootOnly": true }]
101
+ }
102
+ }
103
+ ```
104
+
95
105
  The `comments/class-documentation` rule requires an immediately preceding block comment before class declarations and const-assigned class expressions. Constructors, methods, getters, and setters require full JSDoc; constructors never need an `@returns` tag, and getters and setters need one only when they return a value. Instance and static fields require an immediately preceding line comment.
96
106
 
97
107
  ### `vp check` configuration
98
108
 
99
109
  The `vp check` and `vp lint` commands read Oxlint settings only from a `lint` block in `vite.config.js`; they do not read `.oxlintrc.json` directly. If `vite.config.js` is missing, they silently use an unrelated default configuration. You may still see plausible warnings and exit codes, but none of your rules are applied.
100
110
 
101
- Each consuming repo needs a `vite.config.js` with a `lint` block built from the config layer(s) and the repo's `.oxlintrc.json`, imported as JSON. Verify the setup with `vp lint --print-config <file>` and check that your real values, not defaults, are active.
111
+ Each consuming repo needs a `vite.config.js` with a `lint` block built from the config layer(s) and the repo's `.oxlintrc.json`, imported as JSON. Concatenate the `overrides` arrays from every imported layer before the local overrides so shared file-specific rules still apply. Verify the setup with `vp lint --print-config <file>` and check that your real values, not defaults, are active.
112
+
113
+ ```js
114
+ import { defineConfig } from "vite-plus";
115
+ import lintConfigBase from "@lewishowles/lint-config/base.json" with { type: "json" };
116
+ import lintConfigComments from "@lewishowles/lint-config/comments.json" with { type: "json" };
117
+ import oxlintrc from "./.oxlintrc.json" with { type: "json" };
118
+
119
+ const lint = {
120
+ ...lintConfigBase,
121
+ env: oxlintrc.env,
122
+ ignorePatterns: oxlintrc.ignorePatterns,
123
+ jsPlugins: [...lintConfigBase.jsPlugins, ...lintConfigComments.jsPlugins],
124
+ overrides: [
125
+ ...(lintConfigBase.overrides ?? []),
126
+ ...(lintConfigComments.overrides ?? []),
127
+ ...(oxlintrc.overrides ?? []),
128
+ ],
129
+ rules: { ...lintConfigBase.rules, ...lintConfigComments.rules },
130
+ };
131
+
132
+ export default defineConfig({ lint });
133
+ ```
102
134
 
103
135
  ## Customising
104
136
 
@@ -130,7 +162,7 @@ Ignore patterns are project-specific, so they always live in your project config
130
162
 
131
163
  ### Adding overrides
132
164
 
133
- Overrides are additive: shared overrides (if any) still apply, and your local ones are appended.
165
+ Overrides are additive in the `vite.config.js` lint block: shared overrides still apply, and your local ones are appended.
134
166
 
135
167
  ```json
136
168
  {
@@ -167,7 +199,7 @@ The base layer sorts named members within each import statement, but leaves decl
167
199
  ## What stays repo-local
168
200
 
169
201
  - `ignorePatterns`, since every project has different build output and tool directories
170
- - `overrides` for project-specific directories (e.g. `bin/**/*.js`, `src/cli/**/*.js`, `src/playwright/**/*.js`), since the file paths differ per project and can't be generalised
202
+ - `overrides` for project-specific directories (e.g. `bin/**/*.js`, `src/cli/**/*.js`, `src/playwright/**/*.js`), since the file paths differ per project and can't be generalised. The `vite.config.js` lint block appends these local entries after the shared layer overrides.
171
203
  - Rule relaxations for specific file patterns (e.g. turning off `vite-plus/prefer-vite-plus-imports` in generated `.d.ts` files)
172
204
  - Additional plugins, only for projects that need them
173
205
 
@@ -176,6 +208,6 @@ The base layer sorts named members within each import statement, but leaves decl
176
208
  When a project's `.oxlintrc.json` extends a shared layer:
177
209
 
178
210
  - **Rules** shallow-merge by key: your value wins for any rule defined in both
179
- - **Overrides** are additive: both shared and local `overrides` entries apply, including any `env` declared inside an override block
211
+ - **Overrides** are additive in the `vite.config.js` lint block: it concatenates shared layer and local `overrides` entries, including any `env` declared inside an override block
180
212
  - **Plugins** are additive: both shared and local `plugins`/`jsPlugins` load, deduplicated
181
213
  - **`env`, `globals`, and `ignorePatterns` don't merge through `extends` at all** (an open Oxlint bug), which is why the usage examples above redeclare `env`/`globals` directly. See [known limitations](docs/limitations.md) for the full detail, including the separate `vite-plus` caveat around resolving `extends` paths.
package/base.json CHANGED
@@ -35,13 +35,32 @@
35
35
  "@stylistic/no-confusing-arrow": "error",
36
36
  "@stylistic/padding-line-between-statements": [
37
37
  "error",
38
- { "blankLine": "always", "prev": "const", "next": "let" },
39
- { "blankLine": "always", "prev": "let", "next": "const" },
40
38
  { "blankLine": "always", "prev": "*", "next": "break" },
41
39
  { "blankLine": "always", "prev": ["const", "let"], "next": "*" },
40
+ { "blankLine": "always", "prev": "*", "next": ["const", "let"] },
42
41
  { "blankLine": "always", "prev": "*", "next": "return" },
43
- { "blankLine": "any", "prev": "const", "next": "const" },
44
- { "blankLine": "any", "prev": "let", "next": "let" },
42
+ {
43
+ "blankLine": "always",
44
+ "prev": ["block-like", "class", "do", "for", "function", "if", "switch", "try", "while"],
45
+ "next": "*"
46
+ },
47
+ {
48
+ "blankLine": "always",
49
+ "prev": "*",
50
+ "next": ["block-like", "class", "do", "for", "function", "if", "switch", "try", "while"]
51
+ },
52
+ {
53
+ "blankLine": "always",
54
+ "prev": { "selector": "ExpressionStatement[expression.type=\"AssignmentExpression\"]" },
55
+ "next": { "selector": "ExpressionStatement[expression.type=\"CallExpression\"]" }
56
+ },
57
+ {
58
+ "blankLine": "always",
59
+ "prev": { "selector": "ExpressionStatement[expression.type=\"CallExpression\"]" },
60
+ "next": { "selector": "ExpressionStatement[expression.type=\"AssignmentExpression\"]" }
61
+ },
62
+ { "blankLine": "never", "prev": "const", "next": "const" },
63
+ { "blankLine": "never", "prev": "let", "next": "let" },
45
64
  { "blankLine": "always", "prev": "multiline-const", "next": "*" },
46
65
  { "blankLine": "always", "prev": "*", "next": "multiline-const" }
47
66
  ],
@@ -1,12 +1,7 @@
1
- import blockComments from "./rules/block-comments.js";
2
1
  import classDocumentation from "./rules/class-documentation.js";
3
2
  import configuredApiCalls from "./rules/configured-api-calls.js";
3
+ import formatting from "./rules/formatting.js";
4
4
  import functionDocumentation from "./rules/function-documentation.js";
5
- import jsdocTagFormatting from "./rules/jsdoc-tag-formatting.js";
6
- import lineComments from "./rules/line-comments.js";
7
- import maxLineLength from "./rules/max-line-length.js";
8
- import placement from "./rules/placement.js";
9
- import sentencePunctuation from "./rules/sentence-punctuation.js";
10
5
  import variableDeclarations from "./rules/variable-declarations.js";
11
6
  import vueComponentDocumentation from "./rules/vue-component-documentation.js";
12
7
  import vueEmitDocumentation from "./rules/vue-emit-documentation.js";
@@ -15,15 +10,10 @@ import vuePropDocumentation from "./rules/vue-prop-documentation.js";
15
10
  export default {
16
11
  meta: { name: "comments" },
17
12
  rules: {
18
- "block-comments": blockComments,
19
13
  "class-documentation": classDocumentation,
20
14
  "configured-api-calls": configuredApiCalls,
15
+ formatting,
21
16
  "function-documentation": functionDocumentation,
22
- "jsdoc-tag-formatting": jsdocTagFormatting,
23
- "line-comments": lineComments,
24
- "max-line-length": maxLineLength,
25
- placement,
26
- "sentence-punctuation": sentencePunctuation,
27
17
  "variable-declarations": variableDeclarations,
28
18
  "vue-component-documentation": vueComponentDocumentation,
29
19
  "vue-emit-documentation": vueEmitDocumentation,
@@ -33,7 +33,8 @@ export default {
33
33
  * The class declaration node.
34
34
  */
35
35
  ClassDeclaration(node) {
36
- // Resolves any export wrapper before checking for documentation.
36
+ // Resolves any export wrapper before checking for
37
+ // documentation.
37
38
  const documentationNode = getDocumentationNode(node);
38
39
 
39
40
  if (!hasImmediateBlockComment(context.sourceCode, documentationNode)) {
@@ -44,8 +45,8 @@ export default {
44
45
  }
45
46
  },
46
47
  /**
47
- * Check class methods for required JSDoc blocks and tags. Constructors are
48
- * exempt from the @returns requirement.
48
+ * Check class methods for required JSDoc blocks and tags.
49
+ * Constructors are exempt from the @returns requirement.
49
50
  *
50
51
  * @param {object} node
51
52
  * The method-definition node.
@@ -93,7 +94,8 @@ export default {
93
94
  return;
94
95
  }
95
96
 
96
- // Static and instance fields share the requirement; only the wording differs.
97
+ // Static and instance fields share the requirement; only the
98
+ // wording differs.
97
99
  const message = node.static
98
100
  ? "Static fields require an immediately preceding line comment."
99
101
  : "Instance fields require an immediately preceding line comment.";
@@ -116,7 +118,8 @@ export default {
116
118
  return;
117
119
  }
118
120
 
119
- // Resolves any export wrapper before checking for documentation.
121
+ // Resolves any export wrapper before checking for
122
+ // documentation.
120
123
  const documentationNode = getDocumentationNode(node.parent);
121
124
 
122
125
  if (!hasImmediateBlockComment(context.sourceCode, documentationNode)) {
@@ -117,9 +117,9 @@ export default {
117
117
  * The call expression node.
118
118
  */
119
119
  CallExpression(node) {
120
- // Read fresh for every call: createOnce's visitor is shared across every file
121
- // in the run, so caching this at closure-creation time would freeze the first
122
- // file's options.
120
+ // Read fresh for every call: createOnce's visitor is shared
121
+ // across every file in the run, so caching this at
122
+ // closure-creation time would freeze the first file's options.
123
123
  const configuredApis = getConfiguredApis(context);
124
124
 
125
125
  if (node.callee.type !== "Identifier" || !configuredApis.has(node.callee.name)) {