Skip to content

Commit

Permalink
feat: wrapIndent option; fixes #715
Browse files Browse the repository at this point in the history
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
  • Loading branch information
brettz9 committed Feb 11, 2023
1 parent f420121 commit 236fec2
Show file tree
Hide file tree
Showing 5 changed files with 453 additions and 35 deletions.
21 changes: 15 additions & 6 deletions .README/rules/check-line-alignment.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,16 @@ for example.
This rule allows one optional string argument. If it is `"always"` then a
problem is raised when the lines are not aligned. If it is `"never"` then
a problem should be raised when there is more than one space between each
line's parts. Defaults to `"never"`.
line's parts. If it is `"any"`, no alignment is made. Defaults to `"never"`.

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

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

##### `tags`

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

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

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

##### `preserveMainDescriptionPostDelimiter`

A boolean to determine whether to preserve the post-delimiter spacing of the
main description. If `false` or unset, will be set to a single space.

##### `wrapIndent`

The indent that will be applied for tag text after the first line.
Default to the empty string (no indent).

|||
|---|---|
|Context|everywhere|
|Options|(a string matching `"always" or "never"` and optional object with `tags` and `customSpacings`)|
|Options|(a string matching `"always"`, `"never"`, or `"any"` and optional object with `tags`, `customSpacings`, `preserveMainDescriptionPostDelimiter`, and `wrapIndent`)|
|Tags|`param`, `property`, `returns` and others added by `tags`|
|Aliases|`arg`, `argument`, `prop`, `return`|
|Recommended|false|
Expand Down
120 changes: 114 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2031,19 +2031,18 @@ for example.
This rule allows one optional string argument. If it is `"always"` then a
problem is raised when the lines are not aligned. If it is `"never"` then
a problem should be raised when there is more than one space between each
line's parts. Defaults to `"never"`.
line's parts. If it is `"any"`, no alignment is made. Defaults to `"never"`.

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

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

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

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

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

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

<a name="user-content-eslint-plugin-jsdoc-rules-check-line-alignment-options-3-preservemaindescriptionpostdelimiter"></a>
<a name="eslint-plugin-jsdoc-rules-check-line-alignment-options-3-preservemaindescriptionpostdelimiter"></a>
##### <code>preserveMainDescriptionPostDelimiter</code>

A boolean to determine whether to preserve the post-delimiter spacing of the
main description. If `false` or unset, will be set to a single space.

<a name="user-content-eslint-plugin-jsdoc-rules-check-line-alignment-options-3-wrapindent"></a>
<a name="eslint-plugin-jsdoc-rules-check-line-alignment-options-3-wrapindent"></a>
##### <code>wrapIndent</code>

The indent that will be applied for tag text after the first line.
Default to the empty string (no indent).

|||
|---|---|
|Context|everywhere|
|Options|(a string matching `"always" or "never"` and optional object with `tags` and `customSpacings`)|
|Options|(a string matching `"always"`, `"never"`, or `"any"` and optional object with `tags`, `customSpacings`, `preserveMainDescriptionPostDelimiter`, and `wrapIndent`)|
|Tags|`param`, `property`, `returns` and others added by `tags`|
|Aliases|`arg`, `argument`, `prop`, `return`|
|Recommended|false|
Expand Down Expand Up @@ -2508,6 +2521,53 @@ const fn = ( lorem, sit ) => {}
const fn = ( lorem, sit ) => {}
// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"customSpacings":{"postHyphen":2}}]
// Message: Expected JSDoc block lines to not be aligned.

/**
* @param {string} lorem Description
* with multiple lines.
*/
function quux () {
}
// "jsdoc/check-line-alignment": ["error"|"warn", "any",{"wrapIndent":" "}]
// Message: Expected wrap indent

/**
* Function description.
*
* @param {string} lorem Description.
* @param {int} sit Description multi
* line with asterisks.
*/
const fn = ( lorem, sit ) => {}
// "jsdoc/check-line-alignment": ["error"|"warn", "always",{"wrapIndent":" "}]
// Message: Expected JSDoc block lines to be aligned.

/**
* My function.
*
* @param {string} lorem Description.
* @param {int} sit Description multiple
* lines.
*/
const fn = ( lorem, sit ) => {}
// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"wrapIndent":" "}]
// Message: Expected JSDoc block lines to not be aligned.

/**
* @property {boolean} tls_verify_client_certificate - Whether our API should
* enable TLS client authentication
*/
function quux () {}
// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"wrapIndent":" "}]
// Message: Expected wrap indent

/**
* @property {boolean} tls_verify_client_certificate - Whether our API should
* enable TLS client authentication
*/
function quux () {}
// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"wrapIndent":""}]
// Message: Expected wrap indent
````

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

/**
* @param {string} lorem Description
* with multiple lines.
*/
function quux () {
}
// "jsdoc/check-line-alignment": ["error"|"warn", "any",{"wrapIndent":" "}]

/**
* @param {string} lorem Description
* with multiple lines.
*/
function quux () {
}
// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"wrapIndent":" "}]

/**
* Function description.
*
* @param {string} lorem Description.
* @param {int} sit Description multi
* line with asterisks.
*/
const fn = ( lorem, sit ) => {}
// "jsdoc/check-line-alignment": ["error"|"warn", "always",{"wrapIndent":" "}]

/**
* Function description.
*
* @param {string} lorem Description.
* @param {int} sit Description multi
* line with
* asterisks.
*/
const fn = ( lorem, sit ) => {}
// "jsdoc/check-line-alignment": ["error"|"warn", "always",{"wrapIndent":" "}]

/**
* @param {
* string | number
* } lorem Description
* with multiple lines.
*/
function quux () {
}
// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"wrapIndent":" "}]

/**
* @param {string|string[]|TemplateResult|TemplateResult[]} event.detail.description -
* Notification description
*/
function quux () {}
// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"wrapIndent":" "}]
````


Expand Down
51 changes: 30 additions & 21 deletions src/alignTransform.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ const alignTransform = ({
tags,
indent,
preserveMainDescriptionPostDelimiter,
wrapIndent,
}) => {
let intoTags = false;
let width;
Expand Down Expand Up @@ -180,10 +181,11 @@ const alignTransform = ({
return tokens;
};

const update = (line, index, source, typelessInfo) => {
const update = (line, index, source, typelessInfo, indentTag) => {
const tokens = {
...line.tokens,
};

if (tokens.tag !== '') {
intoTags = true;
}
Expand All @@ -204,21 +206,19 @@ const alignTransform = ({
};
}

/* eslint-disable indent */
switch (tokens.delimiter) {
case Markers.start:
tokens.start = indent;
break;
case Markers.delim:
tokens.start = indent + ' ';
break;
default:
tokens.delimiter = '';

// compensate delimiter
tokens.start = indent + ' ';
case Markers.start:
tokens.start = indent;
break;
case Markers.delim:
tokens.start = indent + ' ';
break;
default:
tokens.delimiter = '';

// compensate delimiter
tokens.start = indent + ' ';
}
/* eslint-enable */

if (!intoTags) {
if (tokens.description === '') {
Expand All @@ -240,16 +240,16 @@ const alignTransform = ({
);

// Not align.
if (!shouldAlign(tags, index, source)) {
return {
...line,
tokens,
};
if (shouldAlign(tags, index, source)) {
alignTokens(tokens, typelessInfo);
if (indentTag) {
tokens.postDelimiter += wrapIndent;
}
}

return {
...line,
tokens: alignTokens(tokens, typelessInfo),
tokens,
};
};

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

const typelessInfo = getTypelessInfo(fields);

let tagIndentMode = false;

return rewireSource({
...fields,
source: source.map((line, index) => {
return update(line, index, source, typelessInfo);
const indentTag = tagIndentMode && !line.tokens.tag && line.tokens.description;
const ret = update(line, index, source, typelessInfo, indentTag);

if (line.tokens.tag) {
tagIndentMode = true;
}

return ret;
}),
});
};
Expand Down
44 changes: 42 additions & 2 deletions src/rules/checkLineAlignment.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,15 @@ const checkAlignment = ({
report,
tags,
utils,
wrapIndent,
}) => {
const transform = commentFlow(
alignTransform({
customSpacings,
indent,
preserveMainDescriptionPostDelimiter,
tags,
wrapIndent,
}),
);
const transformedJsdoc = transform(jsdoc);
Expand Down Expand Up @@ -176,6 +178,7 @@ export default iterateJsdoc(({
],
preserveMainDescriptionPostDelimiter,
customSpacings,
wrapIndent = '',
} = context.options[1] || {};

if (context.options[0] === 'always') {
Expand All @@ -193,14 +196,48 @@ export default iterateJsdoc(({
report,
tags: applicableTags,
utils,
wrapIndent,
});

return;
}

const foundTags = utils.getPresentTags(applicableTags);
if (context.options[0] !== 'any') {
for (const tag of foundTags) {
checkNotAlignedPerTag(utils, tag, customSpacings);
}
}

for (const tag of foundTags) {
checkNotAlignedPerTag(utils, tag, customSpacings);
if (tag.source.length > 1) {
let idx = 0;
for (const {
tokens,
// Avoid the tag line
} of tag.source.slice(1)) {
idx++;

if (
!tokens.description ||
// Avoid first lines after multiline type
tokens.type ||
tokens.name
) {
continue;
}

// Don't include a single separating space/tab
if (tokens.postDelimiter.slice(1) !== wrapIndent) {
utils.reportJSDoc('Expected wrap indent', {
line: tag.source[0].number + idx,
}, () => {
tokens.postDelimiter = tokens.postDelimiter.charAt() + wrapIndent;
});
return;
}
}
}
}
}, {
iterateAllJsdocs: true,
Expand All @@ -213,7 +250,7 @@ export default iterateJsdoc(({
schema: [
{
enum: [
'always', 'never',
'always', 'never', 'any',
],
type: 'string',
},
Expand Down Expand Up @@ -250,6 +287,9 @@ export default iterateJsdoc(({
},
type: 'array',
},
wrapIndent: {
type: 'string',
},
},
type: 'object',
},
Expand Down
Loading

0 comments on commit 236fec2

Please sign in to comment.