Skip to content

Commit 236fec2

Browse files
committed
feat: wrapIndent option; fixes #715
BREAKING CHANGE: Will strip indents by default; set `wrapIndent` option to a whitespace string (e.g., of 2 spaces) to set the indent you wish after wrapping
1 parent f420121 commit 236fec2

File tree

5 files changed

+453
-35
lines changed

5 files changed

+453
-35
lines changed

.README/rules/check-line-alignment.md

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,16 @@ for example.
99
This rule allows one optional string argument. If it is `"always"` then a
1010
problem is raised when the lines are not aligned. If it is `"never"` then
1111
a problem should be raised when there is more than one space between each
12-
line's parts. Defaults to `"never"`.
12+
line's parts. If it is `"any"`, no alignment is made. Defaults to `"never"`.
1313

14-
Note that in addition to alignment, both options will ensure at least one
15-
space is present after the asterisk delimiter.
14+
Note that in addition to alignment, the "never" and "always" options will both
15+
ensure that at least one space is present after the asterisk delimiter.
1616

1717
After the string, an options object is allowed with the following properties.
1818

1919
##### `tags`
2020

21-
Use this to change the tags which are sought for alignment changes. *Currently*
22-
*only works with the "never" option.* Defaults to an array of
21+
Use this to change the tags which are sought for alignment changes. Defaults to an array of
2322
`['param', 'arg', 'argument', 'property', 'prop', 'returns', 'return']`.
2423

2524
##### `customSpacings`
@@ -34,10 +33,20 @@ An object with any of the following keys set to an integer. Affects spacing:
3433

3534
If a spacing is not defined, it defaults to one.
3635

36+
##### `preserveMainDescriptionPostDelimiter`
37+
38+
A boolean to determine whether to preserve the post-delimiter spacing of the
39+
main description. If `false` or unset, will be set to a single space.
40+
41+
##### `wrapIndent`
42+
43+
The indent that will be applied for tag text after the first line.
44+
Default to the empty string (no indent).
45+
3746
|||
3847
|---|---|
3948
|Context|everywhere|
40-
|Options|(a string matching `"always" or "never"` and optional object with `tags` and `customSpacings`)|
49+
|Options|(a string matching `"always"`, `"never"`, or `"any"` and optional object with `tags`, `customSpacings`, `preserveMainDescriptionPostDelimiter`, and `wrapIndent`)|
4150
|Tags|`param`, `property`, `returns` and others added by `tags`|
4251
|Aliases|`arg`, `argument`, `prop`, `return`|
4352
|Recommended|false|

README.md

Lines changed: 114 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2031,19 +2031,18 @@ for example.
20312031
This rule allows one optional string argument. If it is `"always"` then a
20322032
problem is raised when the lines are not aligned. If it is `"never"` then
20332033
a problem should be raised when there is more than one space between each
2034-
line's parts. Defaults to `"never"`.
2034+
line's parts. If it is `"any"`, no alignment is made. Defaults to `"never"`.
20352035

2036-
Note that in addition to alignment, both options will ensure at least one
2037-
space is present after the asterisk delimiter.
2036+
Note that in addition to alignment, the "never" and "always" options will both
2037+
ensure that at least one space is present after the asterisk delimiter.
20382038

20392039
After the string, an options object is allowed with the following properties.
20402040

20412041
<a name="user-content-eslint-plugin-jsdoc-rules-check-line-alignment-options-3-tags"></a>
20422042
<a name="eslint-plugin-jsdoc-rules-check-line-alignment-options-3-tags"></a>
20432043
##### <code>tags</code>
20442044

2045-
Use this to change the tags which are sought for alignment changes. *Currently*
2046-
*only works with the "never" option.* Defaults to an array of
2045+
Use this to change the tags which are sought for alignment changes. Defaults to an array of
20472046
`['param', 'arg', 'argument', 'property', 'prop', 'returns', 'return']`.
20482047

20492048
<a name="user-content-eslint-plugin-jsdoc-rules-check-line-alignment-options-3-customspacings"></a>
@@ -2060,10 +2059,24 @@ An object with any of the following keys set to an integer. Affects spacing:
20602059

20612060
If a spacing is not defined, it defaults to one.
20622061

2062+
<a name="user-content-eslint-plugin-jsdoc-rules-check-line-alignment-options-3-preservemaindescriptionpostdelimiter"></a>
2063+
<a name="eslint-plugin-jsdoc-rules-check-line-alignment-options-3-preservemaindescriptionpostdelimiter"></a>
2064+
##### <code>preserveMainDescriptionPostDelimiter</code>
2065+
2066+
A boolean to determine whether to preserve the post-delimiter spacing of the
2067+
main description. If `false` or unset, will be set to a single space.
2068+
2069+
<a name="user-content-eslint-plugin-jsdoc-rules-check-line-alignment-options-3-wrapindent"></a>
2070+
<a name="eslint-plugin-jsdoc-rules-check-line-alignment-options-3-wrapindent"></a>
2071+
##### <code>wrapIndent</code>
2072+
2073+
The indent that will be applied for tag text after the first line.
2074+
Default to the empty string (no indent).
2075+
20632076
|||
20642077
|---|---|
20652078
|Context|everywhere|
2066-
|Options|(a string matching `"always" or "never"` and optional object with `tags` and `customSpacings`)|
2079+
|Options|(a string matching `"always"`, `"never"`, or `"any"` and optional object with `tags`, `customSpacings`, `preserveMainDescriptionPostDelimiter`, and `wrapIndent`)|
20672080
|Tags|`param`, `property`, `returns` and others added by `tags`|
20682081
|Aliases|`arg`, `argument`, `prop`, `return`|
20692082
|Recommended|false|
@@ -2508,6 +2521,53 @@ const fn = ( lorem, sit ) => {}
25082521
const fn = ( lorem, sit ) => {}
25092522
// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"customSpacings":{"postHyphen":2}}]
25102523
// Message: Expected JSDoc block lines to not be aligned.
2524+
2525+
/**
2526+
* @param {string} lorem Description
2527+
* with multiple lines.
2528+
*/
2529+
function quux () {
2530+
}
2531+
// "jsdoc/check-line-alignment": ["error"|"warn", "any",{"wrapIndent":" "}]
2532+
// Message: Expected wrap indent
2533+
2534+
/**
2535+
* Function description.
2536+
*
2537+
* @param {string} lorem Description.
2538+
* @param {int} sit Description multi
2539+
* line with asterisks.
2540+
*/
2541+
const fn = ( lorem, sit ) => {}
2542+
// "jsdoc/check-line-alignment": ["error"|"warn", "always",{"wrapIndent":" "}]
2543+
// Message: Expected JSDoc block lines to be aligned.
2544+
2545+
/**
2546+
* My function.
2547+
*
2548+
* @param {string} lorem Description.
2549+
* @param {int} sit Description multiple
2550+
* lines.
2551+
*/
2552+
const fn = ( lorem, sit ) => {}
2553+
// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"wrapIndent":" "}]
2554+
// Message: Expected JSDoc block lines to not be aligned.
2555+
2556+
/**
2557+
* @property {boolean} tls_verify_client_certificate - Whether our API should
2558+
* enable TLS client authentication
2559+
*/
2560+
function quux () {}
2561+
// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"wrapIndent":" "}]
2562+
// Message: Expected wrap indent
2563+
2564+
/**
2565+
* @property {boolean} tls_verify_client_certificate - Whether our API should
2566+
* enable TLS client authentication
2567+
*/
2568+
function quux () {}
2569+
// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"wrapIndent":""}]
2570+
// Message: Expected wrap indent
25112571
````
25122572

25132573
The following patterns are not considered problems:
@@ -2865,11 +2925,59 @@ const fn = ( lorem, sit ) => {};
28652925
const fn = ( a, b ) => {};
28662926
// "jsdoc/check-line-alignment": ["error"|"warn", "always"]
28672927

2928+
/**
2929+
* @param {string} lorem Description
2930+
* with multiple lines.
2931+
*/
2932+
function quux () {
2933+
}
2934+
// "jsdoc/check-line-alignment": ["error"|"warn", "any",{"wrapIndent":" "}]
2935+
2936+
/**
2937+
* @param {string} lorem Description
2938+
* with multiple lines.
2939+
*/
2940+
function quux () {
2941+
}
2942+
// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"wrapIndent":" "}]
2943+
2944+
/**
2945+
* Function description.
2946+
*
2947+
* @param {string} lorem Description.
2948+
* @param {int} sit Description multi
2949+
* line with asterisks.
2950+
*/
2951+
const fn = ( lorem, sit ) => {}
2952+
// "jsdoc/check-line-alignment": ["error"|"warn", "always",{"wrapIndent":" "}]
2953+
2954+
/**
2955+
* Function description.
2956+
*
2957+
* @param {string} lorem Description.
2958+
* @param {int} sit Description multi
2959+
* line with
2960+
* asterisks.
2961+
*/
2962+
const fn = ( lorem, sit ) => {}
2963+
// "jsdoc/check-line-alignment": ["error"|"warn", "always",{"wrapIndent":" "}]
2964+
2965+
/**
2966+
* @param {
2967+
* string | number
2968+
* } lorem Description
2969+
* with multiple lines.
2970+
*/
2971+
function quux () {
2972+
}
2973+
// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"wrapIndent":" "}]
2974+
28682975
/**
28692976
* @param {string|string[]|TemplateResult|TemplateResult[]} event.detail.description -
28702977
* Notification description
28712978
*/
28722979
function quux () {}
2980+
// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"wrapIndent":" "}]
28732981
````
28742982

28752983

src/alignTransform.js

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ const alignTransform = ({
104104
tags,
105105
indent,
106106
preserveMainDescriptionPostDelimiter,
107+
wrapIndent,
107108
}) => {
108109
let intoTags = false;
109110
let width;
@@ -180,10 +181,11 @@ const alignTransform = ({
180181
return tokens;
181182
};
182183

183-
const update = (line, index, source, typelessInfo) => {
184+
const update = (line, index, source, typelessInfo, indentTag) => {
184185
const tokens = {
185186
...line.tokens,
186187
};
188+
187189
if (tokens.tag !== '') {
188190
intoTags = true;
189191
}
@@ -204,21 +206,19 @@ const alignTransform = ({
204206
};
205207
}
206208

207-
/* eslint-disable indent */
208209
switch (tokens.delimiter) {
209-
case Markers.start:
210-
tokens.start = indent;
211-
break;
212-
case Markers.delim:
213-
tokens.start = indent + ' ';
214-
break;
215-
default:
216-
tokens.delimiter = '';
217-
218-
// compensate delimiter
219-
tokens.start = indent + ' ';
210+
case Markers.start:
211+
tokens.start = indent;
212+
break;
213+
case Markers.delim:
214+
tokens.start = indent + ' ';
215+
break;
216+
default:
217+
tokens.delimiter = '';
218+
219+
// compensate delimiter
220+
tokens.start = indent + ' ';
220221
}
221-
/* eslint-enable */
222222

223223
if (!intoTags) {
224224
if (tokens.description === '') {
@@ -240,16 +240,16 @@ const alignTransform = ({
240240
);
241241

242242
// Not align.
243-
if (!shouldAlign(tags, index, source)) {
244-
return {
245-
...line,
246-
tokens,
247-
};
243+
if (shouldAlign(tags, index, source)) {
244+
alignTokens(tokens, typelessInfo);
245+
if (indentTag) {
246+
tokens.postDelimiter += wrapIndent;
247+
}
248248
}
249249

250250
return {
251251
...line,
252-
tokens: alignTokens(tokens, typelessInfo),
252+
tokens,
253253
};
254254
};
255255

@@ -263,10 +263,19 @@ const alignTransform = ({
263263

264264
const typelessInfo = getTypelessInfo(fields);
265265

266+
let tagIndentMode = false;
267+
266268
return rewireSource({
267269
...fields,
268270
source: source.map((line, index) => {
269-
return update(line, index, source, typelessInfo);
271+
const indentTag = tagIndentMode && !line.tokens.tag && line.tokens.description;
272+
const ret = update(line, index, source, typelessInfo, indentTag);
273+
274+
if (line.tokens.tag) {
275+
tagIndentMode = true;
276+
}
277+
278+
return ret;
270279
}),
271280
});
272281
};

src/rules/checkLineAlignment.js

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,15 @@ const checkAlignment = ({
137137
report,
138138
tags,
139139
utils,
140+
wrapIndent,
140141
}) => {
141142
const transform = commentFlow(
142143
alignTransform({
143144
customSpacings,
144145
indent,
145146
preserveMainDescriptionPostDelimiter,
146147
tags,
148+
wrapIndent,
147149
}),
148150
);
149151
const transformedJsdoc = transform(jsdoc);
@@ -176,6 +178,7 @@ export default iterateJsdoc(({
176178
],
177179
preserveMainDescriptionPostDelimiter,
178180
customSpacings,
181+
wrapIndent = '',
179182
} = context.options[1] || {};
180183

181184
if (context.options[0] === 'always') {
@@ -193,14 +196,48 @@ export default iterateJsdoc(({
193196
report,
194197
tags: applicableTags,
195198
utils,
199+
wrapIndent,
196200
});
197201

198202
return;
199203
}
200204

201205
const foundTags = utils.getPresentTags(applicableTags);
206+
if (context.options[0] !== 'any') {
207+
for (const tag of foundTags) {
208+
checkNotAlignedPerTag(utils, tag, customSpacings);
209+
}
210+
}
211+
202212
for (const tag of foundTags) {
203-
checkNotAlignedPerTag(utils, tag, customSpacings);
213+
if (tag.source.length > 1) {
214+
let idx = 0;
215+
for (const {
216+
tokens,
217+
// Avoid the tag line
218+
} of tag.source.slice(1)) {
219+
idx++;
220+
221+
if (
222+
!tokens.description ||
223+
// Avoid first lines after multiline type
224+
tokens.type ||
225+
tokens.name
226+
) {
227+
continue;
228+
}
229+
230+
// Don't include a single separating space/tab
231+
if (tokens.postDelimiter.slice(1) !== wrapIndent) {
232+
utils.reportJSDoc('Expected wrap indent', {
233+
line: tag.source[0].number + idx,
234+
}, () => {
235+
tokens.postDelimiter = tokens.postDelimiter.charAt() + wrapIndent;
236+
});
237+
return;
238+
}
239+
}
240+
}
204241
}
205242
}, {
206243
iterateAllJsdocs: true,
@@ -213,7 +250,7 @@ export default iterateJsdoc(({
213250
schema: [
214251
{
215252
enum: [
216-
'always', 'never',
253+
'always', 'never', 'any',
217254
],
218255
type: 'string',
219256
},
@@ -250,6 +287,9 @@ export default iterateJsdoc(({
250287
},
251288
type: 'array',
252289
},
290+
wrapIndent: {
291+
type: 'string',
292+
},
253293
},
254294
type: 'object',
255295
},

0 commit comments

Comments
 (0)