Addnew sheets (armor, weapons, malefica) and v13 support
This commit is contained in:
39
node_modules/@es-joy/jsdoccomment/src/commentHandler.js
generated
vendored
Normal file
39
node_modules/@es-joy/jsdoccomment/src/commentHandler.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import esquery from 'esquery';
|
||||
|
||||
import {
|
||||
visitorKeys as jsdocTypePrattParserVisitorKeys
|
||||
} from 'jsdoc-type-pratt-parser';
|
||||
|
||||
import {
|
||||
commentParserToESTree, jsdocVisitorKeys
|
||||
} from './commentParserToESTree.js';
|
||||
|
||||
/**
|
||||
* @param {{[name: string]: any}} settings
|
||||
* @returns {import('.').CommentHandler}
|
||||
*/
|
||||
const commentHandler = (settings) => {
|
||||
/**
|
||||
* @type {import('.').CommentHandler}
|
||||
*/
|
||||
return (commentSelector, jsdoc) => {
|
||||
const {mode} = settings;
|
||||
|
||||
const selector = esquery.parse(commentSelector);
|
||||
|
||||
const ast = commentParserToESTree(jsdoc, mode);
|
||||
|
||||
const _ast = /** @type {unknown} */ (ast);
|
||||
|
||||
return esquery.matches(/** @type {import('estree').Node} */ (
|
||||
_ast
|
||||
), selector, undefined, {
|
||||
visitorKeys: {
|
||||
...jsdocTypePrattParserVisitorKeys,
|
||||
...jsdocVisitorKeys
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export {commentHandler};
|
||||
504
node_modules/@es-joy/jsdoccomment/src/commentParserToESTree.js
generated
vendored
Normal file
504
node_modules/@es-joy/jsdoccomment/src/commentParserToESTree.js
generated
vendored
Normal file
@@ -0,0 +1,504 @@
|
||||
import {parse as jsdocTypePrattParse} from 'jsdoc-type-pratt-parser';
|
||||
|
||||
/**
|
||||
* Removes initial and ending brackets from `rawType`
|
||||
* @param {JsdocTypeLine[]|JsdocTag} container
|
||||
* @param {boolean} [isArr]
|
||||
* @returns {void}
|
||||
*/
|
||||
const stripEncapsulatingBrackets = (container, isArr) => {
|
||||
if (isArr) {
|
||||
const firstItem = /** @type {JsdocTypeLine[]} */ (container)[0];
|
||||
firstItem.rawType = firstItem.rawType.replace(
|
||||
/^\{/u, ''
|
||||
);
|
||||
|
||||
const lastItem = /** @type {JsdocTypeLine} */ (
|
||||
/** @type {JsdocTypeLine[]} */ (
|
||||
container
|
||||
).at(-1)
|
||||
);
|
||||
lastItem.rawType = lastItem.rawType.replace(/\}$/u, '');
|
||||
|
||||
return;
|
||||
}
|
||||
/** @type {JsdocTag} */ (container).rawType =
|
||||
/** @type {JsdocTag} */ (container).rawType.replace(
|
||||
/^\{/u, ''
|
||||
).replace(/\}$/u, '');
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* delimiter: string,
|
||||
* postDelimiter: string,
|
||||
* rawType: string,
|
||||
* initial: string,
|
||||
* type: "JsdocTypeLine"
|
||||
* }} JsdocTypeLine
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* delimiter: string,
|
||||
* description: string,
|
||||
* postDelimiter: string,
|
||||
* initial: string,
|
||||
* type: "JsdocDescriptionLine"
|
||||
* }} JsdocDescriptionLine
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* format: 'pipe' | 'plain' | 'prefix' | 'space',
|
||||
* namepathOrURL: string,
|
||||
* tag: string,
|
||||
* text: string,
|
||||
* }} JsdocInlineTagNoType
|
||||
*/
|
||||
/**
|
||||
* @typedef {JsdocInlineTagNoType & {
|
||||
* type: "JsdocInlineTag"
|
||||
* }} JsdocInlineTag
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* delimiter: string,
|
||||
* description: string,
|
||||
* descriptionLines: JsdocDescriptionLine[],
|
||||
* initial: string,
|
||||
* inlineTags: JsdocInlineTag[]
|
||||
* name: string,
|
||||
* postDelimiter: string,
|
||||
* postName: string,
|
||||
* postTag: string,
|
||||
* postType: string,
|
||||
* rawType: string,
|
||||
* parsedType: import('jsdoc-type-pratt-parser').RootResult|null
|
||||
* tag: string,
|
||||
* type: "JsdocTag",
|
||||
* typeLines: JsdocTypeLine[],
|
||||
* }} JsdocTag
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {number} Integer
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* 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",
|
||||
* }} JsdocBlock
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {object} cfg
|
||||
* @param {string} cfg.text
|
||||
* @param {string} cfg.tag
|
||||
* @param {'pipe' | 'plain' | 'prefix' | 'space'} cfg.format
|
||||
* @param {string} cfg.namepathOrURL
|
||||
* @returns {JsdocInlineTag}
|
||||
*/
|
||||
const inlineTagToAST = ({text, tag, format, namepathOrURL}) => ({
|
||||
text,
|
||||
tag,
|
||||
format,
|
||||
namepathOrURL,
|
||||
type: 'JsdocInlineTag'
|
||||
});
|
||||
|
||||
/**
|
||||
* 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}
|
||||
*/
|
||||
const commentParserToESTree = (jsdoc, mode, {
|
||||
spacing = 'compact',
|
||||
throwOnTypeParsingErrors = false
|
||||
} = {}) => {
|
||||
/**
|
||||
* Strips brackets from a tag's `rawType` values and adds `parsedType`
|
||||
* @param {JsdocTag} lastTag
|
||||
* @returns {void}
|
||||
*/
|
||||
const cleanUpLastTag = (lastTag) => {
|
||||
// Strip out `}` that encapsulates and is not part of
|
||||
// the type
|
||||
stripEncapsulatingBrackets(lastTag);
|
||||
|
||||
if (lastTag.typeLines.length) {
|
||||
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
|
||||
let parsedType = null;
|
||||
|
||||
try {
|
||||
parsedType = jsdocTypePrattParse(lastTag.rawType, mode);
|
||||
} catch (err) {
|
||||
// Ignore
|
||||
if (lastTag.rawType && throwOnTypeParsingErrors) {
|
||||
/** @type {Error} */ (
|
||||
err
|
||||
).message = `Tag @${lastTag.tag} with raw type ` +
|
||||
`\`${lastTag.rawType}\` had parsing error: ${
|
||||
/** @type {Error} */ (err).message}`;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
lastTag.parsedType = parsedType;
|
||||
};
|
||||
|
||||
const {source, inlineTags: blockInlineTags} = jsdoc;
|
||||
|
||||
const {tokens: {
|
||||
delimiter: delimiterRoot,
|
||||
lineEnd: lineEndRoot,
|
||||
postDelimiter: postDelimiterRoot,
|
||||
start: startRoot,
|
||||
end: endRoot
|
||||
}} = source[0];
|
||||
|
||||
const endLine = source.length - 1;
|
||||
|
||||
/** @type {JsdocBlock} */
|
||||
const ast = {
|
||||
delimiter: delimiterRoot,
|
||||
delimiterLineBreak: '\n',
|
||||
description: '',
|
||||
|
||||
descriptionLines: [],
|
||||
inlineTags: blockInlineTags.map((t) => inlineTagToAST(t)),
|
||||
|
||||
initial: startRoot,
|
||||
tags: [],
|
||||
// `terminal` will be overwritten if there are other entries
|
||||
terminal: endRoot,
|
||||
preterminalLineBreak: '\n',
|
||||
hasPreterminalDescription: 0,
|
||||
endLine,
|
||||
postDelimiter: postDelimiterRoot,
|
||||
lineEnd: lineEndRoot,
|
||||
|
||||
type: 'JsdocBlock'
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {JsdocTag[]}
|
||||
*/
|
||||
const tags = [];
|
||||
|
||||
/** @type {Integer|undefined} */
|
||||
let lastDescriptionLine;
|
||||
|
||||
/** @type {JsdocTag|null} */
|
||||
let lastTag = null;
|
||||
|
||||
// Tracks when first valid tag description line is seen.
|
||||
let tagDescriptionSeen = false;
|
||||
|
||||
let descLineStateOpen = true;
|
||||
|
||||
source.forEach((info, idx) => {
|
||||
const {tokens} = info;
|
||||
const {
|
||||
delimiter,
|
||||
description,
|
||||
postDelimiter,
|
||||
start: initial,
|
||||
tag,
|
||||
end,
|
||||
type: rawType
|
||||
} = tokens;
|
||||
|
||||
if (!tag && description && descLineStateOpen) {
|
||||
if (ast.descriptionStartLine === undefined) {
|
||||
ast.descriptionStartLine = idx;
|
||||
}
|
||||
ast.descriptionEndLine = idx;
|
||||
}
|
||||
|
||||
if (tag || end) {
|
||||
descLineStateOpen = false;
|
||||
if (lastDescriptionLine === undefined) {
|
||||
lastDescriptionLine = idx;
|
||||
}
|
||||
|
||||
// Clean-up with last tag before end or new tag
|
||||
if (lastTag) {
|
||||
cleanUpLastTag(lastTag);
|
||||
}
|
||||
|
||||
// Stop the iteration when we reach the end
|
||||
// but only when there is no tag earlier in the line
|
||||
// to still process
|
||||
if (end && !tag) {
|
||||
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) {
|
||||
ast.hasPreterminalTagDescription = 1;
|
||||
} else {
|
||||
ast.hasPreterminalDescription = 1;
|
||||
}
|
||||
|
||||
const holder = lastTag || ast;
|
||||
holder.description += (holder.description ? '\n' : '') + description;
|
||||
|
||||
// Do not include `delimiter` / `postDelimiter` for opening
|
||||
// delimiter line.
|
||||
|
||||
holder.descriptionLines.push({
|
||||
delimiter: isDelimiterLine ? '' : delimiter,
|
||||
description,
|
||||
postDelimiter: isDelimiterLine ? '' : postDelimiter,
|
||||
initial,
|
||||
type: 'JsdocDescriptionLine'
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
// eslint-disable-next-line no-unused-vars -- Discarding
|
||||
end: ed,
|
||||
delimiter: de,
|
||||
postDelimiter: pd,
|
||||
start: init,
|
||||
...tkns
|
||||
} = tokens;
|
||||
|
||||
if (!tokens.name) {
|
||||
let i = 1;
|
||||
while (source[idx + i]) {
|
||||
const {tokens: {
|
||||
name,
|
||||
postName,
|
||||
postType,
|
||||
tag: tg
|
||||
}} = source[idx + i];
|
||||
if (tg) {
|
||||
break;
|
||||
}
|
||||
if (name) {
|
||||
tkns.postType = postType;
|
||||
tkns.name = name;
|
||||
tkns.postName = postName;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {JsdocInlineTag[]}
|
||||
*/
|
||||
let tagInlineTags = [];
|
||||
if (tag) {
|
||||
// Assuming the tags from `source` are in the same order as `jsdoc.tags`
|
||||
// we can use the `tags` length as index into the parser result tags.
|
||||
tagInlineTags =
|
||||
/**
|
||||
* @type {import('comment-parser').Spec & {
|
||||
* inlineTags: JsdocInlineTagNoType[]
|
||||
* }}
|
||||
*/ (
|
||||
jsdoc.tags[tags.length]
|
||||
).inlineTags.map(
|
||||
(t) => inlineTagToAST(t)
|
||||
);
|
||||
}
|
||||
|
||||
/** @type {JsdocTag} */
|
||||
const tagObj = {
|
||||
...tkns,
|
||||
initial: endLine ? init : '',
|
||||
postDelimiter: lastDescriptionLine ? pd : '',
|
||||
delimiter: lastDescriptionLine ? de : '',
|
||||
descriptionLines: [],
|
||||
inlineTags: tagInlineTags,
|
||||
parsedType: null,
|
||||
rawType: '',
|
||||
type: 'JsdocTag',
|
||||
typeLines: []
|
||||
};
|
||||
tagObj.tag = tagObj.tag.replace(/^@/u, '');
|
||||
|
||||
lastTag = tagObj;
|
||||
tagDescriptionSeen = false;
|
||||
|
||||
tags.push(tagObj);
|
||||
}
|
||||
|
||||
if (rawType) {
|
||||
// Will strip rawType brackets after this tag
|
||||
/** @type {JsdocTag} */ (lastTag).typeLines.push(
|
||||
/** @type {JsdocTag} */ (lastTag).typeLines.length
|
||||
? {
|
||||
delimiter,
|
||||
postDelimiter,
|
||||
rawType,
|
||||
initial,
|
||||
type: 'JsdocTypeLine'
|
||||
}
|
||||
: {
|
||||
delimiter: '',
|
||||
postDelimiter: '',
|
||||
rawType,
|
||||
initial: '',
|
||||
type: 'JsdocTypeLine'
|
||||
}
|
||||
);
|
||||
/** @type {JsdocTag} */ (lastTag).rawType += /** @type {JsdocTag} */ (
|
||||
lastTag
|
||||
).rawType
|
||||
? '\n' + rawType
|
||||
: rawType;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// 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: isFirstDescriptionLine ? '' : postDelimiter,
|
||||
initial: isFirstDescriptionLine ? '' : initial,
|
||||
type: 'JsdocDescriptionLine'
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
holder.descriptionLines.push({
|
||||
delimiter: isDelimiterLine ? '' : delimiter,
|
||||
description,
|
||||
postDelimiter: isDelimiterLine ? '' : postDelimiter,
|
||||
initial: isDelimiterLine ? `` : initial,
|
||||
type: 'JsdocDescriptionLine'
|
||||
});
|
||||
}
|
||||
|
||||
if (!tag) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean-up where last line itself has tag content
|
||||
if (end && tag) {
|
||||
ast.terminal = end;
|
||||
ast.hasPreterminalTagDescription = 1;
|
||||
|
||||
// Remove terminal line break at end when tag is defined on last line.
|
||||
if (ast.terminal === '*/') {
|
||||
ast.preterminalLineBreak = '';
|
||||
}
|
||||
|
||||
cleanUpLastTag(/** @type {JsdocTag} */ (lastTag));
|
||||
}
|
||||
});
|
||||
|
||||
ast.lastDescriptionLine = lastDescriptionLine;
|
||||
ast.tags = tags;
|
||||
|
||||
return ast;
|
||||
};
|
||||
|
||||
const jsdocVisitorKeys = {
|
||||
JsdocBlock: ['descriptionLines', 'tags', 'inlineTags'],
|
||||
JsdocDescriptionLine: [],
|
||||
JsdocTypeLine: [],
|
||||
JsdocTag: ['parsedType', 'typeLines', 'descriptionLines', 'inlineTags'],
|
||||
JsdocInlineTag: []
|
||||
};
|
||||
|
||||
export {commentParserToESTree, jsdocVisitorKeys};
|
||||
179
node_modules/@es-joy/jsdoccomment/src/estreeToString.js
generated
vendored
Normal file
179
node_modules/@es-joy/jsdoccomment/src/estreeToString.js
generated
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
import {stringify as prattStringify} from 'jsdoc-type-pratt-parser';
|
||||
|
||||
/** @type {Record<string, Function>} */
|
||||
const stringifiers = {
|
||||
JsdocBlock,
|
||||
|
||||
/**
|
||||
* @param {import('./commentParserToESTree').JsdocDescriptionLine} node
|
||||
* @returns {string}
|
||||
*/
|
||||
JsdocDescriptionLine ({
|
||||
initial, delimiter, postDelimiter, description
|
||||
}) {
|
||||
return `${initial}${delimiter}${postDelimiter}${description}`;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {import('./commentParserToESTree').JsdocTypeLine} node
|
||||
* @returns {string}
|
||||
*/
|
||||
JsdocTypeLine ({
|
||||
initial, delimiter, postDelimiter, rawType
|
||||
}) {
|
||||
return `${initial}${delimiter}${postDelimiter}${rawType}`;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {import('./commentParserToESTree').JsdocInlineTag} node
|
||||
*/
|
||||
JsdocInlineTag ({format, namepathOrURL, tag, text}) {
|
||||
return format === 'pipe'
|
||||
? `{@${tag} ${namepathOrURL}|${text}}`
|
||||
: format === 'plain'
|
||||
? `{@${tag} ${namepathOrURL}}`
|
||||
: format === 'prefix'
|
||||
? `[${text}]{@${tag} ${namepathOrURL}}`
|
||||
// "space"
|
||||
: `{@${tag} ${namepathOrURL} ${text}}`;
|
||||
},
|
||||
|
||||
JsdocTag
|
||||
};
|
||||
|
||||
/**
|
||||
* @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}
|
||||
*/
|
||||
function estreeToString (node, opts = {}) {
|
||||
if (Object.prototype.hasOwnProperty.call(stringifiers, node.type)) {
|
||||
return stringifiers[
|
||||
/**
|
||||
* @type {import('./commentParserToESTree').JsdocBlock|
|
||||
* import('./commentParserToESTree').JsdocDescriptionLine|
|
||||
* import('./commentParserToESTree').JsdocTypeLine|
|
||||
* import('./commentParserToESTree').JsdocTag}
|
||||
*/
|
||||
(node).type
|
||||
](
|
||||
node,
|
||||
opts
|
||||
);
|
||||
}
|
||||
|
||||
// We use raw type instead but it is a key as other apps may wish to traverse
|
||||
if (node.type.startsWith('JsdocType')) {
|
||||
return opts.preferRawType
|
||||
? ''
|
||||
: `{${prattStringify(
|
||||
/** @type {import('jsdoc-type-pratt-parser').RootResult} */ (
|
||||
node
|
||||
)
|
||||
)}}`;
|
||||
}
|
||||
|
||||
throw new Error(`Unhandled node type: ${node.type}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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};
|
||||
50
node_modules/@es-joy/jsdoccomment/src/index.js
generated
vendored
Normal file
50
node_modules/@es-joy/jsdoccomment/src/index.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @typedef {import('./commentParserToESTree').JsdocInlineTagNoType & {
|
||||
* start: number,
|
||||
* end: number,
|
||||
* }} InlineTag
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {import('comment-parser').Spec & {
|
||||
* line?: import('./commentParserToESTree').Integer,
|
||||
* inlineTags: (import('./commentParserToESTree').JsdocInlineTagNoType & {
|
||||
* line?: import('./commentParserToESTree').Integer
|
||||
* })[]
|
||||
* }} JsdocTagWithInline
|
||||
*/
|
||||
|
||||
/**
|
||||
* Expands on comment-parser's `Block` interface.
|
||||
* @typedef {{
|
||||
* description: string,
|
||||
* source: import('comment-parser').Line[],
|
||||
* problems: import('comment-parser').Problem[],
|
||||
* tags: JsdocTagWithInline[],
|
||||
* inlineTags: (import('./commentParserToESTree').JsdocInlineTagNoType & {
|
||||
* line?: import('./commentParserToESTree').Integer
|
||||
* })[]
|
||||
* }} JsdocBlockWithInline
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{preferRawType?: boolean}} ESTreeToStringOptions
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback CommentHandler
|
||||
* @param {string} commentSelector
|
||||
* @param {import('.').JsdocBlockWithInline} jsdoc
|
||||
* @returns {boolean}
|
||||
*/
|
||||
|
||||
export {visitorKeys as jsdocTypeVisitorKeys} from 'jsdoc-type-pratt-parser';
|
||||
|
||||
export * from 'jsdoc-type-pratt-parser';
|
||||
|
||||
export * from './commentHandler.js';
|
||||
export * from './commentParserToESTree.js';
|
||||
export * from './estreeToString.js';
|
||||
export * from './jsdoccomment.js';
|
||||
export * from './parseComment.js';
|
||||
export * from './parseInlineTags.js';
|
||||
487
node_modules/@es-joy/jsdoccomment/src/jsdoccomment.js
generated
vendored
Normal file
487
node_modules/@es-joy/jsdoccomment/src/jsdoccomment.js
generated
vendored
Normal file
@@ -0,0 +1,487 @@
|
||||
/**
|
||||
* Obtained originally from {@link https://github.com/eslint/eslint/blob/master/lib/util/source-code.js#L313}.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {import('eslint').AST.Token | import('estree').Comment | {
|
||||
* type: import('eslint').AST.TokenType|"Line"|"Block"|"Shebang",
|
||||
* range: [number, number],
|
||||
* value: string
|
||||
* }} Token
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {import('eslint').Rule.Node|
|
||||
* import('@typescript-eslint/types').TSESTree.Node} ESLintOrTSNode
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {number} int
|
||||
*/
|
||||
|
||||
/**
|
||||
* Checks if the given token is a comment token or not.
|
||||
*
|
||||
* @param {Token} token - The token to check.
|
||||
* @returns {boolean} `true` if the token is a comment token.
|
||||
*/
|
||||
const isCommentToken = (token) => {
|
||||
return token.type === 'Line' || token.type === 'Block' ||
|
||||
token.type === 'Shebang';
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {(ESLintOrTSNode|import('estree').Comment) & {
|
||||
* declaration?: any,
|
||||
* decorators?: any[],
|
||||
* parent?: import('eslint').Rule.Node & {
|
||||
* decorators?: any[]
|
||||
* }
|
||||
* }} node
|
||||
* @returns {import('@typescript-eslint/types').TSESTree.Decorator|undefined}
|
||||
*/
|
||||
const getDecorator = (node) => {
|
||||
return node?.declaration?.decorators?.[0] || node?.decorators?.[0] ||
|
||||
node?.parent?.decorators?.[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Check to see if it is a ES6 export declaration.
|
||||
*
|
||||
* @param {ESLintOrTSNode} astNode An AST node.
|
||||
* @returns {boolean} whether the given node represents an export declaration.
|
||||
* @private
|
||||
*/
|
||||
const looksLikeExport = function (astNode) {
|
||||
return astNode.type === 'ExportDefaultDeclaration' ||
|
||||
astNode.type === 'ExportNamedDeclaration' ||
|
||||
astNode.type === 'ExportAllDeclaration' ||
|
||||
astNode.type === 'ExportSpecifier';
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ESLintOrTSNode} astNode
|
||||
* @returns {ESLintOrTSNode}
|
||||
*/
|
||||
const getTSFunctionComment = function (astNode) {
|
||||
const {parent} = astNode;
|
||||
/* v8 ignore next 3 */
|
||||
if (!parent) {
|
||||
return astNode;
|
||||
}
|
||||
const grandparent = parent.parent;
|
||||
/* v8 ignore next 3 */
|
||||
if (!grandparent) {
|
||||
return astNode;
|
||||
}
|
||||
const greatGrandparent = grandparent.parent;
|
||||
const greatGreatGrandparent = greatGrandparent && greatGrandparent.parent;
|
||||
|
||||
/* v8 ignore next 3 */
|
||||
if (/** @type {ESLintOrTSNode} */ (parent).type !== 'TSTypeAnnotation') {
|
||||
return astNode;
|
||||
}
|
||||
|
||||
switch (/** @type {ESLintOrTSNode} */ (grandparent).type) {
|
||||
// @ts-expect-error -- For `ClassProperty`.
|
||||
case 'PropertyDefinition': case 'ClassProperty':
|
||||
case 'TSDeclareFunction':
|
||||
case 'TSMethodSignature':
|
||||
case 'TSPropertySignature':
|
||||
return grandparent;
|
||||
case 'ArrowFunctionExpression':
|
||||
/* v8 ignore next 3 */
|
||||
if (!greatGrandparent) {
|
||||
return astNode;
|
||||
}
|
||||
|
||||
if (
|
||||
greatGrandparent.type === 'VariableDeclarator'
|
||||
|
||||
// && greatGreatGrandparent.parent.type === 'VariableDeclaration'
|
||||
) {
|
||||
/* v8 ignore next 3 */
|
||||
if (!greatGreatGrandparent || !greatGreatGrandparent.parent) {
|
||||
return astNode;
|
||||
}
|
||||
return greatGreatGrandparent.parent;
|
||||
}
|
||||
/* v8 ignore next */
|
||||
return astNode;
|
||||
case 'FunctionExpression':
|
||||
/* v8 ignore next 3 */
|
||||
if (!greatGreatGrandparent) {
|
||||
return astNode;
|
||||
}
|
||||
if (greatGrandparent.type === 'MethodDefinition') {
|
||||
return greatGrandparent;
|
||||
}
|
||||
|
||||
// Fallthrough
|
||||
default:
|
||||
/* v8 ignore next 3 */
|
||||
if (grandparent.type !== 'Identifier') {
|
||||
return astNode;
|
||||
}
|
||||
}
|
||||
|
||||
/* v8 ignore next 3 */
|
||||
if (!greatGreatGrandparent) {
|
||||
return astNode;
|
||||
}
|
||||
|
||||
switch (greatGrandparent.type) {
|
||||
case 'ArrowFunctionExpression':
|
||||
if (
|
||||
greatGreatGrandparent.type === 'VariableDeclarator' &&
|
||||
greatGreatGrandparent.parent.type === 'VariableDeclaration'
|
||||
) {
|
||||
return greatGreatGrandparent.parent;
|
||||
}
|
||||
|
||||
return astNode;
|
||||
case 'FunctionDeclaration':
|
||||
return greatGrandparent;
|
||||
case 'VariableDeclarator':
|
||||
if (greatGreatGrandparent.type === 'VariableDeclaration') {
|
||||
return greatGreatGrandparent;
|
||||
}
|
||||
/* v8 ignore next 2 */
|
||||
// Fallthrough
|
||||
default:
|
||||
/* v8 ignore next 3 */
|
||||
return astNode;
|
||||
}
|
||||
};
|
||||
|
||||
const invokedExpression = new Set(
|
||||
['CallExpression', 'OptionalCallExpression', 'NewExpression']
|
||||
);
|
||||
const allowableCommentNode = new Set([
|
||||
'AssignmentPattern',
|
||||
'VariableDeclaration',
|
||||
'ExpressionStatement',
|
||||
'MethodDefinition',
|
||||
'Property',
|
||||
'ObjectProperty',
|
||||
'ClassProperty',
|
||||
'PropertyDefinition',
|
||||
'ExportDefaultDeclaration',
|
||||
'ReturnStatement'
|
||||
]);
|
||||
|
||||
/**
|
||||
* Reduces the provided node to the appropriate node for evaluating
|
||||
* JSDoc comment status.
|
||||
*
|
||||
* @param {ESLintOrTSNode} node An AST node.
|
||||
* @param {import('eslint').SourceCode} sourceCode The ESLint SourceCode.
|
||||
* @returns {ESLintOrTSNode} The AST node that
|
||||
* can be evaluated for appropriate JSDoc comments.
|
||||
*/
|
||||
const getReducedASTNode = function (node, sourceCode) {
|
||||
let {parent} = node;
|
||||
|
||||
switch (/** @type {ESLintOrTSNode} */ (node).type) {
|
||||
case 'TSFunctionType':
|
||||
return getTSFunctionComment(node);
|
||||
case 'TSInterfaceDeclaration':
|
||||
case 'TSTypeAliasDeclaration':
|
||||
case 'TSEnumDeclaration':
|
||||
case 'ClassDeclaration':
|
||||
case 'FunctionDeclaration':
|
||||
/* v8 ignore next 3 */
|
||||
if (!parent) {
|
||||
return node;
|
||||
}
|
||||
return looksLikeExport(parent) ? parent : node;
|
||||
|
||||
case 'TSDeclareFunction':
|
||||
case 'ClassExpression':
|
||||
case 'ObjectExpression':
|
||||
case 'ArrowFunctionExpression':
|
||||
case 'TSEmptyBodyFunctionExpression':
|
||||
case 'FunctionExpression':
|
||||
/* v8 ignore next 3 */
|
||||
if (!parent) {
|
||||
return node;
|
||||
}
|
||||
if (
|
||||
!invokedExpression.has(parent.type)
|
||||
) {
|
||||
/**
|
||||
* @type {ESLintOrTSNode|Token|null}
|
||||
*/
|
||||
let token = node;
|
||||
do {
|
||||
token = sourceCode.getTokenBefore(
|
||||
/** @type {import('eslint').Rule.Node|import('eslint').AST.Token} */ (
|
||||
token
|
||||
),
|
||||
{includeComments: true}
|
||||
);
|
||||
} while (token && token.type === 'Punctuator' && token.value === '(');
|
||||
if (token && token.type === 'Block') {
|
||||
return node;
|
||||
}
|
||||
|
||||
if (sourceCode.getCommentsBefore(
|
||||
/** @type {import('eslint').Rule.Node} */
|
||||
(node)
|
||||
).length) {
|
||||
return node;
|
||||
}
|
||||
|
||||
while (
|
||||
!sourceCode.getCommentsBefore(
|
||||
/** @type {import('eslint').Rule.Node} */
|
||||
(parent)
|
||||
).length &&
|
||||
!(/Function/u).test(parent.type) &&
|
||||
!allowableCommentNode.has(parent.type)
|
||||
) {
|
||||
({parent} = parent);
|
||||
|
||||
if (!parent) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parent && parent.type !== 'FunctionDeclaration' &&
|
||||
parent.type !== 'Program'
|
||||
) {
|
||||
if (parent.parent && parent.parent.type === 'ExportNamedDeclaration') {
|
||||
return parent.parent;
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
|
||||
default:
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks for the presence of a JSDoc comment for the given node and returns it.
|
||||
*
|
||||
* @param {ESLintOrTSNode} astNode The AST node to get
|
||||
* the comment for.
|
||||
* @param {import('eslint').SourceCode} sourceCode
|
||||
* @param {{maxLines: int, minLines: int, [name: string]: any}} settings
|
||||
* @param {{nonJSDoc?: boolean}} [opts]
|
||||
* @returns {Token|null} The Block comment token containing the JSDoc comment
|
||||
* for the given node or null if not found.
|
||||
*/
|
||||
const findJSDocComment = (astNode, sourceCode, settings, opts = {}) => {
|
||||
const {nonJSDoc} = opts;
|
||||
const {minLines, maxLines} = settings;
|
||||
|
||||
/** @type {ESLintOrTSNode|import('estree').Comment} */
|
||||
let currentNode = astNode;
|
||||
let tokenBefore = null;
|
||||
let parenthesisToken = null;
|
||||
|
||||
while (currentNode) {
|
||||
const decorator = getDecorator(
|
||||
/** @type {import('eslint').Rule.Node} */
|
||||
(currentNode)
|
||||
);
|
||||
if (decorator) {
|
||||
const dec = /** @type {unknown} */ (decorator);
|
||||
currentNode = /** @type {import('eslint').Rule.Node} */ (dec);
|
||||
}
|
||||
tokenBefore = sourceCode.getTokenBefore(
|
||||
/** @type {import('eslint').Rule.Node} */
|
||||
(currentNode),
|
||||
{includeComments: true}
|
||||
);
|
||||
if (
|
||||
tokenBefore && tokenBefore.type === 'Punctuator' &&
|
||||
tokenBefore.value === '('
|
||||
) {
|
||||
parenthesisToken = tokenBefore;
|
||||
[tokenBefore] = sourceCode.getTokensBefore(
|
||||
/** @type {import('eslint').Rule.Node} */
|
||||
(currentNode),
|
||||
{
|
||||
count: 2,
|
||||
includeComments: true
|
||||
}
|
||||
);
|
||||
}
|
||||
if (!tokenBefore || !isCommentToken(tokenBefore)) {
|
||||
return null;
|
||||
}
|
||||
if (!nonJSDoc && tokenBefore.type === 'Line') {
|
||||
currentNode = tokenBefore;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* v8 ignore next 3 */
|
||||
if (!tokenBefore || !currentNode.loc || !tokenBefore.loc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
(
|
||||
(nonJSDoc && (tokenBefore.type !== 'Block' ||
|
||||
!(/^\*\s/u).test(tokenBefore.value))) ||
|
||||
(!nonJSDoc && tokenBefore.type === 'Block' &&
|
||||
(/^\*\s/u).test(tokenBefore.value))
|
||||
) &&
|
||||
currentNode.loc.start.line - (
|
||||
/** @type {import('eslint').AST.Token} */
|
||||
(parenthesisToken ?? tokenBefore)
|
||||
).loc.end.line >= minLines &&
|
||||
currentNode.loc.start.line - (
|
||||
/** @type {import('eslint').AST.Token} */
|
||||
(parenthesisToken ?? tokenBefore)
|
||||
).loc.end.line <= maxLines
|
||||
) {
|
||||
return tokenBefore;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
const getJSDocComment = function (sourceCode, node, settings) {
|
||||
const reducedNode = getReducedASTNode(node, sourceCode);
|
||||
|
||||
return findJSDocComment(reducedNode, sourceCode, settings);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the comment preceding a given node.
|
||||
*
|
||||
* @param {import('eslint').SourceCode} sourceCode The ESLint SourceCode
|
||||
* @param {ESLintOrTSNode} 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
|
||||
*/
|
||||
const getNonJsdocComment = function (sourceCode, node, settings) {
|
||||
const reducedNode = getReducedASTNode(node, sourceCode);
|
||||
|
||||
return findJSDocComment(reducedNode, sourceCode, settings, {
|
||||
nonJSDoc: true
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ESLintOrTSNode|import('eslint').AST.Token|
|
||||
* import('estree').Comment
|
||||
* } nodeA The AST node or token to compare
|
||||
* @param {ESLintOrTSNode|import('eslint').AST.Token|
|
||||
* import('estree').Comment} nodeB The
|
||||
* AST node or token to compare
|
||||
*/
|
||||
const compareLocEndToStart = (nodeA, nodeB) => {
|
||||
/* v8 ignore next */
|
||||
return (nodeA.loc?.end.line ?? 0) === (nodeB.loc?.start.line ?? 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks for the presence of a comment following the given node and
|
||||
* returns it.
|
||||
*
|
||||
* This method is experimental.
|
||||
*
|
||||
* @param {import('eslint').SourceCode} sourceCode
|
||||
* @param {ESLintOrTSNode} astNode The AST node to get
|
||||
* the comment for.
|
||||
* @returns {Token|null} The comment token containing the comment
|
||||
* for the given node or null if not found.
|
||||
*/
|
||||
const getFollowingComment = function (sourceCode, astNode) {
|
||||
/**
|
||||
* @param {ESLintOrTSNode} node The
|
||||
* AST node to get the comment for.
|
||||
*/
|
||||
const getTokensAfterIgnoringSemis = (node) => {
|
||||
let tokenAfter = sourceCode.getTokenAfter(
|
||||
/** @type {import('eslint').Rule.Node} */
|
||||
(node),
|
||||
{includeComments: true}
|
||||
);
|
||||
|
||||
while (
|
||||
tokenAfter && tokenAfter.type === 'Punctuator' &&
|
||||
// tokenAfter.value === ')' // Don't apparently need to ignore
|
||||
tokenAfter.value === ';'
|
||||
) {
|
||||
[tokenAfter] = sourceCode.getTokensAfter(tokenAfter, {
|
||||
includeComments: true
|
||||
});
|
||||
}
|
||||
return tokenAfter;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ESLintOrTSNode} node The
|
||||
* AST node to get the comment for.
|
||||
*/
|
||||
const tokenAfterIgnoringSemis = (node) => {
|
||||
const tokenAfter = getTokensAfterIgnoringSemis(node);
|
||||
return (
|
||||
tokenAfter &&
|
||||
isCommentToken(tokenAfter) &&
|
||||
compareLocEndToStart(node, tokenAfter)
|
||||
)
|
||||
? tokenAfter
|
||||
: null;
|
||||
};
|
||||
|
||||
let tokenAfter = tokenAfterIgnoringSemis(astNode);
|
||||
|
||||
if (!tokenAfter) {
|
||||
switch (astNode.type) {
|
||||
case 'FunctionDeclaration':
|
||||
tokenAfter = tokenAfterIgnoringSemis(
|
||||
/** @type {ESLintOrTSNode} */
|
||||
(astNode.body)
|
||||
);
|
||||
break;
|
||||
case 'ExpressionStatement':
|
||||
tokenAfter = tokenAfterIgnoringSemis(
|
||||
/** @type {ESLintOrTSNode} */
|
||||
(astNode.expression)
|
||||
);
|
||||
break;
|
||||
|
||||
/* v8 ignore next 3 */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return tokenAfter;
|
||||
};
|
||||
|
||||
export {
|
||||
getReducedASTNode, getJSDocComment, getNonJsdocComment,
|
||||
getDecorator, findJSDocComment, getFollowingComment
|
||||
};
|
||||
190
node_modules/@es-joy/jsdoccomment/src/parseComment.js
generated
vendored
Normal file
190
node_modules/@es-joy/jsdoccomment/src/parseComment.js
generated
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
/* eslint-disable prefer-named-capture-group -- Temporary */
|
||||
import {
|
||||
parse as commentParser,
|
||||
tokenizers
|
||||
} from 'comment-parser';
|
||||
|
||||
import {parseInlineTags} from './parseInlineTags.js';
|
||||
|
||||
const {
|
||||
name: nameTokenizer,
|
||||
tag: tagTokenizer,
|
||||
type: typeTokenizer,
|
||||
description: descriptionTokenizer
|
||||
} = tokenizers;
|
||||
|
||||
/**
|
||||
* @param {import('comment-parser').Spec} spec
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const hasSeeWithLink = (spec) => {
|
||||
return spec.tag === 'see' && (/\{@link.+?\}/u).test(spec.source[0].source);
|
||||
};
|
||||
|
||||
export const defaultNoTypes = [
|
||||
'default', 'defaultvalue', 'description', 'example',
|
||||
'file', 'fileoverview', 'license',
|
||||
'overview', 'see', 'summary'
|
||||
];
|
||||
|
||||
export const defaultNoNames = [
|
||||
'access', 'author',
|
||||
'default', 'defaultvalue',
|
||||
'description',
|
||||
'example', 'exception', 'file', 'fileoverview',
|
||||
'kind',
|
||||
'license', 'overview',
|
||||
'return', 'returns',
|
||||
'since', 'summary',
|
||||
'throws',
|
||||
'version', 'variation'
|
||||
];
|
||||
|
||||
const optionalBrackets = /^\[(?<name>[^=]*)=[^\]]*\]/u;
|
||||
const preserveTypeTokenizer = typeTokenizer('preserve');
|
||||
const preserveDescriptionTokenizer = descriptionTokenizer('preserve');
|
||||
const plainNameTokenizer = nameTokenizer();
|
||||
|
||||
/**
|
||||
* 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[]}
|
||||
*/
|
||||
const getTokenizers = ({
|
||||
noTypes = defaultNoTypes,
|
||||
noNames = defaultNoNames
|
||||
} = {}) => {
|
||||
// trim
|
||||
return [
|
||||
// Tag
|
||||
tagTokenizer(),
|
||||
|
||||
/**
|
||||
* Type tokenizer.
|
||||
* @param {import('comment-parser').Spec} spec
|
||||
* @returns {import('comment-parser').Spec}
|
||||
*/
|
||||
(spec) => {
|
||||
if (noTypes.includes(spec.tag)) {
|
||||
return spec;
|
||||
}
|
||||
|
||||
return preserveTypeTokenizer(spec);
|
||||
},
|
||||
|
||||
/**
|
||||
* Name tokenizer.
|
||||
* @param {import('comment-parser').Spec} spec
|
||||
* @returns {import('comment-parser').Spec}
|
||||
*/
|
||||
(spec) => {
|
||||
if (spec.tag === 'template') {
|
||||
// const preWS = spec.postTag;
|
||||
const remainder = spec.source[0].tokens.description;
|
||||
|
||||
let pos;
|
||||
if (remainder.startsWith('[') && remainder.includes(']')) {
|
||||
const endingBracketPos = remainder.indexOf(']');
|
||||
pos = remainder.slice(endingBracketPos).search(/(?<![\s,])\s/u);
|
||||
if (pos > -1) { // Add offset to starting point if space found
|
||||
pos += endingBracketPos;
|
||||
}
|
||||
} else {
|
||||
pos = remainder.search(/(?<![\s,])\s/u);
|
||||
}
|
||||
|
||||
let name = pos === -1 ? remainder : remainder.slice(0, pos);
|
||||
const extra = remainder.slice(pos);
|
||||
let postName = '', description = '', lineEnd = '';
|
||||
if (pos > -1) {
|
||||
[, postName, description, lineEnd] = /** @type {RegExpMatchArray} */ (
|
||||
extra.match(/(\s*)([^\r]*)(\r)?/u)
|
||||
);
|
||||
}
|
||||
|
||||
if (optionalBrackets.test(name)) {
|
||||
name = /** @type {string} */ (
|
||||
/** @type {RegExpMatchArray} */ (
|
||||
name.match(optionalBrackets)
|
||||
)?.groups?.name
|
||||
);
|
||||
spec.optional = true;
|
||||
} else {
|
||||
spec.optional = false;
|
||||
}
|
||||
|
||||
spec.name = name;
|
||||
const {tokens} = spec.source[0];
|
||||
tokens.name = name;
|
||||
tokens.postName = postName;
|
||||
tokens.description = description;
|
||||
tokens.lineEnd = lineEnd || '';
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
if (noNames.includes(spec.tag) || hasSeeWithLink(spec)) {
|
||||
return spec;
|
||||
}
|
||||
|
||||
return plainNameTokenizer(spec);
|
||||
},
|
||||
|
||||
/**
|
||||
* Description tokenizer.
|
||||
* @param {import('comment-parser').Spec} spec
|
||||
* @returns {import('comment-parser').Spec}
|
||||
*/
|
||||
(spec) => {
|
||||
return preserveDescriptionTokenizer(spec);
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* 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}
|
||||
*/
|
||||
const parseComment = (commentOrNode, indent = '') => {
|
||||
let block;
|
||||
|
||||
switch (typeof commentOrNode) {
|
||||
case 'string':
|
||||
// Preserve JSDoc block start/end indentation.
|
||||
[block] = commentParser(`${indent}${commentOrNode}`, {
|
||||
// @see https://github.com/yavorskiy/comment-parser/issues/21
|
||||
tokenizers: getTokenizers()
|
||||
});
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
if (commentOrNode === null) {
|
||||
throw new TypeError(`'commentOrNode' is not a string or object.`);
|
||||
}
|
||||
|
||||
// Preserve JSDoc block start/end indentation.
|
||||
[block] = commentParser(`${indent}/*${commentOrNode.value}*/`, {
|
||||
// @see https://github.com/yavorskiy/comment-parser/issues/21
|
||||
tokenizers: getTokenizers()
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new TypeError(`'commentOrNode' is not a string or object.`);
|
||||
}
|
||||
|
||||
return parseInlineTags(block);
|
||||
};
|
||||
|
||||
export {getTokenizers, parseComment};
|
||||
108
node_modules/@es-joy/jsdoccomment/src/parseInlineTags.js
generated
vendored
Normal file
108
node_modules/@es-joy/jsdoccomment/src/parseInlineTags.js
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @param {RegExpMatchArray & {
|
||||
* indices: {
|
||||
* groups: {
|
||||
* [key: string]: [number, number]
|
||||
* }
|
||||
* }
|
||||
* groups: {[key: string]: string}
|
||||
* }} match An inline tag regexp match.
|
||||
* @returns {'pipe' | 'plain' | 'prefix' | 'space'}
|
||||
*/
|
||||
function determineFormat (match) {
|
||||
const {separator, text} = match.groups;
|
||||
const [, textEnd] = match.indices.groups.text;
|
||||
const [tagStart] = match.indices.groups.tag;
|
||||
if (!text) {
|
||||
return 'plain';
|
||||
} else if (separator === '|') {
|
||||
return 'pipe';
|
||||
} else if (textEnd < tagStart) {
|
||||
return 'prefix';
|
||||
}
|
||||
return 'space';
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts inline tags from a description.
|
||||
* @param {string} description
|
||||
* @returns {import('.').InlineTag[]} Array of inline tags from the description.
|
||||
*/
|
||||
function parseDescription (description) {
|
||||
/** @type {import('.').InlineTag[]} */
|
||||
const result = [];
|
||||
|
||||
// This could have been expressed in a single pattern,
|
||||
// but having two avoids a potentially exponential time regex.
|
||||
|
||||
const prefixedTextPattern = new RegExp(/(?:\[(?<text>[^\]]+)\])\{@(?<tag>[^}\s]+)\s?(?<namepathOrURL>[^}\s|]*)\}/gu, 'gud');
|
||||
// The pattern used to match for text after tag uses a negative lookbehind
|
||||
// on the ']' char to avoid matching the prefixed case too.
|
||||
const suffixedAfterPattern = new RegExp(/(?<!\])\{@(?<tag>[^}\s]+)\s?(?<namepathOrURL>[^}\s|]*)\s*(?<separator>[\s|])?\s*(?<text>[^}]*)\}/gu, 'gud');
|
||||
|
||||
const matches = [
|
||||
...description.matchAll(prefixedTextPattern),
|
||||
...description.matchAll(suffixedAfterPattern)
|
||||
];
|
||||
|
||||
for (const mtch of matches) {
|
||||
const match = /**
|
||||
* @type {RegExpMatchArray & {
|
||||
* indices: {
|
||||
* groups: {
|
||||
* [key: string]: [number, number]
|
||||
* }
|
||||
* }
|
||||
* groups: {[key: string]: string}
|
||||
* }}
|
||||
*/ (
|
||||
mtch
|
||||
);
|
||||
const {tag, namepathOrURL, text} = match.groups;
|
||||
const [start, end] = match.indices[0];
|
||||
const format = determineFormat(match);
|
||||
|
||||
result.push({
|
||||
tag,
|
||||
namepathOrURL,
|
||||
text,
|
||||
format,
|
||||
start,
|
||||
end
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}
|
||||
*/
|
||||
export function parseInlineTags (block) {
|
||||
const inlineTags =
|
||||
/**
|
||||
* @type {(import('./commentParserToESTree').JsdocInlineTagNoType & {
|
||||
* line?: import('./commentParserToESTree').Integer
|
||||
* })[]}
|
||||
*/ (
|
||||
parseDescription(block.description)
|
||||
);
|
||||
|
||||
/** @type {import('.').JsdocBlockWithInline} */ (
|
||||
block
|
||||
).inlineTags = inlineTags;
|
||||
|
||||
for (const tag of block.tags) {
|
||||
/**
|
||||
* @type {import('.').JsdocTagWithInline}
|
||||
*/ (tag).inlineTags = parseDescription(tag.description);
|
||||
}
|
||||
return (
|
||||
/**
|
||||
* @type {import('.').JsdocBlockWithInline}
|
||||
*/ (block)
|
||||
);
|
||||
}
|
||||
13
node_modules/@es-joy/jsdoccomment/src/toCamelCase.js
generated
vendored
Normal file
13
node_modules/@es-joy/jsdoccomment/src/toCamelCase.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
const toCamelCase = (str) => {
|
||||
return str.toLowerCase().replaceAll(/^[a-z]/gu, (init) => {
|
||||
return init.toUpperCase();
|
||||
}).replaceAll(/_(?<wordInit>[a-z])/gu, (_, n1, o, s, {wordInit}) => {
|
||||
return wordInit.toUpperCase();
|
||||
});
|
||||
};
|
||||
|
||||
export {toCamelCase};
|
||||
Reference in New Issue
Block a user