forked from public/fvtt-cthulhu-eternal
Initial import with skill sheet working
This commit is contained in:
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};
|
||||
Reference in New Issue
Block a user