mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: annotate md utils to compile with ts-check (#17600)
This commit is contained in:
parent
6fe551e6ac
commit
0a3cfc1c21
@ -22,6 +22,9 @@ const md = require('../markdown');
|
|||||||
const Documentation = require('./documentation');
|
const Documentation = require('./documentation');
|
||||||
|
|
||||||
/** @typedef {import('../markdown').MarkdownNode} MarkdownNode */
|
/** @typedef {import('../markdown').MarkdownNode} MarkdownNode */
|
||||||
|
/** @typedef {import('../markdown').MarkdownHeaderNode} MarkdownHeaderNode */
|
||||||
|
/** @typedef {import('../markdown').MarkdownLiNode} MarkdownLiNode */
|
||||||
|
/** @typedef {import('../markdown').MarkdownTextNode} MarkdownTextNode */
|
||||||
|
|
||||||
class ApiParser {
|
class ApiParser {
|
||||||
/**
|
/**
|
||||||
@ -39,7 +42,7 @@ class ApiParser {
|
|||||||
bodyParts.push(fs.readFileSync(path.join(apiDir, name)).toString());
|
bodyParts.push(fs.readFileSync(path.join(apiDir, name)).toString());
|
||||||
}
|
}
|
||||||
const body = md.parse(bodyParts.join('\n'));
|
const body = md.parse(bodyParts.join('\n'));
|
||||||
const params = paramsPath ? md.parse(fs.readFileSync(paramsPath).toString()) : null;
|
const params = paramsPath ? md.parse(fs.readFileSync(paramsPath).toString()) : undefined;
|
||||||
checkNoDuplicateParamEntries(params);
|
checkNoDuplicateParamEntries(params);
|
||||||
const api = params ? applyTemplates(body, params) : body;
|
const api = params ? applyTemplates(body, params) : body;
|
||||||
/** @type {Map<string, Documentation.Class>} */
|
/** @type {Map<string, Documentation.Class>} */
|
||||||
@ -61,7 +64,7 @@ class ApiParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MarkdownNode} node
|
* @param {MarkdownHeaderNode} node
|
||||||
*/
|
*/
|
||||||
parseClass(node) {
|
parseClass(node) {
|
||||||
let extendsName = null;
|
let extendsName = null;
|
||||||
@ -80,7 +83,7 @@ class ApiParser {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MarkdownNode} spec
|
* @param {MarkdownHeaderNode} spec
|
||||||
*/
|
*/
|
||||||
parseMember(spec) {
|
parseMember(spec) {
|
||||||
const match = spec.text.match(/(event|method|property|async method|optional method|optional async method): ([^.]+)\.(.*)/);
|
const match = spec.text.match(/(event|method|property|async method|optional method|optional async method): ([^.]+)\.(.*)/);
|
||||||
@ -112,10 +115,13 @@ class ApiParser {
|
|||||||
if (match[1].includes('optional'))
|
if (match[1].includes('optional'))
|
||||||
member.required = false;
|
member.required = false;
|
||||||
}
|
}
|
||||||
const clazz = this.classes.get(match[2]);
|
if (!member)
|
||||||
|
throw new Error('Unknown member: ' + spec.text);
|
||||||
|
|
||||||
|
const clazz = /** @type {Documentation.Class} */(this.classes.get(match[2]));
|
||||||
const existingMember = clazz.membersArray.find(m => m.name === name && m.kind === member.kind);
|
const existingMember = clazz.membersArray.find(m => m.name === name && m.kind === member.kind);
|
||||||
if (existingMember && isTypeOverride(existingMember, member)) {
|
if (existingMember && isTypeOverride(existingMember, member)) {
|
||||||
for (const lang of member.langs.only) {
|
for (const lang of member?.langs?.only || []) {
|
||||||
existingMember.langs.types = existingMember.langs.types || {};
|
existingMember.langs.types = existingMember.langs.types || {};
|
||||||
existingMember.langs.types[lang] = returnType;
|
existingMember.langs.types[lang] = returnType;
|
||||||
}
|
}
|
||||||
@ -125,7 +131,7 @@ class ApiParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MarkdownNode} spec
|
* @param {MarkdownHeaderNode} spec
|
||||||
*/
|
*/
|
||||||
parseArgument(spec) {
|
parseArgument(spec) {
|
||||||
const match = spec.text.match(/(param|option): (.*)/);
|
const match = spec.text.match(/(param|option): (.*)/);
|
||||||
@ -173,34 +179,35 @@ class ApiParser {
|
|||||||
}
|
}
|
||||||
const p = this.parseProperty(spec);
|
const p = this.parseProperty(spec);
|
||||||
p.required = false;
|
p.required = false;
|
||||||
|
// @ts-ignore
|
||||||
options.type.properties.push(p);
|
options.type.properties.push(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MarkdownNode} spec
|
* @param {MarkdownHeaderNode} spec
|
||||||
*/
|
*/
|
||||||
parseProperty(spec) {
|
parseProperty(spec) {
|
||||||
const param = childrenWithoutProperties(spec)[0];
|
const param = childrenWithoutProperties(spec)[0];
|
||||||
const text = param.text;
|
const text = /** @type {string}*/(param.text);
|
||||||
let typeStart = text.indexOf('<');
|
let typeStart = text.indexOf('<');
|
||||||
while ('?e'.includes(text[typeStart - 1]))
|
while ('?e'.includes(text[typeStart - 1]))
|
||||||
typeStart--;
|
typeStart--;
|
||||||
const name = text.substring(0, typeStart).replace(/\`/g, '').trim();
|
const name = text.substring(0, typeStart).replace(/\`/g, '').trim();
|
||||||
const comments = extractComments(spec);
|
const comments = extractComments(spec);
|
||||||
const { type, optional } = this.parseType(param);
|
const { type, optional } = this.parseType(/** @type {MarkdownLiNode} */(param));
|
||||||
return Documentation.Member.createProperty(extractMetainfo(spec), name, type, comments, !optional);
|
return Documentation.Member.createProperty(extractMetainfo(spec), name, type, comments, !optional);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MarkdownNode=} spec
|
* @param {MarkdownLiNode} spec
|
||||||
* @return {{ type: Documentation.Type, optional: boolean, experimental: boolean }}
|
* @return {{ type: Documentation.Type, optional: boolean, experimental: boolean }}
|
||||||
*/
|
*/
|
||||||
parseType(spec) {
|
parseType(spec) {
|
||||||
const arg = parseVariable(spec.text);
|
const arg = parseVariable(spec.text);
|
||||||
const properties = [];
|
const properties = [];
|
||||||
for (const child of spec.children || []) {
|
for (const child of /** @type {MarkdownLiNode[]} */ (spec.children) || []) {
|
||||||
const { name, text } = parseVariable(child.text);
|
const { name, text } = parseVariable(/** @type {string} */(child.text));
|
||||||
const comments = /** @type {MarkdownNode[]} */ ([{ type: 'text', text }]);
|
const comments = /** @type {MarkdownNode[]} */ ([{ type: 'text', text }]);
|
||||||
const childType = this.parseType(child);
|
const childType = this.parseType(child);
|
||||||
properties.push(Documentation.Member.createProperty({ langs: {}, experimental: childType.experimental, since: 'v1.0' }, name, childType.type, comments, !childType.optional));
|
properties.push(Documentation.Member.createProperty({ langs: {}, experimental: childType.experimental, since: 'v1.0' }, name, childType.type, comments, !childType.optional));
|
||||||
@ -271,7 +278,7 @@ function applyTemplates(body, params) {
|
|||||||
if (!template)
|
if (!template)
|
||||||
throw new Error('Bad template: ' + prop.text);
|
throw new Error('Bad template: ' + prop.text);
|
||||||
const children = childrenWithoutProperties(template);
|
const children = childrenWithoutProperties(template);
|
||||||
const { name: argName } = parseVariable(children[0].text);
|
const { name: argName } = parseVariable(children[0].text || '');
|
||||||
newChildren.push({
|
newChildren.push({
|
||||||
type: node.type,
|
type: node.type,
|
||||||
text: name + argName,
|
text: name + argName,
|
||||||
@ -301,7 +308,7 @@ function applyTemplates(body, params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MarkdownNode} item
|
* @param {MarkdownHeaderNode} item
|
||||||
* @returns {MarkdownNode[]}
|
* @returns {MarkdownNode[]}
|
||||||
*/
|
*/
|
||||||
function extractComments(item) {
|
function extractComments(item) {
|
||||||
@ -323,7 +330,7 @@ function parseApi(apiDir, paramsPath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MarkdownNode} spec
|
* @param {MarkdownHeaderNode} spec
|
||||||
* @returns {import('./documentation').Metainfo}
|
* @returns {import('./documentation').Metainfo}
|
||||||
*/
|
*/
|
||||||
function extractMetainfo(spec) {
|
function extractMetainfo(spec) {
|
||||||
@ -339,7 +346,7 @@ function extractMetainfo(spec) {
|
|||||||
* @returns {import('./documentation').Langs}
|
* @returns {import('./documentation').Langs}
|
||||||
*/
|
*/
|
||||||
function extractLangs(spec) {
|
function extractLangs(spec) {
|
||||||
for (const child of spec.children) {
|
for (const child of spec.children || []) {
|
||||||
if (child.type !== 'li' || child.liType !== 'bullet' || !child.text.startsWith('langs:'))
|
if (child.type !== 'li' || child.liType !== 'bullet' || !child.text.startsWith('langs:'))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -347,7 +354,7 @@ function extractLangs(spec) {
|
|||||||
/** @type {Object<string, string>} */
|
/** @type {Object<string, string>} */
|
||||||
const aliases = {};
|
const aliases = {};
|
||||||
for (const p of child.children || []) {
|
for (const p of child.children || []) {
|
||||||
const match = p.text.match(/alias-(\w+)[\s]*:(.*)/);
|
const match = /** @type {string}*/(p.text).match(/alias-(\w+)[\s]*:(.*)/);
|
||||||
if (match)
|
if (match)
|
||||||
aliases[match[1].trim()] = match[2].trim();
|
aliases[match[1].trim()] = match[2].trim();
|
||||||
}
|
}
|
||||||
@ -362,7 +369,7 @@ function extractLangs(spec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MarkdownNode} spec
|
* @param {MarkdownHeaderNode} spec
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function extractSince(spec) {
|
function extractSince(spec) {
|
||||||
@ -377,7 +384,7 @@ function extractSince(spec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MarkdownNode} spec
|
* @param {MarkdownHeaderNode} spec
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
function extractExperimental(spec) {
|
function extractExperimental(spec) {
|
||||||
@ -389,12 +396,12 @@ function extractSince(spec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MarkdownNode} spec
|
* @param {MarkdownHeaderNode} spec
|
||||||
* @returns {MarkdownNode[]}
|
* @returns {MarkdownNode[]}
|
||||||
*/
|
*/
|
||||||
function childrenWithoutProperties(spec) {
|
function childrenWithoutProperties(spec) {
|
||||||
return (spec.children || []).filter(c => {
|
return (spec.children || []).filter(c => {
|
||||||
const isProperty = c.liType === 'bullet' && (c.text.startsWith('langs:') || c.text.startsWith('since:') || c.text === 'experimental');
|
const isProperty = c.type === 'li' && c.liType === 'bullet' && (c.text.startsWith('langs:') || c.text.startsWith('since:') || c.text === 'experimental');
|
||||||
return !isProperty;
|
return !isProperty;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -405,11 +412,12 @@ function childrenWithoutProperties(spec) {
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
function isTypeOverride(existingMember, member) {
|
function isTypeOverride(existingMember, member) {
|
||||||
if (!existingMember.langs.only)
|
if (!existingMember.langs.only || !member.langs.only)
|
||||||
return true;
|
return true;
|
||||||
if (member.langs.only.every(l => existingMember.langs.only.includes(l))) {
|
const existingOnly = existingMember.langs.only;
|
||||||
|
if (member.langs.only.every(l => existingOnly.includes(l))) {
|
||||||
return true;
|
return true;
|
||||||
} else if (member.langs.only.some(l => existingMember.langs.only.includes(l))) {
|
} else if (member.langs.only.some(l => existingOnly.includes(l))) {
|
||||||
throw new Error(`Ambiguous language override for: ${member.name}`);
|
throw new Error(`Ambiguous language override for: ${member.name}`);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -149,19 +149,19 @@ class Documentation {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param {Documentation.Class|Documentation.Member|null} classOrMember
|
* @param {Documentation.Class|Documentation.Member|null} classOrMember
|
||||||
* @param {MarkdownNode[]} nodes
|
* @param {MarkdownNode[] | undefined} nodes
|
||||||
*/
|
*/
|
||||||
this._patchLinks = (classOrMember, nodes) => patchLinks(classOrMember, nodes, classesMap, membersMap, linkRenderer);
|
this._patchLinks = (classOrMember, nodes) => patchLinks(classOrMember, nodes, classesMap, membersMap, linkRenderer);
|
||||||
|
|
||||||
for (const clazz of this.classesArray)
|
for (const clazz of this.classesArray)
|
||||||
clazz.visit(item => this._patchLinks(item, item.spec));
|
clazz.visit(item => this._patchLinks?.(item, item.spec));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MarkdownNode[]} nodes
|
* @param {MarkdownNode[]} nodes
|
||||||
*/
|
*/
|
||||||
renderLinksInText(nodes) {
|
renderLinksInText(nodes) {
|
||||||
this._patchLinks(null, nodes);
|
this._patchLinks?.(null, nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
generateSourceCodeComments() {
|
generateSourceCodeComments() {
|
||||||
@ -192,11 +192,8 @@ Documentation.Class = class {
|
|||||||
this.extends = extendsName;
|
this.extends = extendsName;
|
||||||
this.comment = '';
|
this.comment = '';
|
||||||
this.index();
|
this.index();
|
||||||
const match = name.match(/(API|JS|CDP|[A-Z])(.*)/);
|
const match = /** @type {string[]} */(name.match(/(API|JS|CDP|[A-Z])(.*)/));
|
||||||
this.varName = match[1].toLowerCase() + match[2];
|
this.varName = match[1].toLowerCase() + match[2];
|
||||||
}
|
|
||||||
|
|
||||||
index() {
|
|
||||||
/** @type {!Map<string, !Documentation.Member>} */
|
/** @type {!Map<string, !Documentation.Member>} */
|
||||||
this.members = new Map();
|
this.members = new Map();
|
||||||
/** @type {!Map<string, !Documentation.Member>} */
|
/** @type {!Map<string, !Documentation.Member>} */
|
||||||
@ -211,6 +208,16 @@ Documentation.Class = class {
|
|||||||
this.events = new Map();
|
this.events = new Map();
|
||||||
/** @type {!Array<!Documentation.Member>} */
|
/** @type {!Array<!Documentation.Member>} */
|
||||||
this.eventsArray = [];
|
this.eventsArray = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
index() {
|
||||||
|
this.members = new Map();
|
||||||
|
this.properties = new Map();
|
||||||
|
this.propertiesArray = [];
|
||||||
|
this.methods = new Map();
|
||||||
|
this.methodsArray = [];
|
||||||
|
this.events = new Map();
|
||||||
|
this.eventsArray = [];
|
||||||
|
|
||||||
for (const member of this.membersArray) {
|
for (const member of this.membersArray) {
|
||||||
this.members.set(member.name, member);
|
this.members.set(member.name, member);
|
||||||
@ -342,7 +349,7 @@ Documentation.Member = class {
|
|||||||
/** @type {!Map<string, !Documentation.Member>} */
|
/** @type {!Map<string, !Documentation.Member>} */
|
||||||
this.args = new Map();
|
this.args = new Map();
|
||||||
this.index();
|
this.index();
|
||||||
/** @type {!Documentation.Class} */
|
/** @type {!Documentation.Class | null} */
|
||||||
this.clazz = null;
|
this.clazz = null;
|
||||||
/** @type {Documentation.Member=} */
|
/** @type {Documentation.Member=} */
|
||||||
this.enclosingMethod = undefined;
|
this.enclosingMethod = undefined;
|
||||||
@ -357,13 +364,13 @@ Documentation.Member = class {
|
|||||||
this.alias = name;
|
this.alias = name;
|
||||||
this.overloadIndex = 0;
|
this.overloadIndex = 0;
|
||||||
if (name.includes('#')) {
|
if (name.includes('#')) {
|
||||||
const match = name.match(/(.*)#(.*)/);
|
const match = /** @type {string[]} */(name.match(/(.*)#(.*)/));
|
||||||
this.alias = match[1];
|
this.alias = match[1];
|
||||||
this.overloadIndex = (+match[2]) - 1;
|
this.overloadIndex = (+match[2]) - 1;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Param is true and option false
|
* Param is true and option false
|
||||||
* @type {Boolean}
|
* @type {Boolean | null}
|
||||||
*/
|
*/
|
||||||
this.paramOrOption = null;
|
this.paramOrOption = null;
|
||||||
}
|
}
|
||||||
@ -376,7 +383,9 @@ Documentation.Member = class {
|
|||||||
this.args.set(arg.name, arg);
|
this.args.set(arg.name, arg);
|
||||||
arg.enclosingMethod = this;
|
arg.enclosingMethod = this;
|
||||||
if (arg.name === 'options') {
|
if (arg.name === 'options') {
|
||||||
|
// @ts-ignore
|
||||||
arg.type.properties.sort((p1, p2) => p1.name.localeCompare(p2.name));
|
arg.type.properties.sort((p1, p2) => p1.name.localeCompare(p2.name));
|
||||||
|
// @ts-ignore
|
||||||
arg.type.properties.forEach(p => p.enclosingMethod = this);
|
arg.type.properties.forEach(p => p.enclosingMethod = this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -386,6 +395,8 @@ Documentation.Member = class {
|
|||||||
* @param {string} lang
|
* @param {string} lang
|
||||||
*/
|
*/
|
||||||
filterForLanguage(lang) {
|
filterForLanguage(lang) {
|
||||||
|
if (!this.type)
|
||||||
|
return;
|
||||||
if (this.langs.aliases && this.langs.aliases[lang])
|
if (this.langs.aliases && this.langs.aliases[lang])
|
||||||
this.alias = this.langs.aliases[lang];
|
this.alias = this.langs.aliases[lang];
|
||||||
if (this.langs.types && this.langs.types[lang])
|
if (this.langs.types && this.langs.types[lang])
|
||||||
@ -397,8 +408,10 @@ Documentation.Member = class {
|
|||||||
continue;
|
continue;
|
||||||
const overriddenArg = (arg.langs.overrides && arg.langs.overrides[lang]) || arg;
|
const overriddenArg = (arg.langs.overrides && arg.langs.overrides[lang]) || arg;
|
||||||
overriddenArg.filterForLanguage(lang);
|
overriddenArg.filterForLanguage(lang);
|
||||||
|
// @ts-ignore
|
||||||
if (overriddenArg.name === 'options' && !overriddenArg.type.properties.length)
|
if (overriddenArg.name === 'options' && !overriddenArg.type.properties.length)
|
||||||
continue;
|
continue;
|
||||||
|
// @ts-ignore
|
||||||
overriddenArg.type.filterForLanguage(lang);
|
overriddenArg.type.filterForLanguage(lang);
|
||||||
argsArray.push(overriddenArg);
|
argsArray.push(overriddenArg);
|
||||||
}
|
}
|
||||||
@ -406,10 +419,12 @@ Documentation.Member = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
filterOutExperimental() {
|
filterOutExperimental() {
|
||||||
|
if (!this.type)
|
||||||
|
return;
|
||||||
this.type.filterOutExperimental();
|
this.type.filterOutExperimental();
|
||||||
const argsArray = [];
|
const argsArray = [];
|
||||||
for (const arg of this.argsArray) {
|
for (const arg of this.argsArray) {
|
||||||
if (arg.experimental)
|
if (arg.experimental || !arg.type)
|
||||||
continue;
|
continue;
|
||||||
arg.type.filterOutExperimental();
|
arg.type.filterOutExperimental();
|
||||||
argsArray.push(arg);
|
argsArray.push(arg);
|
||||||
@ -418,7 +433,7 @@ Documentation.Member = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clone() {
|
clone() {
|
||||||
const result = new Documentation.Member(this.kind, { langs: this.langs, experimental: this.experimental, since: this.since }, this.name, this.type.clone(), this.argsArray.map(arg => arg.clone()), this.spec, this.required);
|
const result = new Documentation.Member(this.kind, { langs: this.langs, experimental: this.experimental, since: this.since }, this.name, this.type?.clone(), this.argsArray.map(arg => arg.clone()), this.spec, this.required);
|
||||||
result.alias = this.alias;
|
result.alias = this.alias;
|
||||||
result.async = this.async;
|
result.async = this.async;
|
||||||
result.paramOrOption = this.paramOrOption;
|
result.paramOrOption = this.paramOrOption;
|
||||||
@ -512,6 +527,7 @@ Documentation.Type = class {
|
|||||||
if (!inUnion && (parsedType.union || parsedType.unionName)) {
|
if (!inUnion && (parsedType.union || parsedType.unionName)) {
|
||||||
const type = new Documentation.Type(parsedType.unionName || '');
|
const type = new Documentation.Type(parsedType.unionName || '');
|
||||||
type.union = [];
|
type.union = [];
|
||||||
|
// @ts-ignore
|
||||||
for (let t = parsedType; t; t = t.union) {
|
for (let t = parsedType; t; t = t.union) {
|
||||||
const nestedUnion = !!t.unionName && t !== parsedType;
|
const nestedUnion = !!t.unionName && t !== parsedType;
|
||||||
type.union.push(Documentation.Type.fromParsedType(t, !nestedUnion));
|
type.union.push(Documentation.Type.fromParsedType(t, !nestedUnion));
|
||||||
@ -524,15 +540,17 @@ Documentation.Type = class {
|
|||||||
if (parsedType.args) {
|
if (parsedType.args) {
|
||||||
const type = new Documentation.Type('function');
|
const type = new Documentation.Type('function');
|
||||||
type.args = [];
|
type.args = [];
|
||||||
|
// @ts-ignore
|
||||||
for (let t = parsedType.args; t; t = t.next)
|
for (let t = parsedType.args; t; t = t.next)
|
||||||
type.args.push(Documentation.Type.fromParsedType(t));
|
type.args.push(Documentation.Type.fromParsedType(t));
|
||||||
type.returnType = parsedType.retType ? Documentation.Type.fromParsedType(parsedType.retType) : null;
|
type.returnType = parsedType.retType ? Documentation.Type.fromParsedType(parsedType.retType) : undefined;
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsedType.template) {
|
if (parsedType.template) {
|
||||||
const type = new Documentation.Type(parsedType.name);
|
const type = new Documentation.Type(parsedType.name);
|
||||||
type.templates = [];
|
type.templates = [];
|
||||||
|
// @ts-ignore
|
||||||
for (let t = parsedType.template; t; t = t.next)
|
for (let t = parsedType.template; t; t = t.next)
|
||||||
type.templates.push(Documentation.Type.fromParsedType(t));
|
type.templates.push(Documentation.Type.fromParsedType(t));
|
||||||
return type;
|
return type;
|
||||||
@ -597,7 +615,7 @@ Documentation.Type = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Documentation.Member[]}
|
* @returns {Documentation.Member[] | undefined}
|
||||||
*/
|
*/
|
||||||
sortedProperties() {
|
sortedProperties() {
|
||||||
if (!this.properties)
|
if (!this.properties)
|
||||||
@ -653,7 +671,7 @@ Documentation.Type = class {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ParsedType} type
|
* @param {ParsedType | null} type
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
function isStringUnion(type) {
|
function isStringUnion(type) {
|
||||||
@ -744,7 +762,7 @@ function matchingBracket(str, open, close) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Documentation.Class|Documentation.Member|null} classOrMember
|
* @param {Documentation.Class|Documentation.Member|null} classOrMember
|
||||||
* @param {MarkdownNode[]} spec
|
* @param {MarkdownNode[]|undefined} spec
|
||||||
* @param {Map<string, Documentation.Class>} classesMap
|
* @param {Map<string, Documentation.Class>} classesMap
|
||||||
* @param {Map<string, Documentation.Member>} membersMap
|
* @param {Map<string, Documentation.Member>} membersMap
|
||||||
* @param {Renderer} linkRenderer
|
* @param {Renderer} linkRenderer
|
||||||
@ -790,16 +808,17 @@ function patchLinks(classOrMember, spec, classesMap, membersMap, linkRenderer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MarkdownNode[]} spec
|
* @param {MarkdownNode[] | undefined} spec
|
||||||
*/
|
*/
|
||||||
function generateSourceCodeComment(spec) {
|
function generateSourceCodeComment(spec) {
|
||||||
const comments = (spec || []).filter(n => !n.type.startsWith('h') && (n.type !== 'li' || n.liType !== 'default')).map(c => md.clone(c));
|
const comments = (spec || []).filter(n => !n.type.startsWith('h') && (n.type !== 'li' || n.liType !== 'default')).map(c => md.clone(c));
|
||||||
md.visitAll(comments, node => {
|
md.visitAll(comments, node => {
|
||||||
if (node.codeLang && node.codeLang.includes('tab=js-js'))
|
if (node.codeLang && node.codeLang.includes('tab=js-js'))
|
||||||
node.type = 'null';
|
node.type = 'null';
|
||||||
if (node.liType === 'bullet')
|
if (node.type === 'li' && node.liType === 'bullet')
|
||||||
node.liType = 'default';
|
node.liType = 'default';
|
||||||
if (node.type === 'note') {
|
if (node.type === 'note') {
|
||||||
|
// @ts-ignore
|
||||||
node.type = 'text';
|
node.type = 'text';
|
||||||
node.text = '> NOTE: ' + node.text;
|
node.text = '> NOTE: ' + node.text;
|
||||||
}
|
}
|
||||||
|
@ -17,14 +17,52 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
/** @typedef {{
|
/** @typedef {{
|
||||||
* type: 'text' | 'li' | 'code' | 'properties' | 'h0' | 'h1' | 'h2' | 'h3' | 'h4' | 'note' | 'null',
|
* type: string,
|
||||||
* text?: string,
|
* text?: string,
|
||||||
|
* children?: MarkdownNode[],
|
||||||
* codeLang?: string,
|
* codeLang?: string,
|
||||||
* noteType?: string,
|
* }} MarkdownBaseNode */
|
||||||
* lines?: string[],
|
|
||||||
* liType?: 'default' | 'bullet' | 'ordinal',
|
/** @typedef {MarkdownBaseNode & {
|
||||||
* children?: MarkdownNode[]
|
* type: 'text',
|
||||||
* }} MarkdownNode */
|
* text: string,
|
||||||
|
* }} MarkdownTextNode */
|
||||||
|
|
||||||
|
/** @typedef {MarkdownBaseNode & {
|
||||||
|
* type: 'h0' | 'h1' | 'h2' | 'h3' | 'h4',
|
||||||
|
* text: string,
|
||||||
|
* children: MarkdownNode[]
|
||||||
|
* }} MarkdownHeaderNode */
|
||||||
|
|
||||||
|
/** @typedef {MarkdownBaseNode & {
|
||||||
|
* type: 'li',
|
||||||
|
* text: string,
|
||||||
|
* liType: 'default' | 'bullet' | 'ordinal',
|
||||||
|
* children: MarkdownNode[]
|
||||||
|
* }} MarkdownLiNode */
|
||||||
|
|
||||||
|
/** @typedef {MarkdownBaseNode & {
|
||||||
|
* type: 'code',
|
||||||
|
* lines: string[],
|
||||||
|
* codeLang: string,
|
||||||
|
* }} MarkdownCodeNode */
|
||||||
|
|
||||||
|
/** @typedef {MarkdownBaseNode & {
|
||||||
|
* type: 'note',
|
||||||
|
* text: string,
|
||||||
|
* noteType: string,
|
||||||
|
* }} MarkdownNoteNode */
|
||||||
|
|
||||||
|
/** @typedef {MarkdownBaseNode & {
|
||||||
|
* type: 'null',
|
||||||
|
* }} MarkdownNullNode */
|
||||||
|
|
||||||
|
/** @typedef {MarkdownBaseNode & {
|
||||||
|
* type: 'properties',
|
||||||
|
* lines: string[],
|
||||||
|
* }} MarkdownPropsNode */
|
||||||
|
|
||||||
|
/** @typedef {MarkdownTextNode | MarkdownLiNode | MarkdownCodeNode | MarkdownNoteNode | MarkdownHeaderNode | MarkdownNullNode | MarkdownPropsNode } MarkdownNode */
|
||||||
|
|
||||||
function flattenWrappedLines(content) {
|
function flattenWrappedLines(content) {
|
||||||
const inLines = content.replace(/\r\n/g, '\n').split('\n');
|
const inLines = content.replace(/\r\n/g, '\n').split('\n');
|
||||||
@ -110,13 +148,13 @@ function buildTree(lines) {
|
|||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
headerStack[0].children.push(node);
|
/** @type {MarkdownNode[]}*/(headerStack[0].children).push(node);
|
||||||
headerStack.unshift(node);
|
headerStack.unshift(node);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remaining items respect indent-based nesting.
|
// Remaining items respect indent-based nesting.
|
||||||
const [, indent, content] = line.match('^([ ]*)(.*)');
|
const [, indent, content] = /** @type {string[]} */ (line.match('^([ ]*)(.*)'));
|
||||||
if (content.startsWith('```')) {
|
if (content.startsWith('```')) {
|
||||||
/** @type {MarkdownNode} */
|
/** @type {MarkdownNode} */
|
||||||
const node = {
|
const node = {
|
||||||
@ -143,10 +181,10 @@ function buildTree(lines) {
|
|||||||
|
|
||||||
if (content.startsWith(':::')) {
|
if (content.startsWith(':::')) {
|
||||||
/** @type {MarkdownNode} */
|
/** @type {MarkdownNode} */
|
||||||
const node = {
|
const node = /** @type {MarkdownNoteNode} */ ({
|
||||||
type: 'note',
|
type: 'note',
|
||||||
noteType: content.substring(3)
|
noteType: content.substring(3)
|
||||||
};
|
});
|
||||||
line = lines[++i];
|
line = lines[++i];
|
||||||
const tokens = [];
|
const tokens = [];
|
||||||
while (!line.trim().startsWith(':::')) {
|
while (!line.trim().startsWith(':::')) {
|
||||||
@ -184,16 +222,17 @@ function buildTree(lines) {
|
|||||||
const liType = content.match(/^(-|1.|\*) /);
|
const liType = content.match(/^(-|1.|\*) /);
|
||||||
const node = /** @type {MarkdownNode} */({ type: 'text', text: content });
|
const node = /** @type {MarkdownNode} */({ type: 'text', text: content });
|
||||||
if (liType) {
|
if (liType) {
|
||||||
node.type = 'li';
|
const liNode = /** @type {MarkdownLiNode} */(node);
|
||||||
node.text = content.substring(liType[0].length);
|
liNode.type = 'li';
|
||||||
|
liNode.text = content.substring(liType[0].length);
|
||||||
if (content.startsWith('1.'))
|
if (content.startsWith('1.'))
|
||||||
node.liType = 'ordinal';
|
liNode.liType = 'ordinal';
|
||||||
else if (content.startsWith('*'))
|
else if (content.startsWith('*'))
|
||||||
node.liType = 'bullet';
|
liNode.liType = 'bullet';
|
||||||
else
|
else
|
||||||
node.liType = 'default';
|
liNode.liType = 'default';
|
||||||
}
|
}
|
||||||
const match = node.text.match(/\*\*langs: (.*)\*\*(.*)/);
|
const match = node.text?.match(/\*\*langs: (.*)\*\*(.*)/);
|
||||||
if (match) {
|
if (match) {
|
||||||
node.codeLang = match[1];
|
node.codeLang = match[1];
|
||||||
node.text = match[2];
|
node.text = match[2];
|
||||||
@ -220,7 +259,7 @@ function render(nodes, maxColumns) {
|
|||||||
for (let node of nodes) {
|
for (let node of nodes) {
|
||||||
if (node.type === 'null')
|
if (node.type === 'null')
|
||||||
continue;
|
continue;
|
||||||
innerRenderMdNode('', node, lastNode, result, maxColumns);
|
innerRenderMdNode('', node, /** @type {MarkdownNode} */ (lastNode), result, maxColumns);
|
||||||
lastNode = node;
|
lastNode = node;
|
||||||
}
|
}
|
||||||
return result.join('\n');
|
return result.join('\n');
|
||||||
@ -240,9 +279,10 @@ function innerRenderMdNode(indent, node, lastNode, result, maxColumns) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (node.type.startsWith('h')) {
|
if (node.type.startsWith('h')) {
|
||||||
|
const headerNode = /** @type {MarkdownHeaderNode} */ (node);
|
||||||
newLine();
|
newLine();
|
||||||
const depth = +node.type.substring(1);
|
const depth = +node.type.substring(1);
|
||||||
result.push(`${'#'.repeat(depth)} ${node.text}`);
|
result.push(`${'#'.repeat(depth)} ${headerNode.text}`);
|
||||||
let lastNode = node;
|
let lastNode = node;
|
||||||
for (const child of node.children || []) {
|
for (const child of node.children || []) {
|
||||||
innerRenderMdNode('', child, lastNode, result, maxColumns);
|
innerRenderMdNode('', child, lastNode, result, maxColumns);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user