"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _commentParser = require("comment-parser"); /** * Transform based on https://github.com/syavorsky/comment-parser/blob/master/src/transforms/align.ts * * It contains some customizations to align based on the tags, and some custom options. */ /** * @typedef {{ * hasNoTypes: boolean, * maxNamedTagLength: import('./iterateJsdoc.js').Integer, * maxUnnamedTagLength: import('./iterateJsdoc.js').Integer * }} TypelessInfo */ const { rewireSource } = _commentParser.util; /** * @typedef {{ * name: import('./iterateJsdoc.js').Integer, * start: import('./iterateJsdoc.js').Integer, * tag: import('./iterateJsdoc.js').Integer, * type: import('./iterateJsdoc.js').Integer * }} Width */ /** @type {Width} */ const zeroWidth = { name: 0, start: 0, tag: 0, type: 0 }; /** * @param {string[]} tags * @param {import('./iterateJsdoc.js').Integer} index * @param {import('comment-parser').Line[]} source * @returns {boolean} */ const shouldAlign = (tags, index, source) => { const tag = source[index].tokens.tag.replace('@', ''); const includesTag = tags.includes(tag); if (includesTag) { return true; } if (tag !== '') { return false; } for (let iterator = index; iterator >= 0; iterator--) { const previousTag = source[iterator].tokens.tag.replace('@', ''); if (previousTag !== '') { if (tags.includes(previousTag)) { return true; } return false; } } return true; }; /** * @param {string[]} tags * @returns {( * width: Width, * line: { * tokens: import('comment-parser').Tokens * }, * index: import('./iterateJsdoc.js').Integer, * source: import('comment-parser').Line[] * ) => Width} */ const getWidth = tags => { return (width, { tokens }, index, source) => { if (!shouldAlign(tags, index, source)) { return width; } return { name: Math.max(width.name, tokens.name.length), start: tokens.delimiter === '/**' ? tokens.start.length : width.start, tag: Math.max(width.tag, tokens.tag.length), type: Math.max(width.type, tokens.type.length) }; }; }; /** * @param {{ * description: string; * tags: import('comment-parser').Spec[]; * problems: import('comment-parser').Problem[]; * }} fields * @returns {TypelessInfo} */ const getTypelessInfo = fields => { const hasNoTypes = fields.tags.every(({ type }) => { return !type; }); const maxNamedTagLength = Math.max(...fields.tags.map(({ tag, name }) => { return name.length === 0 ? -1 : tag.length; }).filter(length => { return length !== -1; })) + 1; const maxUnnamedTagLength = Math.max(...fields.tags.map(({ tag, name }) => { return name.length === 0 ? tag.length : -1; }).filter(length => { return length !== -1; })) + 1; return { hasNoTypes, maxNamedTagLength, maxUnnamedTagLength }; }; /** * @param {import('./iterateJsdoc.js').Integer} len * @returns {string} */ const space = len => { return ''.padStart(len, ' '); }; /** * @param {{ * customSpacings: import('../src/rules/checkLineAlignment.js').CustomSpacings, * tags: string[], * indent: string, * preserveMainDescriptionPostDelimiter: boolean, * wrapIndent: string, * disableWrapIndent: boolean, * }} cfg * @returns {( * block: import('comment-parser').Block * ) => import('comment-parser').Block} */ const alignTransform = ({ customSpacings, tags, indent, preserveMainDescriptionPostDelimiter, wrapIndent, disableWrapIndent }) => { let intoTags = false; /** @type {Width} */ let width; /** * @param {import('comment-parser').Tokens} tokens * @param {TypelessInfo} typelessInfo * @returns {import('comment-parser').Tokens} */ const alignTokens = (tokens, typelessInfo) => { const nothingAfter = { delim: false, name: false, tag: false, type: false }; if (tokens.description === '') { nothingAfter.name = true; tokens.postName = ''; if (tokens.name === '') { nothingAfter.type = true; tokens.postType = ''; if (tokens.type === '') { nothingAfter.tag = true; tokens.postTag = ''; /* c8 ignore next: Never happens because the !intoTags return. But it's here for consistency with the original align transform */ if (tokens.tag === '') { nothingAfter.delim = true; } } } } let untypedNameAdjustment = 0; let untypedTypeAdjustment = 0; if (typelessInfo.hasNoTypes) { nothingAfter.tag = true; tokens.postTag = ''; if (tokens.name === '') { untypedNameAdjustment = typelessInfo.maxNamedTagLength - tokens.tag.length; } else { untypedNameAdjustment = typelessInfo.maxNamedTagLength > typelessInfo.maxUnnamedTagLength ? 0 : Math.max(0, typelessInfo.maxUnnamedTagLength - (tokens.tag.length + tokens.name.length + 1)); untypedTypeAdjustment = typelessInfo.maxNamedTagLength - tokens.tag.length; } } // Todo: Avoid fixing alignment of blocks with multiline wrapping of type if (tokens.tag === '' && tokens.type) { return tokens; } const spacings = { postDelimiter: (customSpacings === null || customSpacings === void 0 ? void 0 : customSpacings.postDelimiter) || 1, postName: (customSpacings === null || customSpacings === void 0 ? void 0 : customSpacings.postName) || 1, postTag: (customSpacings === null || customSpacings === void 0 ? void 0 : customSpacings.postTag) || 1, postType: (customSpacings === null || customSpacings === void 0 ? void 0 : customSpacings.postType) || 1 }; tokens.postDelimiter = nothingAfter.delim ? '' : space(spacings.postDelimiter); if (!nothingAfter.tag) { tokens.postTag = space(width.tag - tokens.tag.length + spacings.postTag); } if (!nothingAfter.type) { tokens.postType = space(width.type - tokens.type.length + spacings.postType + untypedTypeAdjustment); } if (!nothingAfter.name) { // If post name is empty for all lines (name width 0), don't add post name spacing. tokens.postName = width.name === 0 ? '' : space(width.name - tokens.name.length + spacings.postName + untypedNameAdjustment); } return tokens; }; /** * @param {import('comment-parser').Line} line * @param {import('./iterateJsdoc.js').Integer} index * @param {import('comment-parser').Line[]} source * @param {TypelessInfo} typelessInfo * @param {string|false} indentTag * @returns {import('comment-parser').Line} */ const update = (line, index, source, typelessInfo, indentTag) => { /** @type {import('comment-parser').Tokens} */ const tokens = { ...line.tokens }; if (tokens.tag !== '') { intoTags = true; } const isEmpty = tokens.tag === '' && tokens.name === '' && tokens.type === '' && tokens.description === ''; // dangling '*/' if (tokens.end === '*/' && isEmpty) { tokens.start = indent + ' '; return { ...line, tokens }; } switch (tokens.delimiter) { case '/**': tokens.start = indent; break; case '*': tokens.start = indent + ' '; break; default: tokens.delimiter = ''; // compensate delimiter tokens.start = indent + ' '; } if (!intoTags) { if (tokens.description === '') { tokens.postDelimiter = ''; } else if (!preserveMainDescriptionPostDelimiter) { tokens.postDelimiter = ' '; } return { ...line, tokens }; } const postHyphenSpacing = (customSpacings === null || customSpacings === void 0 ? void 0 : customSpacings.postHyphen) ?? 1; const hyphenSpacing = /^\s*-\s+/u; tokens.description = tokens.description.replace(hyphenSpacing, '-' + ''.padStart(postHyphenSpacing, ' ')); // Not align. if (shouldAlign(tags, index, source)) { alignTokens(tokens, typelessInfo); if (!disableWrapIndent && indentTag) { tokens.postDelimiter += wrapIndent; } } return { ...line, tokens }; }; return ({ source, ...fields }) => { width = source.reduce(getWidth(tags), { ...zeroWidth }); const typelessInfo = getTypelessInfo(fields); let tagIndentMode = false; return rewireSource({ ...fields, source: source.map((line, index) => { const indentTag = !disableWrapIndent && tagIndentMode && !line.tokens.tag && line.tokens.description; const ret = update(line, index, source, typelessInfo, indentTag); if (!disableWrapIndent && line.tokens.tag) { tagIndentMode = true; } return ret; }) }); }; }; var _default = exports.default = alignTransform; module.exports = exports.default; //# sourceMappingURL=alignTransform.cjs.map