Socket
Socket
Sign inDemoInstall

@es-joy/jsdoccomment

Package Overview
Dependencies
Maintainers
2
Versions
99
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@es-joy/jsdoccomment - npm Package Compare versions

Comparing version 0.42.0 to 0.43.0

20

CHANGES.md
# CHANGES for `@es-joy/jsdoccomment`
## 0.43.0
This release brings surgical round trip parsing to generated AST and reconstruction of JSDoc comment blocks via: `parseComment` ->
`commentParserToESTree` -> `estreeToString`.
- feat: new option `spacing` for `commentParserToESTree`; the default is `compact` removing empty description lines.
Set to `preserve` to retain empty description lines.
- feat: new properties in the `JsdocBlock` generated AST `delimiterLineBreak` and `preterminalLineBreak` that encode
any line break after the opening `delimiter` and before the closing `terminal` string. Values are either `\n` or an
empty string.
- chore: update devDeps / switch to Vitest.
- New [API documentation](https://es-joy.github.io/jsdoccomment/).
Thanks:
- [@typhonrt](https://github.com/typhonrt)
## 0.42.0
- feat: expand argument for `parseComment` to accept a comment token string (@typhonrt)
- feat: expand argument for `parseComment` to accept a comment token string ([@typhonrt](https://github.com/typhonrt))
- chore: update devDeps.

@@ -7,0 +25,0 @@

@@ -1,36 +0,321 @@

export { visitorKeys as jsdocTypeVisitorKeys } from "jsdoc-type-pratt-parser";
export * from "jsdoc-type-pratt-parser";
export * from "./parseComment.js";
export * from "./commentParserToESTree.js";
export * from "./jsdoccomment.js";
export { default as commentHandler } from "./commentHandler.js";
export { default as toCamelCase } from "./toCamelCase.js";
export { default as parseInlineTags } from "./parseInlineTags.js";
export { default as estreeToString } from "./estreeToString.js";
export type InlineTag = import('./commentParserToESTree.js').JsdocInlineTagNoType & {
start: number;
end: number;
import * as comment_parser from 'comment-parser';
import * as jsdoc_type_pratt_parser from 'jsdoc-type-pratt-parser';
export * from 'jsdoc-type-pratt-parser';
export { visitorKeys as jsdocTypeVisitorKeys } from 'jsdoc-type-pratt-parser';
import * as _typescript_eslint_types from '@typescript-eslint/types';
import * as estree from 'estree';
import * as eslint from 'eslint';
type JsdocTypeLine = {
delimiter: string;
postDelimiter: string;
rawType: string;
initial: string;
type: 'JsdocTypeLine';
};
export type JsdocTagWithInline = import('comment-parser').Spec & {
line?: import('./commentParserToESTree.js').Integer;
inlineTags: (import('./commentParserToESTree.js').JsdocInlineTagNoType & {
line?: import('./commentParserToESTree.js').Integer;
})[];
type JsdocDescriptionLine = {
delimiter: string;
description: string;
postDelimiter: string;
initial: string;
type: 'JsdocDescriptionLine';
};
type JsdocInlineTagNoType = {
format: 'pipe' | 'plain' | 'prefix' | 'space';
namepathOrURL: string;
tag: string;
text: string;
};
type JsdocInlineTag = JsdocInlineTagNoType & {
type: 'JsdocInlineTag';
};
type JsdocTag = {
delimiter: string;
description: string;
descriptionLines: JsdocDescriptionLine[];
initial: string;
inlineTags: JsdocInlineTag[];
name: string;
postDelimiter: string;
postName: string;
postTag: string;
postType: string;
rawType: string;
parsedType: jsdoc_type_pratt_parser.RootResult | null;
tag: string;
type: 'JsdocTag';
typeLines: JsdocTypeLine[];
};
type Integer = number;
type JsdocBlock = {
delimiter: string;
delimiterLineBreak: string;
description: string;
descriptionEndLine?: Integer;
descriptionLines: JsdocDescriptionLine[];
descriptionStartLine?: Integer;
hasPreterminalDescription: 0 | 1;
hasPreterminalTagDescription?: 1;
initial: string;
inlineTags: JsdocInlineTag[];
lastDescriptionLine?: Integer;
endLine: Integer;
lineEnd: string;
postDelimiter: string;
tags: JsdocTag[];
terminal: string;
preterminalLineBreak: string;
type: 'JsdocBlock';
};
/**
* Converts comment parser AST to ESTree format.
* @param {import('.').JsdocBlockWithInline} jsdoc
* @param {import('jsdoc-type-pratt-parser').ParseMode} mode
* @param {object} opts
* @param {'compact'|'preserve'} [opts.spacing] By default, empty lines are
* compacted; set to 'preserve' to preserve empty comment lines.
* @param {boolean} [opts.throwOnTypeParsingErrors]
* @returns {JsdocBlock}
*/
declare function commentParserToESTree(
jsdoc: JsdocBlockWithInline,
mode: jsdoc_type_pratt_parser.ParseMode,
{
spacing,
throwOnTypeParsingErrors,
}?: {
spacing?: 'compact' | 'preserve';
throwOnTypeParsingErrors?: boolean;
},
): JsdocBlock;
declare namespace jsdocVisitorKeys {
let JsdocBlock: string[];
let JsdocDescriptionLine: any[];
let JsdocTypeLine: any[];
let JsdocTag: string[];
let JsdocInlineTag: any[];
}
/**
* @param {{[name: string]: any}} settings
* @returns {import('.').CommentHandler}
*/
declare function commentHandler(settings: { [name: string]: any }): CommentHandler;
/**
* @todo convert for use by escodegen (until may be patched to support
* custom entries?).
* @param {import('./commentParserToESTree').JsdocBlock|
* import('./commentParserToESTree').JsdocDescriptionLine|
* import('./commentParserToESTree').JsdocTypeLine|
* import('./commentParserToESTree').JsdocTag|
* import('./commentParserToESTree').JsdocInlineTag|
* import('jsdoc-type-pratt-parser').RootResult
* } node
* @param {import('.').ESTreeToStringOptions} opts
* @throws {Error}
* @returns {string}
*/
declare function estreeToString(
node:
| JsdocBlock
| JsdocDescriptionLine
| JsdocTypeLine
| JsdocTag
| JsdocInlineTag
| jsdoc_type_pratt_parser.RootResult,
opts?: ESTreeToStringOptions,
): string;
type Token =
| eslint.AST.Token
| estree.Comment
| {
type: eslint.AST.TokenType | 'Line' | 'Block' | 'Shebang';
range: [number, number];
value: string;
};
type ESLintOrTSNode = eslint.Rule.Node | _typescript_eslint_types.TSESTree.Node;
type int = number;
/**
* Reduces the provided node to the appropriate node for evaluating
* JSDoc comment status.
*
* @param {import('eslint').Rule.Node} node An AST node.
* @param {import('eslint').SourceCode} sourceCode The ESLint SourceCode.
* @returns {import('eslint').Rule.Node} The AST node that
* can be evaluated for appropriate JSDoc comments.
*/
declare function getReducedASTNode(node: eslint.Rule.Node, sourceCode: eslint.SourceCode): eslint.Rule.Node;
/**
* Retrieves the JSDoc comment for a given node.
*
* @param {import('eslint').SourceCode} sourceCode The ESLint SourceCode
* @param {import('eslint').Rule.Node} node The AST node to get
* the comment for.
* @param {{maxLines: int, minLines: int, [name: string]: any}} settings The
* settings in context
* @returns {Token|null} The Block comment
* token containing the JSDoc comment for the given node or
* null if not found.
* @public
*/
declare function getJSDocComment(
sourceCode: eslint.SourceCode,
node: eslint.Rule.Node,
settings: {
[name: string]: any;
maxLines: int;
minLines: int;
},
): Token | null;
/**
* @param {(import('estree').Comment|import('eslint').Rule.Node) & {
* declaration?: any,
* decorators?: any[],
* parent?: import('eslint').Rule.Node & {
* decorators?: any[]
* }
* }} node
* @returns {import('@typescript-eslint/types').TSESTree.Decorator|undefined}
*/
declare function getDecorator(
node: (estree.Comment | eslint.Rule.Node) & {
declaration?: any;
decorators?: any[];
parent?: eslint.Rule.Node & {
decorators?: any[];
};
},
): _typescript_eslint_types.TSESTree.Decorator | undefined;
/**
* Checks for the presence of a JSDoc comment for the given node and returns it.
*
* @param {import('eslint').Rule.Node} astNode The AST node to get
* the comment for.
* @param {import('eslint').SourceCode} sourceCode
* @param {{maxLines: int, minLines: int, [name: string]: any}} settings
* @returns {Token|null} The Block comment token containing the JSDoc comment
* for the given node or null if not found.
* @private
*/
declare function findJSDocComment(
astNode: eslint.Rule.Node,
sourceCode: eslint.SourceCode,
settings: {
[name: string]: any;
maxLines: int;
minLines: int;
},
): Token | null;
declare function hasSeeWithLink(spec: comment_parser.Spec): boolean;
declare const defaultNoTypes: string[];
declare const defaultNoNames: string[];
/**
* Can't import `comment-parser/es6/parser/tokenizers/index.js`,
* so we redefine here.
*/
type CommentParserTokenizer = (spec: comment_parser.Spec) => comment_parser.Spec;
/**
* Can't import `comment-parser/es6/parser/tokenizers/index.js`,
* so we redefine here.
* @typedef {(spec: import('comment-parser').Spec) =>
* import('comment-parser').Spec} CommentParserTokenizer
*/
/**
* @param {object} [cfg]
* @param {string[]} [cfg.noTypes]
* @param {string[]} [cfg.noNames]
* @returns {CommentParserTokenizer[]}
*/
declare function getTokenizers({
noTypes,
noNames,
}?: {
noTypes?: string[];
noNames?: string[];
}): CommentParserTokenizer[];
/**
* Accepts a comment token or complete comment string and converts it into
* `comment-parser` AST.
* @param {string | {value: string}} commentOrNode
* @param {string} [indent] Whitespace
* @returns {import('.').JsdocBlockWithInline}
*/
declare function parseComment(
commentOrNode:
| string
| {
value: string;
},
indent?: string,
): JsdocBlockWithInline;
/**
* Splits the `{@prefix}` from remaining `Spec.lines[].token.description`
* into the `inlineTags` tokens, and populates `spec.inlineTags`
* @param {import('comment-parser').Block} block
* @returns {import('.').JsdocBlockWithInline}
*/
declare function parseInlineTags(block: comment_parser.Block): JsdocBlockWithInline;
type InlineTag = JsdocInlineTagNoType & {
start: number;
end: number;
};
type JsdocTagWithInline = comment_parser.Spec & {
line?: Integer;
inlineTags: (JsdocInlineTagNoType & {
line?: Integer;
})[];
};
/**
* Expands on comment-parser's `Block` interface.
*/
export type JsdocBlockWithInline = {
description: string;
source: import('comment-parser').Line[];
problems: import('comment-parser').Problem[];
tags: JsdocTagWithInline[];
inlineTags: (import('./commentParserToESTree.js').JsdocInlineTagNoType & {
line?: import('./commentParserToESTree.js').Integer;
})[];
type JsdocBlockWithInline = {
description: string;
source: comment_parser.Line[];
problems: comment_parser.Problem[];
tags: JsdocTagWithInline[];
inlineTags: (JsdocInlineTagNoType & {
line?: Integer;
})[];
};
export type ESTreeToStringOptions = {
preferRawType?: boolean;
type ESTreeToStringOptions = {
preferRawType?: boolean;
};
export type CommentHandler = (commentSelector: string, jsdoc: import('./index.js').JsdocBlockWithInline) => boolean;
//# sourceMappingURL=index.d.ts.map
type CommentHandler = (commentSelector: string, jsdoc: JsdocBlockWithInline) => boolean;
export {
type CommentHandler,
type CommentParserTokenizer,
type ESLintOrTSNode,
type ESTreeToStringOptions,
type InlineTag,
type Integer,
JsdocBlock,
type JsdocBlockWithInline,
JsdocDescriptionLine,
JsdocInlineTag,
type JsdocInlineTagNoType,
JsdocTag,
type JsdocTagWithInline,
JsdocTypeLine,
type Token,
commentHandler,
commentParserToESTree,
defaultNoNames,
defaultNoTypes,
estreeToString,
findJSDocComment,
getDecorator,
getJSDocComment,
getReducedASTNode,
getTokenizers,
hasSeeWithLink,
type int,
jsdocVisitorKeys,
parseComment,
parseInlineTags,
};

63

package.json
{
"name": "@es-joy/jsdoccomment",
"version": "0.42.0",
"version": "0.43.0",
"author": "Brett Zamir <brettz9@yahoo.com>",

@@ -9,2 +9,7 @@ "contributors": [],

"keywords": [
"ast",
"comment",
"estree",
"jsdoc",
"parser",
"eslint",

@@ -15,3 +20,2 @@ "sourcecode"

"types": "./dist/index.d.ts",
"main": "./dist/index.cjs.cjs",
"exports": {

@@ -22,16 +26,11 @@ "types": "./dist/index.d.ts",

},
"c8": {
"reporter": [
"lcov",
"text"
],
"checkCoverage": true,
"branches": 100,
"statements": 100,
"lines": 100,
"functions": 100
},
"browserslist": [
"cover 100%"
],
"typedocOptions": {
"dmtLinksService": {
"GitHub": "https://github.com/es-joy/jsdoccomment",
"NPM": "https://www.npmjs.com/package/@es-joy/jsdoccomment"
}
},
"repository": {

@@ -49,2 +48,5 @@ "type": "git",

"dependencies": {
"@typescript-eslint/types": "^7.2.0",
"@types/eslint": "^8.56.5",
"@types/estree": "^1.0.5",
"comment-parser": "1.4.1",

@@ -60,11 +62,8 @@ "esquery": "^1.5.0",

"@rollup/plugin-babel": "^6.0.4",
"@types/chai": "^4.3.11",
"@types/eslint": "^8.56.2",
"@types/esquery": "^1.5.3",
"@types/estraverse": "^5.1.7",
"@types/estree": "^1.0.5",
"@types/mocha": "^10.0.6",
"@typescript-eslint/types": "^6.20.0",
"c8": "^9.1.0",
"chai": "^5.0.3",
"@typhonjs-build-test/esm-d-ts": "^0.3.0-next.1",
"@typhonjs-typedoc/typedoc-pkg": "^0.0.4",
"@vitest/coverage-v8": "^1.3.0",
"@vitest/ui": "^1.3.0",
"eslint": "^8.56.0",

@@ -88,17 +87,23 @@ "eslint-config-ash-nazg": "35.3.0",

"estraverse": "^5.3.0",
"mocha": "^10.2.0",
"rollup": "^4.9.6",
"typescript": "^5.3.3"
"typescript": "^5.4.2",
"vitest": "^1.3.0"
},
"files": [
"/dist",
"/src",
"CHANGES.md",
"LICENSE-MIT.txt"
],
"scripts": {
"tsc": "tsc",
"open": "open ./coverage/lcov-report/index.html",
"build": "npm run rollup && tsc -p tsconfig-prod.json",
"rollup": "rollup -c",
"build": "rollup -c && npm run types",
"docs": "typedoc-pkg --api-link es",
"eslint": "eslint --ext=js,cjs,md,html .",
"lint": "npm run eslint --",
"mocha": "mocha --require chai/register-expect.js",
"c8": "c8 npm run mocha",
"test": "npm run lint && npm run build && npm run c8"
"open": "open ./coverage/index.html",
"test": "npm run lint && npm run build && vitest run --coverage",
"test-ui": "vitest --ui --coverage",
"tsc": "tsc",
"types": "esm-d-ts gen ./src/index.js --output ./dist/index.d.ts"
}
}
# @es-joy/jsdoccomment
[![Node.js CI status](https://github.com/brettz9/getJSDocComment/workflows/Node.js%20CI/badge.svg)](https://github.com/brettz9/getJSDocComment/actions)
[![NPM](https://img.shields.io/npm/v/@es-joy/jsdoccomment.svg?label=npm)](https://www.npmjs.com/package/@es-joy/jsdoccomment)
[![License](https://img.shields.io/badge/license-MIT-yellowgreen.svg?style=flat)](https://github.com/es-joy/jsdoccomment/blob/main/LICENSE-MIT.txt)
[![Build Status](https://github.com/es-joy/jsdoccomment/workflows/CI/CD/badge.svg)](#)
[![API Docs](https://img.shields.io/badge/API%20Documentation-476ff0)](https://es-joy.github.io/jsdoccomment/)
This project aims to preserve and expand upon the

@@ -65,21 +69,16 @@ `SourceCode#getJSDocComment` functionality of the deprecated ESLint method.

Also currently exports these utilities, though they might be removed in the
future:
Also currently exports these utilities:
- `getTokenizers` - Used with `parseComment` (its main core)
- `toCamelCase` - Convert to CamelCase.
- `hasSeeWithLink` - A utility to detect if a tag is `@see` and has a `@link`
- `commentHandler` - Used by `eslint-plugin-jsdoc`. Might be removed in future.
- `getTokenizers` - Used with `parseComment` (its main core).
- `hasSeeWithLink` - A utility to detect if a tag is `@see` and has a `@link`.
- `commentHandler` - Used by `eslint-plugin-jsdoc`.
- `commentParserToESTree`- Converts [comment-parser](https://github.com/syavorsky/comment-parser)
AST to ESTree/ESLint/Babel friendly AST
AST to ESTree/ESLint/Babel friendly AST.
- `jsdocVisitorKeys` - The [VisitorKeys](https://github.com/eslint/eslint-visitor-keys)
for `JSDocBlock`, `JSDocDescriptionLine`, and `JSDocTag`. Might change.
for `JSDocBlock`, `JSDocDescriptionLine`, and `JSDocTag`.
- `jsdocTypeVisitorKeys` - [VisitorKeys](https://github.com/eslint/eslint-visitor-keys)
for `jsdoc-type-pratt-parser`.
- `getTokenizers` - A utility. Might be removed in future.
- `toCamelCase` - A utility. Might be removed in future.
- `hasSeeWithLink` - A utility to detect if a tag is `@see` and has a `@link`
- `defaultNoTypes` = The tags which allow no types by default:
`default`, `defaultvalue`, `description`, `example`, `file`,
`fileoverview`, `license`, `overview`, `see`, `summary`;
`fileoverview`, `license`, `overview`, `see`, `summary`
- `defaultNoNames` - The tags which allow no names by default:

@@ -107,12 +106,14 @@ `access`, `author`, `default`, `defaultvalue`, `description`, `example`,

1. `lastDescriptionLine` - A number
2. `endLine` - A number representing the line number with `end`/`terminal`
3. `descriptionStartLine` - A 0+ number indicating the line where any
1. `delimiterLineBreak` - A string containing any line break after `delimiter`.
2. `lastDescriptionLine` - A number
3. `endLine` - A number representing the line number with `end`/`terminal`
4. `descriptionStartLine` - A 0+ number indicating the line where any
description begins
4. `descriptionEndLine` - A 0+ number indicating the line where the description
5. `descriptionEndLine` - A 0+ number indicating the line where the description
ends
5. `hasPreterminalDescription` - Set to 0 or 1. On if has a block description
6. `hasPreterminalDescription` - Set to 0 or 1. On if has a block description
on the same line as the terminal `*/`.
6. `hasPreterminalTagDescription` - Set to 0 or 1. On if has a tag description
7. `hasPreterminalTagDescription` - Set to 0 or 1. On if has a tag description
on the same line as the terminal `*/`.
8. `preterminalLineBreak` - A string containing any line break before `terminal`.

@@ -216,3 +217,3 @@ May also have the following non-visitable properties from `comment-parser`:

The changelog can be found on the [CHANGES.md](./CHANGES.md).
The changelog can be found on the [CHANGES.md](https://github.com/es-joy/jsdoccomment/blob/main/CHANGES.md).
<!--## Contributing

@@ -225,5 +226,5 @@

[Brett Zamir](http://brett-zamir.me/) and
[contributors](https://github.com/es-joy/jsdoc-eslint-parser/graphs/contributors).
[contributors](https://github.com/es-joy/jsdoccomment/graphs/contributors).
MIT License, see the included [LICENSE-MIT.txt](LICENSE-MIT.txt) file.
MIT License, see the included [LICENSE-MIT.txt](https://github.com/es-joy/jsdoccomment/blob/main/LICENSE-MIT.txt) file.

@@ -230,0 +231,0 @@ ## To-dos

@@ -12,12 +12,8 @@ import esquery from 'esquery';

/**
* @typedef {import('./index.js').CommentHandler} CommentHandler
*/
/**
* @param {{[name: string]: any}} settings
* @returns {CommentHandler}
* @returns {import('.').CommentHandler}
*/
const commentHandler = (settings) => {
/**
* @type {CommentHandler}
* @type {import('.').CommentHandler}
*/

@@ -44,2 +40,2 @@ return (commentSelector, jsdoc) => {

export default commentHandler;
export {commentHandler};

@@ -92,2 +92,3 @@ import {parse as jsdocTypePrattParse} from 'jsdoc-type-pratt-parser';

* delimiter: string,
* delimiterLineBreak: string,
* description: string,

@@ -107,2 +108,3 @@ * descriptionEndLine?: Integer,

* terminal: string,
* preterminalLineBreak: string,
* type: "JsdocBlock",

@@ -130,5 +132,7 @@ * }} JsdocBlock

* Converts comment parser AST to ESTree format.
* @param {import('./index.js').JsdocBlockWithInline} jsdoc
* @param {import('.').JsdocBlockWithInline} jsdoc
* @param {import('jsdoc-type-pratt-parser').ParseMode} mode
* @param {object} opts
* @param {'compact'|'preserve'} [opts.spacing] By default, empty lines are
* compacted; set to 'preserve' to preserve empty comment lines.
* @param {boolean} [opts.throwOnTypeParsingErrors]

@@ -138,2 +142,3 @@ * @returns {JsdocBlock}

const commentParserToESTree = (jsdoc, mode, {
spacing = 'compact',
throwOnTypeParsingErrors = false

@@ -150,2 +155,3 @@ } = {}) => {

stripEncapsulatingBrackets(lastTag);
if (lastTag.typeLines.length) {

@@ -155,2 +161,8 @@ stripEncapsulatingBrackets(lastTag.typeLines, true);

// Remove single empty line description.
if (lastTag.descriptionLines.length === 1 &&
lastTag.descriptionLines[0].description === '') {
lastTag.descriptionLines.length = 0;
}
// With even a multiline type now in full, add parsing

@@ -191,2 +203,3 @@ let parsedType = null;

delimiter: delimiterRoot,
delimiterLineBreak: '\n',
description: '',

@@ -201,2 +214,3 @@

terminal: endRoot,
preterminalLineBreak: '\n',
hasPreterminalDescription: 0,

@@ -221,2 +235,5 @@ endLine,

// Tracks when first valid tag description line is seen.
let tagDescriptionSeen = false;
let descLineStateOpen = true;

@@ -259,3 +276,19 @@

ast.terminal = end;
// Check if there are any description lines and if not then this is a
// one line comment block.
const isDelimiterLine = ast.descriptionLines.length === 0 &&
delimiter === '/**';
// Remove delimiter line break for one line comments blocks.
if (isDelimiterLine) {
ast.delimiterLineBreak = '';
}
if (description) {
// Remove terminal line break at end when description is defined.
if (ast.terminal === '*/') {
ast.preterminalLineBreak = '';
}
if (lastTag) {

@@ -269,6 +302,10 @@ ast.hasPreterminalTagDescription = 1;

holder.description += (holder.description ? '\n' : '') + description;
// Do not include `delimiter` / `postDelimiter` for opening
// delimiter line.
holder.descriptionLines.push({
delimiter,
delimiter: isDelimiterLine ? '' : delimiter,
description,
postDelimiter,
postDelimiter: isDelimiterLine ? '' : postDelimiter,
initial,

@@ -347,2 +384,3 @@ type: 'JsdocDescriptionLine'

lastTag = tagObj;
tagDescriptionSeen = false;

@@ -378,34 +416,71 @@ tags.push(tagObj);

if (description) {
// In `compact` mode skip processing if `description` is an empty string
// unless lastTag is being processed.
//
// In `preserve` mode process when `description` is not the `empty string
// or the `delimiter` is not `/**` ensuring empty lines are preserved.
if (((spacing === 'compact' && description) || lastTag) ||
(spacing === 'preserve' && (description || delimiter !== '/**'))) {
const holder = lastTag || ast;
holder.descriptionLines.push(
holder.descriptionLines.length
? {
delimiter,
description,
postDelimiter,
initial,
type: 'JsdocDescriptionLine'
}
: lastTag
? {
delimiter: '',
// Check if there are any description lines and if not then this is a
// multi-line comment block with description on 0th line. Treat
// `delimiter` / `postDelimiter` / `initial` as being on a new line.
const isDelimiterLine = holder.descriptionLines.length === 0 &&
delimiter === '/**';
// Remove delimiter line break for one line comments blocks.
if (isDelimiterLine) {
ast.delimiterLineBreak = '';
}
// Track when the first description line is seen to avoid adding empty
// description lines for tag type lines.
tagDescriptionSeen ||= Boolean(lastTag &&
(rawType === '' || rawType?.endsWith('}')));
if (lastTag) {
if (tagDescriptionSeen) {
// The first tag description line is a continuation after type /
// name parsing.
const isFirstDescriptionLine = holder.descriptionLines.length === 0;
// For `compact` spacing must allow through first description line.
if ((spacing === 'compact' &&
(description || isFirstDescriptionLine)) ||
spacing === 'preserve') {
holder.descriptionLines.push({
delimiter: isFirstDescriptionLine ? '' : delimiter,
description,
postDelimiter: '',
initial: '',
postDelimiter: isFirstDescriptionLine ? '' : postDelimiter,
initial: isFirstDescriptionLine ? '' : initial,
type: 'JsdocDescriptionLine'
}
: {
delimiter,
description,
postDelimiter,
initial,
type: 'JsdocDescriptionLine'
}
);
});
}
}
} else {
holder.descriptionLines.push({
delimiter: isDelimiterLine ? '' : delimiter,
description,
postDelimiter: isDelimiterLine ? '' : postDelimiter,
initial: isDelimiterLine ? `` : initial,
type: 'JsdocDescriptionLine'
});
}
if (!tag) {
holder.description += (!holder.description && !lastTag)
? description
: '\n' + description;
if (lastTag) {
// For `compact` spacing must filter out any empty description lines
// after the initial `holder.description` has content.
if (tagDescriptionSeen && !(spacing === 'compact' &&
holder.description && description === '')) {
holder.description += !holder.description
? description
: '\n' + description;
}
} else {
holder.description += !holder.description
? description
: '\n' + description;
}
}

@@ -419,2 +494,7 @@ }

// Remove terminal line break at end when tag is defined on last line.
if (ast.terminal === '*/') {
ast.preterminalLineBreak = '';
}
cleanUpLastTag(/** @type {JsdocTag} */ (lastTag));

@@ -421,0 +501,0 @@ }

@@ -1,48 +0,9 @@

import {
visitorKeys as jsdocTypePrattParserVisitorKeys,
stringify
} from 'jsdoc-type-pratt-parser';
import {stringify as prattStringify} from 'jsdoc-type-pratt-parser';
import {jsdocVisitorKeys} from './commentParserToESTree.js';
/**
* @typedef {import('./index.js').ESTreeToStringOptions} ESTreeToStringOptions
*/
/** @type {Record<string, Function>} */
const stringifiers = {
/**
* @param {import('./commentParserToESTree.js').JsdocBlock} node
* @param {ESTreeToStringOptions} opts
* @param {string[]} descriptionLines
* @param {string[]} tags
* @returns {string}
*/
JsdocBlock ({
delimiter, postDelimiter, lineEnd, initial, terminal, endLine
}, opts, descriptionLines, tags) {
const alreadyHasLine =
(descriptionLines.length && !tags.length &&
descriptionLines.at(-1)?.endsWith('\n')) ||
(tags.length && tags.at(-1)?.endsWith('\n'));
return `${initial}${delimiter}${postDelimiter}${endLine
? `
`
: ''}${
// Could use `node.description` (and `node.lineEnd`), but lines may have
// been modified
descriptionLines.length
? descriptionLines.join(
lineEnd + '\n'
) + (tags.length ? lineEnd + '\n' : '')
: ''
}${
tags.length ? tags.join(lineEnd + '\n') : ''
}${endLine && !alreadyHasLine
? `${lineEnd}
${initial}`
: endLine ? ` ${initial}` : ''}${terminal}`;
},
JsdocBlock,
/**
* @param {import('./commentParserToESTree.js').JsdocDescriptionLine} node
* @param {import('./commentParserToESTree').JsdocDescriptionLine} node
* @returns {string}

@@ -57,3 +18,3 @@ */

/**
* @param {import('./commentParserToESTree.js').JsdocTypeLine} node
* @param {import('./commentParserToESTree').JsdocTypeLine} node
* @returns {string}

@@ -68,3 +29,3 @@ */

/**
* @param {import('./commentParserToESTree.js').JsdocInlineTag} node
* @param {import('./commentParserToESTree').JsdocInlineTag} node
*/

@@ -82,46 +43,16 @@ JsdocInlineTag ({format, namepathOrURL, tag, text}) {

/**
* @param {import('./commentParserToESTree.js').JsdocTag} node
* @param {ESTreeToStringOptions} opts
* @param {string} parsedType
* @param {string[]} typeLines
* @param {string[]} descriptionLines
* @returns {string}
*/
JsdocTag (node, opts, parsedType, typeLines, descriptionLines) {
const {
description,
name, postName, postTag, postType,
initial, delimiter, postDelimiter, tag
// , rawType
} = node;
return `${initial}${delimiter}${postDelimiter}@${tag}${postTag}${
// Could do `rawType` but may have been changed; could also do
// `typeLines` but not as likely to be changed
// parsedType
// Comment this out later in favor of `parsedType`
// We can't use raw `typeLines` as first argument has delimiter on it
(opts.preferRawType || !parsedType)
? typeLines.length ? `{${typeLines.join('\n')}}` : ''
: parsedType
}${postType}${
name ? `${name}${postName || (description ? '\n' : '')}` : ''
}${descriptionLines.join('\n')}`;
}
JsdocTag
};
const visitorKeys = {...jsdocVisitorKeys, ...jsdocTypePrattParserVisitorKeys};
/**
* @todo convert for use by escodegen (until may be patched to support
* custom entries?).
* @param {import('./commentParserToESTree.js').JsdocBlock|
* import('./commentParserToESTree.js').JsdocDescriptionLine|
* import('./commentParserToESTree.js').JsdocTypeLine|
* import('./commentParserToESTree.js').JsdocTag|
* import('./commentParserToESTree.js').JsdocInlineTag|
* @param {import('./commentParserToESTree').JsdocBlock|
* import('./commentParserToESTree').JsdocDescriptionLine|
* import('./commentParserToESTree').JsdocTypeLine|
* import('./commentParserToESTree').JsdocTag|
* import('./commentParserToESTree').JsdocInlineTag|
* import('jsdoc-type-pratt-parser').RootResult
* } node
* @param {ESTreeToStringOptions} opts
* @param {import('.').ESTreeToStringOptions} opts
* @throws {Error}

@@ -132,36 +63,8 @@ * @returns {string}

if (Object.prototype.hasOwnProperty.call(stringifiers, node.type)) {
const childNodeOrArray = visitorKeys[node.type];
const args = /** @type {(string[]|string|null)[]} */ (
childNodeOrArray.map((key) => {
// @ts-expect-error
return Array.isArray(node[key])
// @ts-expect-error
? node[key].map(
(
/**
* @type {import('./commentParserToESTree.js').JsdocBlock|
* import('./commentParserToESTree.js').JsdocDescriptionLine|
* import('./commentParserToESTree.js').JsdocTypeLine|
* import('./commentParserToESTree.js').JsdocTag|
* import('./commentParserToESTree.js').JsdocInlineTag}
*/
item
) => {
return estreeToString(item, opts);
}
)
// @ts-expect-error
: (node[key] === undefined || node[key] === null
? null
// @ts-expect-error
: estreeToString(node[key], opts));
})
);
return stringifiers[
/**
* @type {import('./commentParserToESTree.js').JsdocBlock|
* import('./commentParserToESTree.js').JsdocDescriptionLine|
* import('./commentParserToESTree.js').JsdocTypeLine|
* import('./commentParserToESTree.js').JsdocTag}
* @type {import('./commentParserToESTree').JsdocBlock|
* import('./commentParserToESTree').JsdocDescriptionLine|
* import('./commentParserToESTree').JsdocTypeLine|
* import('./commentParserToESTree').JsdocTag}
*/

@@ -171,5 +74,3 @@ (node).type

node,
opts,
// @ts-expect-error
...args
opts
);

@@ -182,3 +83,3 @@ }

? ''
: `{${stringify(
: `{${prattStringify(
/** @type {import('jsdoc-type-pratt-parser').RootResult} */ (

@@ -193,2 +94,93 @@ node

export default estreeToString;
/**
* @param {import('./commentParserToESTree').JsdocBlock} node
* @param {import('.').ESTreeToStringOptions} opts
* @returns {string}
*/
function JsdocBlock (node, opts) {
const {delimiter, delimiterLineBreak, descriptionLines,
initial, postDelimiter, preterminalLineBreak, tags, terminal} = node;
const terminalPrepend = preterminalLineBreak !== ''
? `${preterminalLineBreak}${initial} `
: '';
let result = `${initial}${delimiter}${postDelimiter}${delimiterLineBreak}`;
for (let i = 0; i < descriptionLines.length; i++) {
result += estreeToString(descriptionLines[i]);
if (i !== descriptionLines.length - 1 || tags.length) {
result += '\n';
}
}
for (let i = 0; i < tags.length; i++) {
result += estreeToString(tags[i], opts);
if (i !== tags.length - 1) {
result += '\n';
}
}
result += `${terminalPrepend}${terminal}`;
return result;
}
/**
* @param {import('./commentParserToESTree').JsdocTag} node
* @param {import('.').ESTreeToStringOptions} opts
* @returns {string}
*/
function JsdocTag (node, opts) {
const {
delimiter, descriptionLines, initial, name, parsedType, postDelimiter,
postName, postTag, postType, tag, typeLines
} = node;
let result = `${initial}${delimiter}${postDelimiter}@${tag}${postTag}`;
// Could do `rawType` but may have been changed; could also do
// `typeLines` but not as likely to be changed
// parsedType
// Comment this out later in favor of `parsedType`
// We can't use raw `typeLines` as first argument has delimiter on it
if (opts.preferRawType || !parsedType) {
if (typeLines.length) {
result += '{';
for (let i = 0; i < typeLines.length; i++) {
result += estreeToString(typeLines[i]);
if (i !== typeLines.length - 1) {
result += '\n';
}
}
result += '}';
}
} else if (parsedType?.type.startsWith('JsdocType')) {
result += `{${prattStringify(
/** @type {import('jsdoc-type-pratt-parser').RootResult} */ (
parsedType
)
)}}`;
}
result += name ? `${postType}${name}${postName}` : postType;
for (let i = 0; i < descriptionLines.length; i++) {
const descriptionLine = descriptionLines[i];
result += estreeToString(descriptionLine);
if (i !== descriptionLines.length - 1) {
result += '\n';
}
}
return result;
}
export {estreeToString};
/**
* @typedef {import('./commentParserToESTree.js').JsdocInlineTagNoType & {
* @typedef {import('./commentParserToESTree').JsdocInlineTagNoType & {
* start: number,

@@ -10,5 +10,5 @@ * end: number,

* @typedef {import('comment-parser').Spec & {
* line?: import('./commentParserToESTree.js').Integer,
* inlineTags: (import('./commentParserToESTree.js').JsdocInlineTagNoType & {
* line?: import('./commentParserToESTree.js').Integer
* line?: import('./commentParserToESTree').Integer,
* inlineTags: (import('./commentParserToESTree').JsdocInlineTagNoType & {
* line?: import('./commentParserToESTree').Integer
* })[]

@@ -25,4 +25,4 @@ * }} JsdocTagWithInline

* tags: JsdocTagWithInline[],
* inlineTags: (import('./commentParserToESTree.js').JsdocInlineTagNoType & {
* line?: import('./commentParserToESTree.js').Integer
* inlineTags: (import('./commentParserToESTree').JsdocInlineTagNoType & {
* line?: import('./commentParserToESTree').Integer
* })[]

@@ -39,3 +39,3 @@ * }} JsdocBlockWithInline

* @param {string} commentSelector
* @param {import('./index.js').JsdocBlockWithInline} jsdoc
* @param {import('.').JsdocBlockWithInline} jsdoc
* @returns {boolean}

@@ -48,14 +48,7 @@ */

export {default as commentHandler} from './commentHandler.js';
export {default as toCamelCase} from './toCamelCase.js';
export * from './parseComment.js';
export {default as parseInlineTags} from './parseInlineTags.js';
export * from './commentHandler.js';
export * from './commentParserToESTree.js';
export * from './estreeToString.js';
export * from './jsdoccomment.js';
export {default as estreeToString} from './estreeToString.js';
export * from './parseComment.js';
export * from './parseInlineTags.js';

@@ -1,2 +0,1 @@

/* eslint-disable jsdoc/imports-as-dependencies -- https://github.com/gajus/eslint-plugin-jsdoc/issues/1114 */
/**

@@ -71,3 +70,3 @@ * Obtained originally from {@link https://github.com/eslint/eslint/blob/master/lib/util/source-code.js#L313}.

const {parent} = astNode;
/* c8 ignore next 3 */
/* v8 ignore next 3 */
if (!parent) {

@@ -77,3 +76,3 @@ return astNode;

const grandparent = parent.parent;
/* c8 ignore next 3 */
/* v8 ignore next 3 */
if (!grandparent) {

@@ -85,3 +84,3 @@ return astNode;

// istanbul ignore if
/* v8 ignore next 3 */
if (/** @type {ESLintOrTSNode} */ (parent).type !== 'TSTypeAnnotation') {

@@ -92,3 +91,3 @@ return astNode;

switch (/** @type {ESLintOrTSNode} */ (grandparent).type) {
// @ts-expect-error
// @ts-expect-error -- For `ClassProperty`.
case 'PropertyDefinition': case 'ClassProperty':

@@ -100,7 +99,7 @@ case 'TSDeclareFunction':

case 'ArrowFunctionExpression':
/* c8 ignore next 3 */
/* v8 ignore next 3 */
if (!greatGrandparent) {
return astNode;
}
// istanbul ignore else
if (

@@ -111,3 +110,3 @@ greatGrandparent.type === 'VariableDeclarator'

) {
/* c8 ignore next 3 */
/* v8 ignore next 3 */
if (!greatGreatGrandparent || !greatGreatGrandparent.parent) {

@@ -119,10 +118,10 @@ return astNode;

// istanbul ignore next
/* v8 ignore next */
return astNode;
case 'FunctionExpression':
/* c8 ignore next 3 */
/* v8 ignore next 3 */
if (!greatGreatGrandparent) {
return astNode;
}
// istanbul ignore else
/* v8 ignore next 3 */
if (greatGrandparent.type === 'MethodDefinition') {

@@ -134,5 +133,4 @@ return greatGrandparent;

default:
// istanbul ignore if
/* v8 ignore next 3 */
if (grandparent.type !== 'Identifier') {
// istanbul ignore next
return astNode;

@@ -142,3 +140,3 @@ }

/* c8 ignore next 3 */
/* v8 ignore next 3 */
if (!greatGreatGrandparent) {

@@ -148,6 +146,6 @@ return astNode;

// istanbul ignore next
/* v8 ignore next */
switch (greatGrandparent.type) {
case 'ArrowFunctionExpression':
// istanbul ignore else
/* v8 ignore next 6 */
if (

@@ -160,3 +158,3 @@ greatGreatGrandparent.type === 'VariableDeclarator' &&

// istanbul ignore next
/* v8 ignore next */
return astNode;

@@ -166,3 +164,3 @@ case 'FunctionDeclaration':

case 'VariableDeclarator':
// istanbul ignore else
/* v8 ignore next 3 */
if (greatGreatGrandparent.type === 'VariableDeclaration') {

@@ -174,3 +172,3 @@ return greatGreatGrandparent;

default:
// istanbul ignore next
/* v8 ignore next */
return astNode;

@@ -216,3 +214,3 @@ }

case 'FunctionDeclaration':
/* c8 ignore next 3 */
/* v8 ignore next 3 */
if (!parent) {

@@ -229,3 +227,3 @@ return node;

case 'FunctionExpression':
/* c8 ignore next 3 */
/* v8 ignore next 3 */
if (!parent) {

@@ -335,3 +333,3 @@ return node;

/* c8 ignore next 3 */
/* v8 ignore next 3 */
if (!tokenBefore || !currentNode.loc || !tokenBefore.loc) {

@@ -338,0 +336,0 @@ return null;

@@ -7,3 +7,3 @@ /* eslint-disable prefer-named-capture-group -- Temporary */

import parseInlineTags from './parseInlineTags.js';
import {parseInlineTags} from './parseInlineTags.js';

@@ -149,3 +149,3 @@ const {

* @param {string} [indent] Whitespace
* @returns {import('./index.js').JsdocBlockWithInline}
* @returns {import('.').JsdocBlockWithInline}
*/

@@ -165,2 +165,6 @@ const parseComment = (commentOrNode, indent = '') => {

case 'object':
if (commentOrNode === null) {
throw new TypeError(`'commentOrNode' is not a string or object.`);
}
// Preserve JSDoc block start/end indentation.

@@ -167,0 +171,0 @@ [block] = commentParser(`${indent}/*${commentOrNode.value}*/`, {

@@ -27,12 +27,8 @@ /**

/**
* @typedef {import('./index.js').InlineTag} InlineTag
*/
/**
* Extracts inline tags from a description.
* @param {string} description
* @returns {InlineTag[]} Array of inline tags from the description.
* @returns {import('.').InlineTag[]} Array of inline tags from the description.
*/
function parseDescription (description) {
/** @type {InlineTag[]} */
/** @type {import('.').InlineTag[]} */
const result = [];

@@ -87,9 +83,9 @@

* @param {import('comment-parser').Block} block
* @returns {import('./index.js').JsdocBlockWithInline}
* @returns {import('.').JsdocBlockWithInline}
*/
export default function parseInlineTags (block) {
export function parseInlineTags (block) {
const inlineTags =
/**
* @type {(import('./commentParserToESTree.js').JsdocInlineTagNoType & {
* line?: import('./commentParserToESTree.js').Integer
* @type {(import('./commentParserToESTree').JsdocInlineTagNoType & {
* line?: import('./commentParserToESTree').Integer
* })[]}

@@ -100,3 +96,3 @@ */ (

/** @type {import('./index.js').JsdocBlockWithInline} */ (
/** @type {import('.').JsdocBlockWithInline} */ (
block

@@ -107,3 +103,3 @@ ).inlineTags = inlineTags;

/**
* @type {import('./index.js').JsdocTagWithInline}
* @type {import('.').JsdocTagWithInline}
*/ (tag).inlineTags = parseDescription(tag.description);

@@ -113,5 +109,5 @@ }

/**
* @type {import('./index.js').JsdocBlockWithInline}
* @type {import('.').JsdocBlockWithInline}
*/ (block)
);
}

@@ -13,2 +13,2 @@ /**

export default toCamelCase;
export {toCamelCase};

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc