123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- var _alignTransform = _interopRequireDefault(require("../alignTransform.js"));
- var _iterateJsdoc = _interopRequireDefault(require("../iterateJsdoc.js"));
- var _commentParser = require("comment-parser");
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- const {
- flow: commentFlow
- } = _commentParser.transforms;
- /**
- * @typedef {{
- * postDelimiter: import('../iterateJsdoc.js').Integer,
- * postHyphen: import('../iterateJsdoc.js').Integer,
- * postName: import('../iterateJsdoc.js').Integer,
- * postTag: import('../iterateJsdoc.js').Integer,
- * postType: import('../iterateJsdoc.js').Integer,
- * }} CustomSpacings
- */
- /**
- * @param {import('../iterateJsdoc.js').Utils} utils
- * @param {import('comment-parser').Spec & {
- * line: import('../iterateJsdoc.js').Integer
- * }} tag
- * @param {CustomSpacings} customSpacings
- */
- const checkNotAlignedPerTag = (utils, tag, customSpacings) => {
- /*
- start +
- delimiter +
- postDelimiter +
- tag +
- postTag +
- type +
- postType +
- name +
- postName +
- description +
- end +
- lineEnd
- */
- /**
- * @typedef {"tag"|"type"|"name"|"description"} ContentProp
- */
- /** @type {("postDelimiter"|"postTag"|"postType"|"postName")[]} */
- let spacerProps;
- /** @type {ContentProp[]} */
- let contentProps;
- const mightHaveNamepath = utils.tagMightHaveNamepath(tag.tag);
- if (mightHaveNamepath) {
- spacerProps = ['postDelimiter', 'postTag', 'postType', 'postName'];
- contentProps = ['tag', 'type', 'name', 'description'];
- } else {
- spacerProps = ['postDelimiter', 'postTag', 'postType'];
- contentProps = ['tag', 'type', 'description'];
- }
- const {
- tokens
- } = tag.source[0];
- /**
- * @param {import('../iterateJsdoc.js').Integer} idx
- * @param {(notRet: boolean, contentProp: ContentProp) => void} [callbck]
- */
- const followedBySpace = (idx, callbck) => {
- const nextIndex = idx + 1;
- return spacerProps.slice(nextIndex).some((spacerProp, innerIdx) => {
- const contentProp = contentProps[nextIndex + innerIdx];
- const spacePropVal = tokens[spacerProp];
- const ret = spacePropVal;
- if (callbck) {
- callbck(!ret, contentProp);
- }
- return ret && (callbck || !contentProp);
- });
- };
- const postHyphenSpacing = (customSpacings === null || customSpacings === void 0 ? void 0 : customSpacings.postHyphen) ?? 1;
- const exactHyphenSpacing = new RegExp(`^\\s*-\\s{${postHyphenSpacing},${postHyphenSpacing}}(?!\\s)`, 'u');
- const hasNoHyphen = !/^\s*-(?!$)(?=\s)/u.test(tokens.description);
- const hasExactHyphenSpacing = exactHyphenSpacing.test(tokens.description);
- // If checking alignment on multiple lines, need to check other `source`
- // items
- // Go through `post*` spacing properties and exit to indicate problem if
- // extra spacing detected
- const ok = !spacerProps.some((spacerProp, idx) => {
- const contentProp = contentProps[idx];
- const contentPropVal = tokens[contentProp];
- const spacerPropVal = tokens[spacerProp];
- const spacing = (customSpacings === null || customSpacings === void 0 ? void 0 : customSpacings[spacerProp]) || 1;
- // There will be extra alignment if...
- // 1. The spaces don't match the space it should have (1 or custom spacing) OR
- return spacerPropVal.length !== spacing && spacerPropVal.length !== 0 ||
- // 2. There is a (single) space, no immediate content, and yet another
- // space is found subsequently (not separated by intervening content)
- spacerPropVal && !contentPropVal && followedBySpace(idx);
- }) && (hasNoHyphen || hasExactHyphenSpacing);
- if (ok) {
- return;
- }
- const fix = () => {
- for (const [idx, spacerProp] of spacerProps.entries()) {
- const contentProp = contentProps[idx];
- const contentPropVal = tokens[contentProp];
- if (contentPropVal) {
- const spacing = (customSpacings === null || customSpacings === void 0 ? void 0 : customSpacings[spacerProp]) || 1;
- tokens[spacerProp] = ''.padStart(spacing, ' ');
- followedBySpace(idx, (hasSpace, contentPrp) => {
- if (hasSpace) {
- tokens[contentPrp] = '';
- }
- });
- } else {
- tokens[spacerProp] = '';
- }
- }
- if (!hasExactHyphenSpacing) {
- const hyphenSpacing = /^\s*-\s+/u;
- tokens.description = tokens.description.replace(hyphenSpacing, '-' + ''.padStart(postHyphenSpacing, ' '));
- }
- utils.setTag(tag, tokens);
- };
- utils.reportJSDoc('Expected JSDoc block lines to not be aligned.', tag, fix, true);
- };
- /**
- * @param {object} cfg
- * @param {CustomSpacings} cfg.customSpacings
- * @param {string} cfg.indent
- * @param {import('comment-parser').Block} cfg.jsdoc
- * @param {import('eslint').Rule.Node & {
- * range: [number, number]
- * }} cfg.jsdocNode
- * @param {boolean} cfg.preserveMainDescriptionPostDelimiter
- * @param {import('../iterateJsdoc.js').Report} cfg.report
- * @param {string[]} cfg.tags
- * @param {import('../iterateJsdoc.js').Utils} cfg.utils
- * @param {string} cfg.wrapIndent
- * @returns {void}
- */
- const checkAlignment = ({
- customSpacings,
- indent,
- jsdoc,
- jsdocNode,
- preserveMainDescriptionPostDelimiter,
- report,
- tags,
- utils,
- wrapIndent
- }) => {
- const transform = commentFlow((0, _alignTransform.default)({
- customSpacings,
- indent,
- preserveMainDescriptionPostDelimiter,
- tags,
- wrapIndent
- }));
- const transformedJsdoc = transform(jsdoc);
- const comment = '/*' +
- /**
- * @type {import('eslint').Rule.Node & {
- * range: [number, number], value: string
- * }}
- */
- jsdocNode.value + '*/';
- const formatted = utils.stringify(transformedJsdoc).trimStart();
- if (comment !== formatted) {
- report('Expected JSDoc block lines to be aligned.', /** @type {import('eslint').Rule.ReportFixer} */fixer => {
- return fixer.replaceText(jsdocNode, formatted);
- });
- }
- };
- var _default = exports.default = (0, _iterateJsdoc.default)(({
- indent,
- jsdoc,
- jsdocNode,
- report,
- context,
- utils
- }) => {
- const {
- tags: applicableTags = ['param', 'arg', 'argument', 'property', 'prop', 'returns', 'return'],
- preserveMainDescriptionPostDelimiter,
- customSpacings,
- wrapIndent = ''
- } = context.options[1] || {};
- if (context.options[0] === 'always') {
- // Skip if it contains only a single line.
- if (!(
- /**
- * @type {import('eslint').Rule.Node & {
- * range: [number, number], value: string
- * }}
- */
- jsdocNode.value.includes('\n'))) {
- return;
- }
- checkAlignment({
- customSpacings,
- indent,
- jsdoc,
- jsdocNode,
- preserveMainDescriptionPostDelimiter,
- report,
- tags: applicableTags,
- utils,
- wrapIndent
- });
- return;
- }
- const foundTags = utils.getPresentTags(applicableTags);
- if (context.options[0] !== 'any') {
- for (const tag of foundTags) {
- checkNotAlignedPerTag(utils,
- /**
- * @type {import('comment-parser').Spec & {
- * line: import('../iterateJsdoc.js').Integer
- * }}
- */
- tag, customSpacings);
- }
- }
- for (const tag of foundTags) {
- 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(0) + wrapIndent;
- });
- return;
- }
- }
- }
- }
- }, {
- iterateAllJsdocs: true,
- meta: {
- docs: {
- description: 'Reports invalid alignment of JSDoc block lines.',
- url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-line-alignment.md#repos-sticky-header'
- },
- fixable: 'whitespace',
- schema: [{
- enum: ['always', 'never', 'any'],
- type: 'string'
- }, {
- additionalProperties: false,
- properties: {
- customSpacings: {
- additionalProperties: false,
- properties: {
- postDelimiter: {
- type: 'integer'
- },
- postHyphen: {
- type: 'integer'
- },
- postName: {
- type: 'integer'
- },
- postTag: {
- type: 'integer'
- },
- postType: {
- type: 'integer'
- }
- }
- },
- preserveMainDescriptionPostDelimiter: {
- default: false,
- type: 'boolean'
- },
- tags: {
- items: {
- type: 'string'
- },
- type: 'array'
- },
- wrapIndent: {
- type: 'string'
- }
- },
- type: 'object'
- }],
- type: 'layout'
- }
- });
- module.exports = exports.default;
- //# sourceMappingURL=checkLineAlignment.js.map
|