diff options
Diffstat (limited to 'tools/node_modules/eslint/node_modules/eslint-plugin-jsdoc/dist/rules/sortTags.js')
-rw-r--r-- | tools/node_modules/eslint/node_modules/eslint-plugin-jsdoc/dist/rules/sortTags.js | 257 |
1 files changed, 249 insertions, 8 deletions
diff --git a/tools/node_modules/eslint/node_modules/eslint-plugin-jsdoc/dist/rules/sortTags.js b/tools/node_modules/eslint/node_modules/eslint-plugin-jsdoc/dist/rules/sortTags.js index cb4c63f088..4c81206200 100644 --- a/tools/node_modules/eslint/node_modules/eslint-plugin-jsdoc/dist/rules/sortTags.js +++ b/tools/node_modules/eslint/node_modules/eslint-plugin-jsdoc/dist/rules/sortTags.js @@ -7,17 +7,25 @@ exports.default = void 0; var _defaultTagOrder = _interopRequireDefault(require("../defaultTagOrder")); var _iterateJsdoc = _interopRequireDefault(require("../iterateJsdoc")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +// eslint-disable-next-line complexity -- Temporary var _default = (0, _iterateJsdoc.default)(({ context, jsdoc, utils }) => { const { + linesBetween = 1, tagSequence = _defaultTagOrder.default, - alphabetizeExtras = false + alphabetizeExtras = false, + reportTagGroupSpacing = true, + reportIntraTagGroupSpacing = true } = context.options[0] || {}; - const otherPos = tagSequence.indexOf('-other'); - const endPos = otherPos > -1 ? otherPos : tagSequence.length; + const tagList = tagSequence.flatMap(obj => { + /* typeof obj === 'string' ? obj : */ + return obj.tags; + }); + const otherPos = tagList.indexOf('-other'); + const endPos = otherPos > -1 ? otherPos : tagList.length; let ongoingCount = 0; for (const [idx, tag] of jsdoc.tags.entries()) { tag.originalIndex = idx; @@ -44,8 +52,8 @@ var _default = (0, _iterateJsdoc.default)(({ firstChangedTagIndex = originalIndex; } }; - const newPos = tagSequence.indexOf(tagNew); - const oldPos = tagSequence.indexOf(tagOld); + const newPos = tagList.indexOf(tagNew); + const oldPos = tagList.indexOf(tagOld); const preferredNewPos = newPos === -1 ? endPos : newPos; const preferredOldPos = oldPos === -1 ? endPos : oldPos; if (preferredNewPos < preferredOldPos) { @@ -73,6 +81,222 @@ var _default = (0, _iterateJsdoc.default)(({ return 1; }); if (firstChangedTagLine === undefined) { + // Should be ordered by now + + const lastTagsOfGroup = []; + const badLastTagsOfGroup = []; + const countTagEmptyLines = tag => { + return tag.source.reduce((acc, { + tokens: { + description, + name, + type, + end, + tag: tg + } + }) => { + const empty = !tg && !type && !name && !description; + // Reset the count so long as there is content + return empty ? acc + (empty && !end) : 0; + }, 0); + }; + let idx = 0; + for (const { + tags + } of tagSequence) { + let innerIdx; + let currentTag; + let lastTag; + do { + currentTag = jsdoc.tags[idx]; + if (!currentTag) { + idx++; + break; + } + innerIdx = tags.indexOf(currentTag.tag); + if (innerIdx === -1 && ( + // eslint-disable-next-line no-loop-func -- Safe + !tags.includes('-other') || tagSequence.some(({ + tags: tgs + }) => { + return tgs.includes(currentTag.tag); + }))) { + idx++; + break; + } + lastTag = currentTag; + idx++; + } while (true); + idx--; + if (lastTag) { + lastTagsOfGroup.push(lastTag); + const ct = countTagEmptyLines(lastTag); + if (ct !== linesBetween && + // Use another rule for adding to end (should be of interest outside this rule) + jsdoc.tags[idx]) { + badLastTagsOfGroup.push([lastTag, ct]); + } + } + } + if (reportTagGroupSpacing && badLastTagsOfGroup.length) { + const fixer = tg => { + return () => { + // Due to https://github.com/syavorsky/comment-parser/issues/110 , + // we have to modify `jsdoc.source` rather than just modify tags + // directly + for (const [currIdx, { + tokens + }] of jsdoc.source.entries()) { + if (tokens.tag !== '@' + tg.tag) { + continue; + } + + // Cannot be `tokens.end`, as dropped off last tag, so safe to + // go on + let newIdx = currIdx; + const emptyLine = () => { + return { + tokens: utils.seedTokens({ + delimiter: '*', + start: jsdoc.source[newIdx - 1].tokens.start + }) + }; + }; + let existingEmptyLines = 0; + while (true) { + var _jsdoc$source$newIdx; + const nextTokens = (_jsdoc$source$newIdx = jsdoc.source[++newIdx]) === null || _jsdoc$source$newIdx === void 0 ? void 0 : _jsdoc$source$newIdx.tokens; + + /* istanbul ignore if -- Guard */ + if (!nextTokens) { + return; + } + + // Should be no `nextTokens.end` to worry about since ignored + // if not followed by tag + + if (nextTokens.tag) { + // Haven't made it to last tag instance yet, so keep looking + if (nextTokens.tag === tokens.tag) { + existingEmptyLines = 0; + continue; + } + const lineDiff = linesBetween - existingEmptyLines; + if (lineDiff > 0) { + const lines = Array.from({ + length: lineDiff + }, () => { + return emptyLine(); + }); + jsdoc.source.splice(newIdx, 0, ...lines); + } else { + // lineDiff < 0 + jsdoc.source.splice(newIdx + lineDiff, -lineDiff); + } + break; + } + const empty = !nextTokens.type && !nextTokens.name && !nextTokens.description; + if (empty) { + existingEmptyLines++; + } else { + // Has content again, so reset empty line count + existingEmptyLines = 0; + } + } + break; + } + for (const [srcIdx, src] of jsdoc.source.entries()) { + src.number = srcIdx; + } + }; + }; + for (const [tg, ct] of badLastTagsOfGroup) { + utils.reportJSDoc('Tag groups do not have the expected whitespace', tg, fixer(tg, ct)); + } + return; + } + if (!reportIntraTagGroupSpacing) { + return; + } + for (const [tagIdx, tag] of jsdoc.tags.entries()) { + if (!jsdoc.tags[tagIdx + 1] || lastTagsOfGroup.includes(tag)) { + continue; + } + const ct = countTagEmptyLines(tag); + if (ct) { + // eslint-disable-next-line complexity -- Temporary + const fixer = () => { + let foundFirstTag = false; + let currentTag; + for (const [currIdx, { + tokens: { + description, + name, + type, + end, + tag: tg + } + }] of jsdoc.source.entries()) { + if (tg) { + foundFirstTag = true; + currentTag = tg; + } + if (!foundFirstTag) { + continue; + } + if (currentTag && !tg && !type && !name && !description && !end) { + let nextIdx = currIdx; + let ignore = true; + // Even if a tag of the same name as the last tags in a group, + // could still be an earlier tag in that group + + // eslint-disable-next-line no-loop-func -- Safe + if (lastTagsOfGroup.some(lastTagOfGroup => { + return currentTag === '@' + lastTagOfGroup.tag; + })) { + while (true) { + var _jsdoc$source$nextIdx; + const nextTokens = (_jsdoc$source$nextIdx = jsdoc.source[++nextIdx]) === null || _jsdoc$source$nextIdx === void 0 ? void 0 : _jsdoc$source$nextIdx.tokens; + if (!nextTokens) { + break; + } + if (!nextTokens.tag) { + continue; + } + + // Followed by the same tag name, so not actually last in group, + // and of interest + if (nextTokens.tag === currentTag) { + ignore = false; + } + } + } else { + while (true) { + var _jsdoc$source$nextIdx2; + const nextTokens = (_jsdoc$source$nextIdx2 = jsdoc.source[++nextIdx]) === null || _jsdoc$source$nextIdx2 === void 0 ? void 0 : _jsdoc$source$nextIdx2.tokens; + if (!nextTokens || nextTokens.end) { + break; + } + + // Not the very last tag, so don't ignore + if (nextTokens.tag) { + ignore = false; + break; + } + } + } + if (!ignore) { + jsdoc.source.splice(currIdx, 1); + for (const [srcIdx, src] of jsdoc.source.entries()) { + src.number = srcIdx; + } + } + } + } + }; + utils.reportJSDoc('Intra-group tags have unexpected whitespace', tag, fixer); + } + } return; } const firstLine = utils.getFirstLine(); @@ -120,12 +344,12 @@ var _default = (0, _iterateJsdoc.default)(({ } } }; - utils.reportJSDoc(`Tags are not in the prescribed order: ${tagSequence.join(', ')}`, jsdoc.tags[firstChangedTagIndex], fix, true); + utils.reportJSDoc(`Tags are not in the prescribed order: ${tagList.join(', ') || '(alphabetical)'}`, jsdoc.tags[firstChangedTagIndex], fix, true); }, { iterateAllJsdocs: true, meta: { docs: { - description: '', + description: 'Sorts tags by a specified sequence according to tag name.', url: 'https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-sort-tags' }, fixable: 'code', @@ -135,9 +359,26 @@ var _default = (0, _iterateJsdoc.default)(({ alphabetizeExtras: { type: 'boolean' }, + linesBetween: { + type: 'integer' + }, + reportIntraTagGroupSpacing: { + type: 'boolean' + }, + reportTagGroupSpacing: { + type: 'boolean' + }, tagSequence: { items: { - type: 'string' + properties: { + tags: { + items: { + type: 'string' + }, + type: 'array' + } + }, + type: 'object' }, type: 'array' } |