remark-lint rule to warn when lines are too long
npx @tessl/cli install tessl/npm-remark-lint-maximum-line-length@4.1.00
# remark-lint-maximum-line-length
1
2
remark-lint-maximum-line-length is a specialized lint rule for the unified/remark ecosystem that validates maximum line length in Markdown documents. It intelligently handles various Markdown constructs by ignoring non-wrappable elements and provides detailed error reporting with precise character counts and removal suggestions.
3
4
## Package Information
5
6
- **Package Name**: remark-lint-maximum-line-length
7
- **Package Type**: npm
8
- **Language**: JavaScript (ES Modules)
9
- **Installation**: `npm install remark-lint-maximum-line-length`
10
- **Dependencies**: `pluralize`, `mdast-util-mdx`, `unified-lint-rule`, `unist-util-position`, `unist-util-visit`
11
12
## Core Imports
13
14
```javascript
15
import remarkLintMaximumLineLength from 'remark-lint-maximum-line-length';
16
```
17
18
For use with the unified processor:
19
20
```javascript
21
import remarkLint from 'remark-lint';
22
import remarkLintMaximumLineLength from 'remark-lint-maximum-line-length';
23
import remarkParse from 'remark-parse';
24
import remarkStringify from 'remark-stringify';
25
import { unified } from 'unified';
26
```
27
28
## Basic Usage
29
30
```javascript
31
import remarkLint from 'remark-lint';
32
import remarkLintMaximumLineLength from 'remark-lint-maximum-line-length';
33
import remarkParse from 'remark-parse';
34
import remarkStringify from 'remark-stringify';
35
import { read } from 'to-vfile';
36
import { unified } from 'unified';
37
import { reporter } from 'vfile-reporter';
38
39
const file = await read('example.md');
40
41
await unified()
42
.use(remarkParse)
43
.use(remarkLint)
44
.use(remarkLintMaximumLineLength) // Default: 60 characters
45
.use(remarkStringify)
46
.process(file);
47
48
console.error(reporter(file));
49
```
50
51
With custom configuration:
52
53
```javascript
54
// Configure maximum line length to 120 characters
55
await unified()
56
.use(remarkParse)
57
.use(remarkLint)
58
.use(remarkLintMaximumLineLength, 120)
59
.use(remarkStringify)
60
.process(file);
61
62
// Configure with options object
63
await unified()
64
.use(remarkParse)
65
.use(remarkLint)
66
.use(remarkLintMaximumLineLength, {
67
size: 100,
68
stringLength: (value) => value.length // Custom length calculation
69
})
70
.use(remarkStringify)
71
.process(file);
72
```
73
74
## Architecture
75
76
The lint rule follows the unified ecosystem patterns:
77
78
- **Lint Rule Integration**: Built with `unified-lint-rule` framework for seamless integration
79
- **AST Processing**: Uses mdast (Markdown Abstract Syntax Tree) for intelligent content analysis
80
- **Smart Ignoring**: Automatically excludes non-wrappable content (code blocks, HTML, headings, tables, definitions, math, MDX)
81
- **Inline Element Handling**: Special logic for inline code, images, and links that span across line boundaries
82
- **Error Reporting**: Leverages unified's VFile messaging system for detailed diagnostics
83
84
## Capabilities
85
86
### Line Length Validation
87
88
Validates that lines in Markdown documents don't exceed a specified character limit with intelligent content-aware processing.
89
90
```javascript { .api }
91
/**
92
* remark-lint rule to warn when lines are too long
93
* @param options - Configuration options (number or Options object)
94
* @returns Transform function for unified processor
95
*/
96
function remarkLintMaximumLineLength(
97
options?: Options | number
98
): Transformer<Root, Root>;
99
```
100
101
**Parameters:**
102
- `options` (Options | number, optional): Configuration options (default: 60)
103
104
**Behavior:**
105
- Ignores non-wrappable elements: code blocks, HTML, headings, tables, definitions, math expressions, MDX
106
- Handles inline elements (code, images, links) that cross line boundaries intelligently
107
- Reports violations with exact character counts and removal suggestions
108
- Supports custom string length calculation functions
109
110
### Configuration Options
111
112
Configure the maximum line length and string measurement behavior.
113
114
```javascript { .api }
115
/**
116
* Configuration options for line length validation
117
*/
118
interface Options {
119
/**
120
* Preferred maximum line length in characters
121
* @default 60
122
*/
123
size?: number;
124
125
/**
126
* Custom function to calculate string length
127
* Useful for Unicode handling or visual width calculation
128
* @param value - The string to measure
129
* @returns The calculated length
130
*/
131
stringLength?: (value: string) => number;
132
}
133
```
134
135
**Usage Examples:**
136
137
Simple numeric configuration:
138
```javascript
139
// Set maximum line length to 120 characters
140
.use(remarkLintMaximumLineLength, 120)
141
```
142
143
Options object configuration:
144
```javascript
145
// Advanced configuration with custom string length function
146
.use(remarkLintMaximumLineLength, {
147
size: 100,
148
stringLength: (value) => {
149
// Example: Use visual width for CJK characters
150
return Array.from(value).length;
151
}
152
})
153
```
154
155
### Error Messages
156
157
The rule generates detailed error messages for lines that exceed the maximum length.
158
159
**Error Message Format:**
160
```
161
Unexpected `{actualLength}` character line, expected at most `{maxLength}` characters, remove `{difference}` character{s}
162
```
163
164
**Example Output:**
165
```
166
1:24: Unexpected `23` character line, expected at most `20` characters, remove `3` characters
167
4:37: Unexpected `36` character line, expected at most `20` characters, remove `16` characters
168
```
169
170
### Smart Content Handling
171
172
The rule intelligently handles different Markdown constructs:
173
174
**Ignored Elements (Non-wrappable):**
175
- Code blocks (fenced and indented)
176
- HTML elements
177
- Headings
178
- Tables
179
- Definitions/reference links
180
- Math expressions (with remark-math)
181
- MDX elements: `mdxjsEsm`, `mdxFlowExpression`, `mdxTextExpression` (with remark-mdx)
182
- YAML/TOML frontmatter
183
184
**Special Handling (Inline Elements):**
185
- Inline code spans
186
- Images
187
- Links and autolinks
188
189
These elements are allowed to exceed the line limit when they:
190
1. Start before the maximum column and end after it
191
2. Contain no internal whitespace
192
3. Don't have following content with break opportunities on the same line
193
194
## Types
195
196
```javascript { .api }
197
/**
198
* Root node type from mdast
199
*/
200
interface Root {
201
type: 'root';
202
children: Array<Content>;
203
}
204
205
/**
206
* Transformer function type from unified
207
*/
208
type Transformer<In, Out> = (tree: In, file: VFile) => Out | undefined | void;
209
210
/**
211
* Virtual file type from unified ecosystem
212
*/
213
interface VFile {
214
// Core VFile properties and methods
215
message(reason: string, position?: Position): VFileMessage;
216
fail(reason: string, position?: Position): never;
217
}
218
219
/**
220
* Position information for error reporting
221
*/
222
interface Position {
223
line: number;
224
column: number;
225
offset?: number;
226
}
227
```
228
229
## Integration Examples
230
231
### CLI Usage
232
233
```bash
234
# Basic usage with remark CLI
235
remark --frail --use remark-lint --use remark-lint-maximum-line-length .
236
237
# With custom configuration in package.json
238
{
239
"remarkConfig": {
240
"plugins": [
241
"remark-lint",
242
["remark-lint-maximum-line-length", 120]
243
]
244
}
245
}
246
```
247
248
### Programmatic Usage with Configuration
249
250
```javascript
251
import { unified } from 'unified';
252
import remarkParse from 'remark-parse';
253
import remarkLint from 'remark-lint';
254
import remarkLintMaximumLineLength from 'remark-lint-maximum-line-length';
255
import { read } from 'to-vfile';
256
import { reporter } from 'vfile-reporter';
257
258
// Process multiple files with different configurations
259
const files = ['README.md', 'CHANGELOG.md', 'docs/api.md'];
260
261
for (const filePath of files) {
262
const file = await read(filePath);
263
264
const processor = unified()
265
.use(remarkParse)
266
.use(remarkLint)
267
.use(remarkLintMaximumLineLength, {
268
size: filePath.includes('CHANGELOG') ? 120 : 60,
269
stringLength: (value) => {
270
// Custom logic for different file types
271
return Array.from(value).length;
272
}
273
});
274
275
await processor.process(file);
276
277
if (file.messages.length > 0) {
278
console.error(`Issues in ${filePath}:`);
279
console.error(reporter(file));
280
}
281
}
282
```
283
284
### Integration with Other remark-lint Rules
285
286
```javascript
287
import { unified } from 'unified';
288
import remarkParse from 'remark-parse';
289
import remarkLint from 'remark-lint';
290
import remarkLintMaximumLineLength from 'remark-lint-maximum-line-length';
291
import remarkLintNoHeadingPunctuation from 'remark-lint-no-heading-punctuation';
292
import remarkLintListItemIndent from 'remark-lint-list-item-indent';
293
294
const processor = unified()
295
.use(remarkParse)
296
.use(remarkLint)
297
.use(remarkLintMaximumLineLength, {
298
size: 100,
299
stringLength: (line) => {
300
// Account for tab characters as 4 spaces
301
return line.replace(/\t/g, ' ').length;
302
}
303
})
304
.use(remarkLintNoHeadingPunctuation)
305
.use(remarkLintListItemIndent, 'space');
306
```