eslint-plugin-lube 0.5.1 → 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.
Files changed (85) hide show
  1. package/CHANGELOG.md +260 -0
  2. package/LICENSE +21 -0
  3. package/README.md +120 -9
  4. package/docs/ascii-order.md +81 -0
  5. package/docs/pretty-imports.md +70 -59
  6. package/docs/pretty-jsdoc-casting.md +31 -23
  7. package/docs/pretty-sequence.md +129 -117
  8. package/docs/pretty-ternary.md +55 -0
  9. package/docs/svelte-naming-convention.md +59 -46
  10. package/package.json +60 -38
  11. package/src/index.js +299 -0
  12. package/src/rules/ascii-order.js +940 -0
  13. package/src/rules/pretty-imports.js +176 -0
  14. package/src/rules/pretty-jsdoc-casting.js +278 -0
  15. package/src/rules/pretty-sequence.js +489 -0
  16. package/src/rules/pretty-ternary.js +227 -0
  17. package/src/rules/svelte-naming-convention.js +903 -0
  18. package/src/utils/fix_recorder.js +50 -0
  19. package/src/utils/keep_comments.js +99 -0
  20. package/src/utils/keep_line_breaks.js +56 -0
  21. package/src/utils/skip_hole_commas.js +32 -0
  22. package/src/utils/skip_optional_patterns.js +27 -0
  23. package/src/utils/skip_unchanged_fixes.js +35 -0
  24. package/src/utils/source_text.js +442 -0
  25. package/src/utils/split_declarations.js +75 -0
  26. package/src/utils/text_width.js +9 -0
  27. package/types/index.d.ts +27 -13
  28. package/types/index.d.ts.map +1 -1
  29. package/index.js +0 -126
  30. package/private.d.ts +0 -168
  31. package/rules/pretty-imports.js +0 -147
  32. package/rules/pretty-jsdoc-casting.js +0 -236
  33. package/rules/pretty-sequence.js +0 -441
  34. package/rules/svelte-naming-convention.js +0 -361
  35. package/test/pretty-imports/ExportNamedDeclaration.js +0 -123
  36. package/test/pretty-imports/ImportDeclaration.js +0 -125
  37. package/test/pretty-imports.js +0 -20
  38. package/test/pretty-jsdoc-casting/case_by_expression.js +0 -289
  39. package/test/pretty-jsdoc-casting/various_situations.js +0 -111
  40. package/test/pretty-jsdoc-casting.js +0 -22
  41. package/test/pretty-sequence/case_by_node_type.js +0 -360
  42. package/test/pretty-sequence/case_by_option.js +0 -142
  43. package/test/pretty-sequence/various_situations.js +0 -204
  44. package/test/pretty-sequence.js +0 -23
  45. package/test/svelte-naming-convention/basic_snake_case.js +0 -67
  46. package/test/svelte-naming-convention/case_by_identifier.js +0 -1394
  47. package/test/svelte-naming-convention/snake_case_with_symbols.js +0 -67
  48. package/test/svelte-naming-convention.js +0 -25
  49. package/tsconfig.json +0 -21
  50. package/types/rules/pretty-imports.d.ts +0 -3
  51. package/types/rules/pretty-imports.d.ts.map +0 -1
  52. package/types/rules/pretty-jsdoc-casting.d.ts +0 -3
  53. package/types/rules/pretty-jsdoc-casting.d.ts.map +0 -1
  54. package/types/rules/pretty-sequence.d.ts +0 -3
  55. package/types/rules/pretty-sequence.d.ts.map +0 -1
  56. package/types/rules/svelte-naming-convention.d.ts +0 -3
  57. package/types/rules/svelte-naming-convention.d.ts.map +0 -1
  58. package/types/test/pretty-imports/ExportNamedDeclaration.d.ts +0 -2
  59. package/types/test/pretty-imports/ExportNamedDeclaration.d.ts.map +0 -1
  60. package/types/test/pretty-imports/ImportDeclaration.d.ts +0 -2
  61. package/types/test/pretty-imports/ImportDeclaration.d.ts.map +0 -1
  62. package/types/test/pretty-imports.d.ts +0 -2
  63. package/types/test/pretty-imports.d.ts.map +0 -1
  64. package/types/test/pretty-jsdoc-casting/case_by_expression.d.ts +0 -2
  65. package/types/test/pretty-jsdoc-casting/case_by_expression.d.ts.map +0 -1
  66. package/types/test/pretty-jsdoc-casting/various_situations.d.ts +0 -2
  67. package/types/test/pretty-jsdoc-casting/various_situations.d.ts.map +0 -1
  68. package/types/test/pretty-jsdoc-casting.d.ts +0 -2
  69. package/types/test/pretty-jsdoc-casting.d.ts.map +0 -1
  70. package/types/test/pretty-sequence/case_by_node_type.d.ts +0 -2
  71. package/types/test/pretty-sequence/case_by_node_type.d.ts.map +0 -1
  72. package/types/test/pretty-sequence/case_by_option.d.ts +0 -2
  73. package/types/test/pretty-sequence/case_by_option.d.ts.map +0 -1
  74. package/types/test/pretty-sequence/various_situations.d.ts +0 -2
  75. package/types/test/pretty-sequence/various_situations.d.ts.map +0 -1
  76. package/types/test/pretty-sequence.d.ts +0 -2
  77. package/types/test/pretty-sequence.d.ts.map +0 -1
  78. package/types/test/svelte-naming-convention/basic_snake_case.d.ts +0 -2
  79. package/types/test/svelte-naming-convention/basic_snake_case.d.ts.map +0 -1
  80. package/types/test/svelte-naming-convention/case_by_identifier.d.ts +0 -2
  81. package/types/test/svelte-naming-convention/case_by_identifier.d.ts.map +0 -1
  82. package/types/test/svelte-naming-convention/snake_case_with_symbols.d.ts +0 -2
  83. package/types/test/svelte-naming-convention/snake_case_with_symbols.d.ts.map +0 -1
  84. package/types/test/svelte-naming-convention.d.ts +0 -2
  85. package/types/test/svelte-naming-convention.d.ts.map +0 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,260 @@
1
+ # Changelog
2
+
3
+ ## 0.6.0
4
+
5
+ ### Breaking
6
+
7
+ - **Two configs replace `configs.plugins` and `configs.rules`.** `configs.strict` holds the rules
8
+ `configs.rules` held, the house style with renaming, sorting and core rules, and
9
+ `configs.recommended` is a lighter set that only formats and orders, with rules that all have a
10
+ fix. Each is a flat config object with `plugins` and `rules`: replace
11
+ `plugins: lube.configs.plugins, rules: { ...lube.configs.rules }` with
12
+ `plugins: lube.configs.strict.plugins, rules: { ...lube.configs.strict.rules }`, or spread
13
+ `...lube.configs.strict` into the config.
14
+ - **Every rule rejects options it does not know.** A misspelled option such as `maxLenght` is a
15
+ configuration error instead of being ignored, and `pretty-jsdoc-casting` takes no options.
16
+ - **`svelte-naming-convention` is a `suggestion` rule, no longer `layout`,** since its fix renames
17
+ identifiers: `eslint --fix --fix-type layout` leaves names alone now.
18
+ - **The package is an ES module only.** `import lube from "eslint-plugin-lube"` works as before on
19
+ Node.js 18.18+, 20.9+ and 21.1+, the versions `@stylistic/eslint-plugin` supports. A CommonJS
20
+ `eslint.config.cjs` still gets the plugin itself from `require("eslint-plugin-lube")` on Node.js
21
+ 20.19+ and 22.12+, which ESLint 10 requires anyway. Deep paths such as `eslint-plugin-lube/rules/ascii-order` are gone; the rules are
22
+ `lube.rules`.
23
+ - **Both configs use `@stylistic/eslint-plugin` instead of the deprecated core formatting
24
+ rules,** which ESLint 11 removes. Rename overrides of those rules:
25
+ ```js
26
+ // before
27
+ rules: { ...lube.configs.rules, "indent": ["error", 4] }
28
+ // after
29
+ rules: { ...lube.configs.strict.rules, "@stylistic/indent": ["error", 4] }
30
+ ```
31
+ `func-call-spacing` is `@stylistic/function-call-spacing`. `@stylistic/indent` also checks
32
+ TypeScript syntax, and `@stylistic/operator-linebreak` checks `=` of type aliases, which stays at the
33
+ end of the line: `type Name =` followed by `| "a"`.
34
+ - **The strict config reports blank lines** with `@stylistic/no-multiple-empty-lines` (`max: 0`)
35
+ and fixes `arrow-body-style`, `new-parens`, `no-extra-boolean-cast`, `no-extra-semi`,
36
+ `no-unneeded-ternary`, `no-useless-computed-key`, `no-useless-rename`, `no-useless-return`,
37
+ `prefer-exponentiation-operator`, `prefer-object-spread` and `yoda`. Run `eslint --fix` once.
38
+ - **The strict config reports functions assigned to variables** with `func-style`
39
+ (`declaration`): write `function name() {}` instead of `const name = () => {}`. Callbacks and
40
+ arrow functions that use `this` are not reported. It cannot be fixed.
41
+ - **The strict config sorts import statements, import and export names, object keys, function
42
+ declarations and test cases** with the new `ascii-order`, all of its options on. Run
43
+ `eslint --fix` once, then reorder by hand what it reports without a fix, or disable it where the
44
+ order matters: `// eslint-disable-next-line lube/ascii-order`. A report without a fix says why,
45
+ ``Move key "a" before "b" to keep keys in ASCII order; it is not fixed automatically because moving
46
+ `f()` could change the order of side effects, so reorder it by hand``, or that a comment or statement
47
+ next to the item would end up in the wrong place. Keys whose values construct a
48
+ built-in from literals, such as `{ updatedAt: new Date(), createdAt: new Date() }` and
49
+ `{ s: new Set([ 1 ]), m: new Map() }`, are fixed, and so are keys whose values are a `const`, a
50
+ namespace import or a function or class declaration that is never assigned, which no call can
51
+ change: `{ shadow: shadowed(), helper }`. A `const` or class counts only where the value comes
52
+ after its declaration and outside a function declaration, which could run before it, so a read
53
+ that throws in the temporal dead zone still throws after the calls written before it. A
54
+ construction that always throws, such as `new RegExp("(")`, `new Array(-1)` or `new Map([ 1 ])`,
55
+ is not moved, nor one that another runtime may reject or that allocates a lot while linting:
56
+ `new RegExp` with a flag other than `gimsuy` or with syntax newer than ES2018, such as
57
+ `new RegExp("a", "v")` or `(?i:a)`, and `new Array`, a buffer, a typed array or a `DataView` with a
58
+ number over 65536 in its arguments, such as `new Set(new Array(1e8))`. Its fix assumes modules can run
59
+ in any order and nothing reads key order: sorted keys change `Object.keys`, `JSON.stringify` and
60
+ `for...in`, and an import without names, such as `import "./setup.js"`, is never moved and no
61
+ import moves across it. Under `exports` and `imports` of a
62
+ `package.json` it puts `types` first and `default` last, as TypeScript and Node.js read them.
63
+ - **Both configs break nested and long ternaries** with the new `pretty-ternary`: a
64
+ ternary with a ternary branch, or longer than 80 characters, puts `?` and `:` at the start of their
65
+ lines, one indent deeper per level. Run `eslint --fix` once.
66
+ - **`pretty-imports` checks imports with a default import** such as `import def, {a,b} from "m"`,
67
+ which it skipped before.
68
+ - **`pretty-sequence` and `pretty-imports` leave the indentation of code that is already written over
69
+ several lines to `@stylistic/indent`,** and write it only for the line breaks they insert themselves.
70
+ The two rules owned the same lines before, so wherever the indent rule measures a line differently,
71
+ `eslint --fix` never finished. Turn `fixIndent` on in a config without an indent rule.
72
+ - **Both configs wrap the `@stylistic` rules whose fixes break code or never settle:**
73
+ `comma-style` leaves the comma of an array hole on its own line, `operator-linebreak` leaves an
74
+ operator a comment follows, `object-curly-newline` and `object-curly-spacing` skip optional
75
+ destructured parameters, `key-spacing`, `semi-spacing`, `space-unary-ops`, `generator-star-spacing`,
76
+ `rest-spread-spacing` and `yield-star-spacing` keep the comments in the space they remove, every fix
77
+ writes the line break of the file, and a fix that would change nothing is dropped.
78
+ - **`max-len` is in neither config,** since it cannot be fixed.
79
+ - **`svelte-naming-convention` reports more declarations.** Function expression names and
80
+ parameters, `catch` parameters, parameters of exported camelCase functions, non-shorthand
81
+ destructuring such as `const { key: camelCase } = value` and `import { "name" as camelCase }`
82
+ are reported now. Expect new errors on existing code.
83
+ - **`svelte-naming-convention` treats `for...in` and `for...of` targets as usages.** They are fixed
84
+ together with their declaration, like assignments, instead of being renamed on their own.
85
+ - **`pretty-jsdoc-casting` puts one empty comment after nested castings that end together,** after
86
+ the outermost one: `/** @type {A} */(/** @type {unknown} */(a))/**/` instead of
87
+ `/** @type {A} */(/** @type {unknown} */(a)/**/)/**/`. Run `eslint --fix` once.
88
+ - **Every rule message says what to change and why:** `Rename 'isV' to 'is_v'`,
89
+ ``Write these items on one line as `[ a, b ]`, since they fit in 30 characters``,
90
+ `Put each item and the closing bracket on a line of its own, since the items are longer than 30
91
+ characters together`, ``Break this ternary before `?` and `:`, since a branch is another ternary``,
92
+ `Move key "a" before "b" to keep keys in ASCII order`. The message IDs are new:
93
+ `pretty-sequence` reports `multiline`, `single_line` and `indent`; `pretty-imports` `multiline`,
94
+ `single_line`, `indent`, `semicolon` and `no_semicolon` for imports and exports alike;
95
+ `pretty-ternary` `multiline` and `spacing`; `pretty-jsdoc-casting` `marker` and `format`; and
96
+ `svelte-naming-convention` `rename` and `case`.
97
+
98
+ ### Fixed
99
+
100
+ - The `maxLength` of `pretty-sequence` and `pretty-imports` counts a character that takes two
101
+ columns, such as a Korean, Chinese or Japanese one, as two. A line of Korean strings and a line of
102
+ Latin ones that take the same width on screen are now broken or joined alike, where the Korean one
103
+ used to stay on one line at twice the width.
104
+ - The message that asks for one line said the items "fit in" the `maxLength`, although it measures
105
+ the items alone, without the code around them, so the line it wrote could be much longer. It now
106
+ names the width it measured: "since the items are 75 characters together, within the 80 allowed".
107
+ - `pretty-jsdoc-casting` added `/**/` after casts in TypeScript files, where a JSDoc cast means
108
+ nothing. `.ts`, `.tsx`, `.mts` and `.cts` files are not checked now.
109
+ - The `one-var` fix of the strict config left `const a = 1; const b = 2` on one line, which
110
+ `@stylistic/max-statements-per-line` reported without a fix. `eslint --fix` puts each of the
111
+ declarations on a line of its own now.
112
+ - `no-duplicate-imports` of the strict config reported `import type { A } from "m"` next to
113
+ `import { b } from "m"`. A separate type import is allowed now.
114
+ - The `@stylistic/space-unary-ops`, `rest-spread-spacing`, `generator-star-spacing`,
115
+ `yield-star-spacing`, `semi-spacing` and `key-spacing` fixes of both configs deleted a
116
+ comment in the space they remove, or moved a colon into one: `!/** @type {A} */(a)/**/` lost its
117
+ type cast, `.../* @__PURE__ */ f()` its comment, and `a // note` followed by `: 1` became
118
+ `a // note: 1`. Such a space is left unreported now.
119
+ - In a file whose line breaks are CRLF, CR, U+2028 or U+2029, `pretty-sequence`, `pretty-imports`
120
+ and `pretty-ternary` counted only LF as a line break, so they indented from the wrong line, wrote
121
+ LF line breaks into the file and never stopped fixing it; `pretty-sequence` also indented the lines
122
+ inside a string or a template that spans such lines, changing its value, `` f(`a `` + U+2028 +
123
+ `` b`, c) `` grew a tab in front of `b`, and `pretty-ternary` and `pretty-jsdoc-casting` read those
124
+ line breaks as none. Every rule and the `@stylistic` fixes of both configs follow the
125
+ line break of the file now.
126
+ - `ascii-order` sorted only the outermost of nested objects, patterns or import braces per
127
+ `eslint --fix` pass, one pass per nesting level, so deeply nested files needed more than the 10
128
+ passes ESLint runs. Nested ones are sorted in the same pass now.
129
+ - `ascii-order` swapped destructuring targets whose order matters: `var { b: x, a: x } = o` changed
130
+ the value of `x`, and `({ b: this.b, a: this.a } = o)` the order of the setter calls. They are
131
+ reported without a fix now.
132
+ - `pretty-imports` removed `type` from `import type` and `export type`, import attributes such as
133
+ `with { type: "json" }`, and comments between the braces.
134
+ - `pretty-imports` removed a semicolon another statement needs: the one before a statement on the
135
+ same line, `import { a } from "m";var b = 1` became `import { a } from "m"var b = 1`, and the one
136
+ that starts the next line, `;[a].map(f)`. It also added a semicolon before the `}` that closes a
137
+ namespace, which `@stylistic/semi` of both configs removed again on every fix.
138
+ - `pretty-jsdoc-casting` changed what a cast means: it moved the cast of an inner expression out of
139
+ the parentheses, `/** @type {X} */(/** @type {A} */(a).b)` became
140
+ `/** @type {A} *//** @type {X} */((a).b)`, deleted the text after the type of a type comment,
141
+ `/** @type {A} @deprecated */ (a)` lost `@deprecated`, turned the plain comment
142
+ `/* @type {A} */ (a)` into a type cast, and removed the empty comment after a type comment that
143
+ spans lines. A type comment is kept as written now unless it holds only the type. It also mangled
144
+ `/** @type {A} */(a)/**//**/`, left a double space for `/** @type {A} */ (a)` and moved a cast onto
145
+ the next line when a line break followed the type comment.
146
+ - `pretty-jsdoc-casting` moved what stood between the cast parenthesis and the expression in front
147
+ of the type comment: a line break, so `return /** @type {A} */(` followed by `b)/**/` returned
148
+ `undefined`; the JSDoc of a function inside the cast, which landed between `export default` and
149
+ the cast with broken indentation; and the white space of a cast written over several lines, which
150
+ put the cast on a new line and left the old one empty, so with either config every
151
+ `eslint --fix` added one more line and one more indent level. That white space is dropped now,
152
+ unless a line comment ends there, and a cast is left unfixed when another comment stands there or
153
+ when a line break after `return`, `throw` or `yield` would stay.
154
+ - `pretty-jsdoc-casting` read the argument parentheses of a call as cast parentheses when a type
155
+ comment stood before them, so `var x = 1` followed by `/** @type {T} */(f(a))` (a call, because no
156
+ semicolon ends the first line) got a `/**/` marker and never stopped fighting `pretty-sequence`.
157
+ The parentheses of a call, `new` or `import()` are left alone now.
158
+ - `pretty-sequence` and `pretty-jsdoc-casting` took time quadratic in the file size, and
159
+ `pretty-sequence` in the line length: a 258 KB file took about 40 seconds per rule and takes about
160
+ 0.1 seconds, and a 1.4 MB single-line file took 33 seconds and takes about 2 seconds, most of it
161
+ parsing.
162
+ - `pretty-sequence` broke TypeScript: `({ a, b }: Props) => a` became `({ a, b s) => a`, the
163
+ annotation of an array pattern was deleted, and `f<(x: number) => void>( a )` became `f<(a)`.
164
+ - `pretty-sequence` lost or moved comments and holes: a line comment after the last item commented
165
+ out the closing bracket, `[ b, c // note` followed by `]` became `[ b, c // note ]`; comments after
166
+ a trailing comma or inside empty brackets and the trailing hole of `[a, ,]` were deleted; and a
167
+ line comment after an item's comma moved onto the next item's line. It stays with its item now.
168
+ - `pretty-sequence` changed the value of a multiline template literal, a string with a line
169
+ continuation or a multiline JSX attribute string, `f(a, <div title="one` followed by ` two">)`,
170
+ by re-indenting its lines. Such sequences are left unfixed.
171
+ - `pretty-sequence`: with `funcCallSpacing`, `a => b` gained more spaces on every fix.
172
+ - `pretty-sequence` wrote indentation onto the empty lines of a function it moved to a new line.
173
+ - `pretty-sequence` and `@stylistic/indent` fixed each other endlessly ("Circular fixes detected")
174
+ for a sequence opening on the first line of a declaration whose last declarator starts on a later
175
+ line, `let i = [` … `], a = 1`, for a line starting with `;` as `@stylistic/semi-style: first`
176
+ writes it, for the arguments of a call that follows a multiline parenthesized expression on the
177
+ same line, `(a` `|| b).catch(c, d)` or `(a ? b : "") + f(c, d)`, and for a sequence on a line that
178
+ starts inside a block comment, `*/ const a = [b, c]`. `pretty-sequence` indents them like
179
+ `@stylistic/indent` now.
180
+ - In `.svelte` files, `pretty-sequence` and `pretty-ternary` indented a template expression such as
181
+ `{await f(` from the column where the markup before it started, and `@stylistic/indent` undid it
182
+ on every fix.
183
+ - The `pretty-sequence` rule description was copied from `pretty-jsdoc-casting`.
184
+ - `svelte-naming-convention` renamed usages as if they were declarations, arrow function bodies and
185
+ `extends` clauses among them, so references to imported or global names broke, and it left other
186
+ usages with the old name: `do...while` conditions, computed keys, class field values, `import()`,
187
+ JSX, decorators, TypeScript expressions such as `camelCase as T`, `camelCase!` and
188
+ `typeof camelCase`, `export = camelCase`, enum member values, type predicates, the overloads of a
189
+ function (only the implementation was renamed), the object of a JSX member tag such as
190
+ `<routeModule.Layout>`, and the markup of a `.svelte` file, where every node was read as a name
191
+ the rule must not touch, so `{camelCase}` in a mustache tag, an attribute, a directive or a block
192
+ expression stopped the rename. Every usage that scope analysis reaches is renamed with its
193
+ declaration now, a shorthand attribute becomes `camelCase={camel_case}`, what the markup declares,
194
+ such as the context of `{#each}` or a `let:` property, is left alone, and a name is reported
195
+ without a fix where the rule cannot tell a reference from a type or a property, such as
196
+ `let a: camelCase`, or where it is a component tag, `<My_Comp />`, which a lowercase name would
197
+ turn into an HTML tag.
198
+ - `svelte-naming-convention` broke destructuring and exports: `{ camelCase: camelCase }` was read as
199
+ a shorthand property and became `{ camelCase: camelCase: camel_case }`, a shorthand with a default,
200
+ `{ camelCase = 1 }` in a pattern, was never renamed while every other use of the name was, and
201
+ `export { camelCase }` lost its binding. They become `{ camelCase: camel_case }`,
202
+ `{ camelCase: camel_case = 1 }` and `export { camel_case as camelCase }` now, the declaration and
203
+ its export specifier in one fix, since separate fixes in one pass could leave `export` pointing at
204
+ a name that no longer exists, a syntax error.
205
+ - `svelte-naming-convention` matched usages to declarations by name only, so its fixes broke code
206
+ that the Svelte code base holds: a global or an exported camelCase function used where a parameter
207
+ of the same name was renamed elsewhere was renamed too, e.g. `requestAnimationFrame()` or
208
+ `flushSync()` became undefined; the usages of an import, `import { fetchModule }`, were renamed
209
+ with a same-named declaration elsewhere but not the import; a name whose snake_case form is already
210
+ a variable was renamed into it, e.g. `itemCount` next to `item_count`; the type annotation and `?`
211
+ of a TypeScript name were deleted, `itemCount?: number` became `item_count`; a parameter mentioned
212
+ in the prose of a JSDoc comment was renamed while `@param {T} callbackFn`, `[superClass]`,
213
+ `{callbackFn is F}` and `typeof callbackFn` kept the old name and failed type checking; and a store
214
+ read as `$userStore` lost its declaration. Usages follow scope analysis now, an import becomes
215
+ `import { fetchModule as fetch_module }` and `import { foo_bar as fooBar }` becomes
216
+ `import { foo_bar }`, a colliding rename is reported without a fix, only `typeof`, `asserts` and
217
+ `is` inside `{ }` of a JSDoc comment are renamed with the parameter, and in a `.svelte` file the
218
+ `$camelCase` subscriptions are renamed with the store in one fix, while outside one `$camelCase`
219
+ stays a name of its own and nothing is renamed.
220
+ - `svelte-naming-convention` renamed only part of a name and broke the code when another rule's fix
221
+ overlapped a usage in the same `eslint --fix` pass, such as one inside an argument list
222
+ `pretty-sequence` reformats, or when a declaration of the name is one the rule does not rename: a
223
+ function merged with a TypeScript namespace of the same name, as in `.d.ts` files,
224
+ `declare namespace pLimit` and `declare function pLimit(): pLimit.Limit`, a declaration exported
225
+ with `export var` next to a `var` of the same name, a parameter that shadows a function of the same
226
+ name, and a declaration turned off with `// eslint-disable-next-line`, `// eslint-disable-line` or
227
+ `/* eslint-disable */`, whose usages were renamed anyway. With `fixSameNames`, usages are renamed
228
+ first and the declaration in a later pass, once no usage of the old name is left, together with the
229
+ assignments to it and an `export default` of it, so `prefer-const` of the strict config never
230
+ turns `let lastBid = 1` into a `const` whose `lastBid += 1` was renamed in an earlier pass, and
231
+ `ascii-order` never moves a default-exported function while the export names it differently; a
232
+ name whose snake_case form is declared elsewhere is renamed in one fix with its usages; with
233
+ `fixSameNames: false` a declaration is renamed with its usages instead of without them; and the
234
+ other names are reported without a fix.
235
+
236
+ ### Added
237
+
238
+ - `pretty-sequence` and `pretty-imports` take `fixIndent`. With it on, the rule reports a sequence or a
239
+ list of specifiers whose lines differ from it only in their indentation, as it always did.
240
+ - `ascii-order`, in the strict config: sorts import statements by module path, names in import
241
+ and export braces, object keys, function declarations next to each other and `describe`, `it` and
242
+ `test` calls in ASCII order, each turned off with `checkImports`, `checkNames`, `checkKeys`,
243
+ `checkDeclarations` or `checkTests`. Side-effect imports and a function exported with
244
+ `export default name` keep their place. When moving an item could change what the code does, such
245
+ as swapping two object values that call functions, it reports without a fix.
246
+ - `pretty-ternary`, in both configs: breaks a ternary or TypeScript conditional type
247
+ before `?` and `:` when a branch is another ternary, when it is longer than `maxLength` (80) or
248
+ when it already spans lines, indenting each nested level once more. Only the spaces around `?`
249
+ and `:` change.
250
+ - `configs.recommended`, for format on save: the `@stylistic` formatting rules, `pretty-imports`,
251
+ `pretty-jsdoc-casting`, `pretty-sequence` and `pretty-ternary` with items on one line up to 80
252
+ characters, and `ascii-order` for the names inside import and export braces only. It ends a file
253
+ with a line break, allows one blank line, never renames or moves statements or keys, and every
254
+ rule in it has a fix: `{ ...lube.configs.recommended, files: ["**/*.js"] }`, or
255
+ `extends: ["lube/recommended"]` with `defineConfig`.
256
+ - `configs.strict`, the house style: everything above plus `svelte-naming-convention`, every
257
+ `ascii-order` check, `pretty-sequence` and `pretty-imports` at 30 characters, no blank lines, no
258
+ line break at the end of a file, one statement per line and core rules such as `func-style`,
259
+ `no-shadow` and `prefer-const`.
260
+ - `meta.version`, so ESLint can cache results per plugin version.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 artxe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,9 +1,120 @@
1
- # Eslint plugin lube
2
- ## Full fixable rules for auto-formatting with ESLint only without Prettier
3
-
4
- | Rule | Docs | Code | Test |
5
- |---|---|---|---|
6
- | pretty-imports | [docs](https://github.com/Artxe2/lube-series/blob/master/packages/eslint-plugin-lube/docs/pretty-imports.md) | [code](https://github.com/Artxe2/lube-series/blob/master/packages/eslint-plugin-lube/rules/pretty-imports.js) | [test](https://github.com/Artxe2/lube-series/blob/master/packages/eslint-plugin-lube/test/pretty-imports) |
7
- | pretty-jsdoc-casting | [docs](https://github.com/Artxe2/lube-series/blob/master/packages/eslint-plugin-lube/docs/pretty-jsdoc-casting.md) | [code](https://github.com/Artxe2/lube-series/blob/master/packages/eslint-plugin-lube/rules/pretty-jsdoc-casting.js) | [test](https://github.com/Artxe2/lube-series/blob/master/packages/eslint-plugin-lube/test/pretty-jsdoc-casting) |
8
- | pretty-sequence | [docs](https://github.com/Artxe2/lube-series/blob/master/packages/eslint-plugin-lube/docs/pretty-sequence.md) | [code](https://github.com/Artxe2/lube-series/blob/master/packages/eslint-plugin-lube/rules/pretty-sequence.js) | [test](https://github.com/Artxe2/lube-series/blob/master/packages/eslint-plugin-lube/test/pretty-sequence) |
9
- | svelte-naming-convention | [docs](https://github.com/Artxe2/lube-series/blob/master/packages/eslint-plugin-lube/docs/svelte-naming-convention.md) | [code](https://github.com/Artxe2/lube-series/blob/master/packages/eslint-plugin-lube/rules/svelte-naming-convention.js) | [test](https://github.com/Artxe2/lube-series/blob/master/packages/eslint-plugin-lube/test/svelte-naming-convention) |
1
+ # ESLint Plugin Lube
2
+ Fixable formatting and ordering rules, so `eslint --fix` formats a project without Prettier.
3
+
4
+ Instead of Prettier next to ESLint, with a second config and a plugin to keep the two from fighting, formatting is a set of ESLint rules: one `eslint --fix` formats and lints, and each rule can be tuned or turned off like any other.
5
+
6
+ ## Installation
7
+ ```bash
8
+ npm i -D eslint eslint-plugin-lube
9
+ ```
10
+ Requires ESLint 9 or later and Node.js 18.18+, 20.9+ or 21.1+; a CommonJS `eslint.config.cjs` needs Node.js 20.19+ or 22.12+ to `require` it. `@stylistic/eslint-plugin` is installed with the plugin.
11
+
12
+ ## Usage
13
+ ```js
14
+ // eslint.config.js
15
+ import lube from "eslint-plugin-lube"
16
+
17
+ export default [
18
+ {
19
+ ...lube.configs.recommended,
20
+ files: ["**/*.js", "**/*.ts"]
21
+ }
22
+ ]
23
+ ```
24
+ `eslint --fix` with `recommended` turns this:
25
+ ```js
26
+ import {writeFile,readFile} from 'node:fs/promises';
27
+
28
+ export async function copy(from,to){
29
+ const text=await readFile(from,'utf8');
30
+ await writeFile(to,text.replace(/\r\n/g,'\n'),{encoding:'utf8',flag:'wx',mode:0o644,flush:true});
31
+ return text.length>1000?text.length>100000?'large':'medium':'small';
32
+ }
33
+ ```
34
+ into this:
35
+ ```js
36
+ import { readFile, writeFile } from "node:fs/promises"
37
+
38
+ export async function copy(from, to) {
39
+ const text = await readFile(from, "utf8")
40
+ await writeFile(
41
+ to,
42
+ text.replace(/\r\n/g, "\n"),
43
+ { encoding: "utf8", flag: "wx", mode: 0o644, flush: true }
44
+ )
45
+ return text.length > 1000
46
+ ? text.length > 100000
47
+ ? "large"
48
+ : "medium"
49
+ : "small"
50
+ }
51
+ ```
52
+
53
+ For TypeScript files, add the parser from `@typescript-eslint/parser`:
54
+ ```js
55
+ // eslint.config.js
56
+ import tsParser from "@typescript-eslint/parser"
57
+ import lube from "eslint-plugin-lube"
58
+
59
+ export default [
60
+ {
61
+ ...lube.configs.recommended,
62
+ files: ["**/*.js", "**/*.ts"],
63
+ languageOptions: { parser: tsParser }
64
+ }
65
+ ]
66
+ ```
67
+ With `defineConfig`, extend the config by name:
68
+ ```js
69
+ // eslint.config.js
70
+ import { defineConfig } from "eslint/config"
71
+ import lube from "eslint-plugin-lube"
72
+
73
+ export default defineConfig({
74
+ extends: ["lube/recommended"],
75
+ files: ["**/*.js"],
76
+ plugins: { lube }
77
+ })
78
+ ```
79
+
80
+ ### Choosing a config
81
+ Both configs are flat config objects with `plugins` and `rules`, and differ in how much they decide for you. Start with `recommended`; take `strict` for a code base that follows the Svelte code conventions or wants every choice made for it.
82
+
83
+ **`configs.recommended`** only formats and orders, and every rule in it has a fix, so it suits format on save.
84
+ - The `@stylistic` formatting rules: tab indentation, double quotes, no semicolons, spacing and line breaks.
85
+ - `pretty-imports`, `pretty-jsdoc-casting`, `pretty-sequence` and `pretty-ternary`, with items on one line up to 80 characters.
86
+ - `ascii-order` for the names inside import and export braces only.
87
+ - A line break at the end of a file and at most one blank line, as editors write them.
88
+ - It never renames an identifier, never moves an import, key, function or test, and reports nothing about what the code does.
89
+
90
+ **`configs.strict`** is the house style of this repository, and several of its rules cannot be fixed. It is everything in `recommended` plus:
91
+ - `svelte-naming-convention`, which renames declarations to snake_case.
92
+ - `ascii-order` for import statements, object keys, function declarations and test cases too (see below).
93
+ - `pretty-sequence` and `pretty-imports` at 30 characters.
94
+ - No blank lines, no line break at the end of a file and one statement per line.
95
+ - Core rules such as `func-style` (declarations), `no-shadow`, `prefer-const`, `one-var` (never), `no-console` and `no-await-in-loop`.
96
+
97
+ In `strict`, `ascii-order` fixes import order assuming modules can run in any order, and key order assuming nothing reads it: sorted keys change `Object.keys`, `JSON.stringify` and `for...in`.
98
+ - Import a module that has to run first without names, `import "./setup.js"`, which is never moved.
99
+ - Disable the rule where key or import order matters; [ascii-order](https://github.com/artxe/lube-series/blob/master/packages/eslint-plugin-lube/docs/ascii-order.md) lists what it does not fix.
100
+
101
+ ### Changing a rule
102
+ Override a rule after the spread: `rules: { ...lube.configs.recommended.rules, "@stylistic/indent": ["error", 4] }`.
103
+ - Formatting rules go by their `@stylistic/` name.
104
+ - An indentation of your own also goes to the `indent` option of `pretty-imports`, `pretty-sequence` and `pretty-ternary`, or those rules and `@stylistic/indent` keep rewriting each other's fixes.
105
+ - `pretty-sequence` writes the items of an array, object or call one per line once they are longer than its `maxLength` together, 80 in `recommended` and 30 in `strict`: `"lube/pretty-sequence": ["error", { maxLength: 100 }]`.
106
+ - Every option of a rule is checked, so a misspelled option is a configuration error.
107
+
108
+ ## Rules
109
+ | Rule | Enforces | `recommended` |
110
+ | --- | --- | --- |
111
+ | [ascii-order](https://github.com/artxe/lube-series/blob/master/packages/eslint-plugin-lube/docs/ascii-order.md) | ASCII order of import statements, import and export names, object keys, function declarations and test cases | names only |
112
+ | [pretty-imports](https://github.com/artxe/lube-series/blob/master/packages/eslint-plugin-lube/docs/pretty-imports.md) | Import and export names on one line when they fit, or one per line | yes |
113
+ | [pretty-jsdoc-casting](https://github.com/artxe/lube-series/blob/master/packages/eslint-plugin-lube/docs/pretty-jsdoc-casting.md) | JSDoc type casts written as `/** @type {T} */(value)/**/` | yes |
114
+ | [pretty-sequence](https://github.com/artxe/lube-series/blob/master/packages/eslint-plugin-lube/docs/pretty-sequence.md) | Items of arrays, objects, calls and parameters on one line when they fit, or one per line | yes |
115
+ | [pretty-ternary](https://github.com/artxe/lube-series/blob/master/packages/eslint-plugin-lube/docs/pretty-ternary.md) | Nested and long ternaries broken before `?` and `:`, one indent deeper per level | yes |
116
+ | [svelte-naming-convention](https://github.com/artxe/lube-series/blob/master/packages/eslint-plugin-lube/docs/svelte-naming-convention.md) | snake_case declarations, following the Svelte code conventions | no |
117
+
118
+ ## What it is not
119
+ - **Not a formatter you run on its own.** There is no CLI and no config file: the rules run inside `eslint --fix`, and a file ESLint does not lint is not formatted.
120
+ - **Not a whole style guide.** `recommended` only formats and orders, and every rule it turns on has a fix. The opinions, such as renaming and the core rules, are in `strict`, which is the house style of this repository rather than a recommendation.
@@ -0,0 +1,81 @@
1
+ # ascii-order
2
+ Sorts import statements, import and export names, object keys, function declarations and test cases in ASCII order, so uppercase before lowercase. The strict config turns all five on; the recommended config only sorts names inside import and export braces, which never changes what the code does.
3
+
4
+ - **Import statements** next to each other, by module path: `"../a.js"`, `"./b.js"`, `"c"`, `"node:d"`. Side-effect imports such as `import "polyfill"` keep their place and split the imports into groups.
5
+ - **Names** in import and export braces, by the name written first: `import def, { B, a as c }`, `export { a as z, b }`.
6
+ - **Keys** of object literals, destructuring patterns, TypeScript type literals and interfaces. Spread, rest, computed keys and index signatures split the keys into groups sorted on their own. Under `exports` and `imports` of a `package.json`, where conditions match in order, `types` goes first and `default` last, and the conditions between them are in ASCII order.
7
+ - **Function declarations** next to each other in the same block, TypeScript overloads included. A function exported with `export default name` keeps its place.
8
+ - **Test cases**: `describe`, `it` and `test` calls next to each other with a string title, `it.skip` and `test.only` included.
9
+
10
+ Comments on their own lines above an item and comments after it on the same line move with it.
11
+ Nested objects, patterns and braces are sorted in the same pass.
12
+
13
+ The fix assumes three things it cannot see, and changes behavior where they do not hold:
14
+ - **Modules evaluate in any order.** Moving an import statement changes the order in which its module and the modules it imports run their top-level code. A module whose top-level code has to run first, such as a polyfill or a setup file, is imported without names, `import "./setup.js"`, which the rule never moves and never moves another import across. Disable the rule for the other imports whose order matters.
15
+ - **Key order is not observed.** Sorting keys changes the order of `Object.keys`, `Object.entries`, `JSON.stringify` and `for...in`, so an object literal serialized or iterated in a written order changes its output, and a destructuring pattern reads the properties, running their getters, in the new order. Integer-like keys such as `2` and `10` are listed in numeric order by JavaScript anyway. A key written twice keeps its last value.
16
+ - **Tests do not depend on each other.**
17
+
18
+ Where the order matters, disable the rule for that statement, `// eslint-disable-next-line lube/ascii-order`, or turn off one kind with the options below.
19
+
20
+ Beyond that, only the error is reported, without a fix, when moving would change what the code evaluates or where comments end up. The message then says why and names the value that keeps it in place, as in ``Move key "a" before "b" to keep keys in ASCII order; it is not fixed automatically because moving `f()` could change the order of side effects, so reorder it by hand``:
21
+ - An object value that calls a function, constructs an object, assigns, updates, deletes, awaits or yields would change places with another value that is not a constant or a function. A variable is a constant when it is a `const`, a namespace import (`import * as x`), or a function or class declaration that is never assigned, and the value is the variable itself, also inside an array, `!x`, `typeof x`, `x === y`, `a ? x : y` or `x ?? y`; `x.y`, `` `${x}` ``, `-x`, `x + 1` and `...x` can run code of `x`. A `let`, `var`, parameter, global or named import, which the exporting module can reassign, still counts as a variable a call may change, so `{ b: f(), a: x }` is fixed only for such a constant `x`. A `const` or class counts only where the value comes after its declaration and not inside a function declaration, which can run before it: reading it earlier throws in its temporal dead zone, and moving the read before `f()` would throw before `f()` runs. Constructing a built-in counts as reading a variable: it reads the global of the constructor, which a call may replace, so it never moves across a call, while `{ updatedAt: new Date(), createdAt: new Date() }` and `{ s: new Set([ 1 ]), m: new Map() }` are fixed: `new` of `Array`, `ArrayBuffer`, `Date`, `Map`, `RegExp`, `Set`, `WeakMap`, `WeakSet`, the typed arrays such as `Uint8Array`, and `Error` and its subclasses except `AggregateError`, when the name is not declared in the file and every argument is built only from literals, `undefined`, `NaN`, `Infinity`, templates without expressions, negative numbers, array and object literals and such constructions, and when the construction does not throw with those arguments, which the rule tries while linting: `new RegExp("(")`, `new Array(-1)`, `new Set(1)`, `new Map([ 1 ])`, `new WeakSet([ 1 ])` and `new URL("/a")` would throw before the values moved in front of them run, and are not fixed. The runtime that lints is not the one that runs the code, so `new RegExp` is fixed only with the flags `g`, `i`, `m`, `s`, `u` and `y` and the syntax of ES2018: `new RegExp("a", "v")`, the `d` flag, modifiers such as `(?i:a)` and a group name used twice may throw in an older runtime, and are not fixed. The same goes for `DataView` and `URL`, as in `new DataView(new ArrayBuffer(8))` and `new URL("a", "https://example.com")`. An `Array`, `ArrayBuffer`, typed array or `DataView` with a number, a numeric string or an object property over 65536 in its arguments, as in `new Array(1e8)`, `new ArrayBuffer(8, { maxByteLength: 1e9 })` or `new Uint8Array({ length: 1e9 })`, is not tried and not fixed, since trying it would allocate that much while linting. Two `new Date()` values may then read the clock in the other order. `new Date(x)` and `new Set(items)` can run code of `x` and `items`, and are not fixed.
22
+ - A destructuring default that is not a constant would change places with another key.
23
+ - A destructuring target is assigned by two keys, or a member such as `this.a` would change places with another key.
24
+ - A comment shares a line with two items, or a line comment would end up before a closing bracket.
25
+ - The first statement of a file has comments before it and would move.
26
+ - A statement without a semicolon would end up on a line with the next one, as in `import b from "b"; import a from "a"`.
27
+
28
+ ## options
29
+ ```js
30
+ schema: [
31
+ {
32
+ additionalProperties: false,
33
+ properties: {
34
+ checkDeclarations: { default: true, type: "boolean" },
35
+ checkImports: { default: true, type: "boolean" },
36
+ checkKeys: { default: true, type: "boolean" },
37
+ checkNames: { default: true, type: "boolean" },
38
+ checkTests: { default: true, type: "boolean" }
39
+ },
40
+ type: "object"
41
+ }
42
+ ]
43
+ ```
44
+ ### checkDeclarations
45
+ If it is `true`, it sorts function declarations.
46
+ ### checkImports
47
+ If it is `true`, it sorts import statements.
48
+ ### checkKeys
49
+ If it is `true`, it sorts object keys.
50
+ ### checkNames
51
+ If it is `true`, it sorts the names in import and export braces.
52
+ ### checkTests
53
+ If it is `true`, it sorts test cases.
54
+
55
+ ## Valid
56
+ ```js
57
+ import { A, B, a } from "a-module"
58
+ import value from "b-module"
59
+ const object = { a: 1, b: 2, ...rest, a_b: 3 }
60
+ function main() {}
61
+ function b() {}
62
+ function c() {}
63
+ export default main
64
+ it("a", () => {})
65
+ it("b", () => {})
66
+ ```
67
+
68
+ ## Invalid
69
+ ```js
70
+ import other from "b-module"
71
+ import { y, x } from "a-module"
72
+ const value = { b: 1, a: 2 }
73
+ function b() {}
74
+ function a() {}
75
+ it("b", () => {})
76
+ it("a", () => {})
77
+ // reported without a fix: g() would run before f()
78
+ const later = { b: f(), a: g() }
79
+ // fixed: constructing a built-in from literals runs no code of the file
80
+ const empty = { s: new Set([ 1 ]), m: new Map() }
81
+ ```
@@ -1,60 +1,71 @@
1
- # pretty-imports
2
- Enforces proper indentation for import and export statements.
3
-
4
- ## options
5
- ```js
6
- schema: [
7
- {
8
- properties: {
9
- checkExports: { type: "boolean", default: true },
10
- checkImports: { type: "boolean", default: true },
11
- indent: { type: "string", default: "\t" },
12
- maxLength: { type: "number", default: 30 },
13
- semicolon: { type: "boolean", default: false }
14
- },
15
- type: "object"
16
- }
17
- ]
18
- ```
19
- ### checkExports
20
- If it is `true`, it checks the export statement.
21
- ### checkImports
22
- If it is `true`, it checks the import statement.
23
- ### indent
24
- This is the character to be used for indentation.
25
- ### maxLength
26
- If the sum of the characters in the Specifier is greater than the set value, apply line breaks.
27
- ```js
28
- // If maxLength is less than or equal to 20, an error occurs.
29
- export { fff, ggg, hhh, iii, jjj, kkk, lll } from 'module/2'
30
- ```
31
- ### semicolon
32
- If it is `true`, insert a semicolon explicitly.
33
-
34
- ## Valid
35
- ```js
36
- export { a, b as c, d } from 'module'
37
- export { fff, ggg, hhh, iii, jjj, kkk, lll } from 'module/2'
38
- import {
39
- aaaaa_bbbbb,
40
- aaaaa_ccccc,
41
- aaaaa_ddddd
42
- } from "module"
43
- ```
44
-
45
- ## Invalid
46
- ```js
47
- export { a, b as c, d } from 'module';
48
- export {a, b as c, d} from 'module'
49
- export {
50
- a,
51
- b as c,
52
- d
53
- } from 'module'
54
- import { aaaaa_bbbbb, aaaaa_ccccc, aaaaa_ddddd } from "module"
55
- import {
56
- aaaaa_bbbbb,
57
- aaaaa_ccccc,
58
- aaaaa_ddddd
59
- } from "module"
1
+ # pretty-imports
2
+ Formats import and export statements: the names on one line when they fit, or one per line. The order of imports is checked by [ascii-order](ascii-order.md).
3
+
4
+ - `import type`, `export type` and import attributes are kept, and a statement containing comments is not checked.
5
+ - A statement already written over several lines is left to `@stylistic/indent`, which owns the indentation of lines this rule did not write; `fixIndent` gives that back to this rule.
6
+
7
+ ## options
8
+ ```js
9
+ schema: [
10
+ {
11
+ additionalProperties: false,
12
+ properties: {
13
+ checkExports: { default: true, type: "boolean" },
14
+ checkImports: { default: true, type: "boolean" },
15
+ fixIndent: { default: false, type: "boolean" },
16
+ indent: { default: "\t", type: "string" },
17
+ maxLength: { default: 30, type: "number" },
18
+ semicolon: { default: false, type: "boolean" }
19
+ },
20
+ type: "object"
21
+ }
22
+ ]
23
+ ```
24
+ ### checkExports
25
+ If it is `true`, it checks export statements.
26
+ ### checkImports
27
+ If it is `true`, it checks import statements.
28
+ ### fixIndent
29
+ If it is `true`, it also reports a statement whose lines differ from this rule only in their indentation. Leave it off while `@stylistic/indent` is on, or the two rules keep rewriting each other's fixes.
30
+ ### indent
31
+ The string of one indentation level. Match it to `@stylistic/indent`, or the two rules keep rewriting each other's fixes.
32
+ ### maxLength
33
+ The names are written one per line when they are longer than this together, commas and spaces not counted, a character that takes two columns counting as two.
34
+ ```js
35
+ // If maxLength is less than or equal to 20, an error occurs.
36
+ export { fff, ggg, hhh, iii, jjj, kkk, lll } from 'module/2'
37
+ ```
38
+ ### semicolon
39
+ If it is `true`, insert a semicolon explicitly.
40
+ A semicolon that separates the statement from the next one on the same line is kept either way, and so is one that starts the next line, as `@stylistic/semi-style` writes it.
41
+
42
+ ## Valid
43
+ ```js
44
+ export { a, b as c, d } from 'module'
45
+ export { fff, ggg, hhh, iii, jjj, kkk, lll } from 'module/2'
46
+ import {
47
+ aaaaa_bbbbb,
48
+ aaaaa_ccccc,
49
+ aaaaa_ddddd
50
+ } from "module"
51
+ import def, { a, b } from "module/2"
52
+ ```
53
+
54
+ ## Invalid
55
+ ```js
56
+ export { a, b as c, d } from 'module';
57
+ export {e, f as g, h} from 'module'
58
+ export {
59
+ i,
60
+ j as k,
61
+ l
62
+ } from 'module'
63
+ import { aaaaa_bbbbb, aaaaa_ccccc, aaaaa_ddddd } from "module"
64
+ import def, {m, n} from "module/2"
65
+ // only with fixIndent: true
66
+ import {
67
+ aaaaa_eeeee,
68
+ aaaaa_fffff,
69
+ aaaaa_ggggg
70
+ } from "module"
60
71
  ```