chore: brush up documentation scripts (#32782)

References #32590.
This commit is contained in:
Dmitry Gozman 2024-09-24 02:51:09 -07:00 committed by GitHub
parent 22c76aacad
commit 59700aa9f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 60 additions and 68 deletions

View File

@ -192,8 +192,7 @@ class ApiParser {
method.argsArray.push(options);
}
p.required = false;
// @ts-ignore
options.type.properties.push(p);
options.type?.properties?.push(p);
}
}

View File

@ -363,11 +363,6 @@ class Member {
this.alias = match[1];
this.overloadIndex = (+match[2]) - 1;
}
/**
* Param is true and option false
* @type {Boolean | null}
*/
this.paramOrOption = null;
}
index() {
@ -384,10 +379,8 @@ class Member {
for (const arg of this.argsArray) {
this.args.set(arg.name, arg);
arg.enclosingMethod = this;
if (arg.name === 'options') {
// @ts-ignore
arg.type.properties.sort((p1, p2) => p1.name.localeCompare(p2.name));
}
if (arg.name === 'options')
arg.type?.properties?.sort((p1, p2) => p1.name.localeCompare(p2.name));
indexArg(arg);
}
}
@ -410,11 +403,9 @@ class Member {
continue;
const overriddenArg = (arg.langs.overrides && arg.langs.overrides[lang]) || arg;
overriddenArg.filterForLanguage(lang, options);
// @ts-ignore
if (overriddenArg.name === 'options' && !overriddenArg.type.properties.length)
if (overriddenArg.name === 'options' && !overriddenArg.type?.properties?.length)
continue;
// @ts-ignore
overriddenArg.type.filterForLanguage(lang, options);
overriddenArg.type?.filterForLanguage(lang, options);
argsArray.push(overriddenArg);
}
this.argsArray = argsArray;
@ -433,7 +424,6 @@ class Member {
const result = new Member(this.kind, { langs: this.langs, since: this.since, deprecated: this.deprecated, discouraged: this.discouraged }, this.name, this.type?.clone(), this.argsArray.map(arg => arg.clone()), this.spec, this.required);
result.alias = this.alias;
result.async = this.async;
result.paramOrOption = this.paramOrOption;
return result;
}
@ -526,8 +516,7 @@ class Type {
if (!inUnion && (parsedType.union || parsedType.unionName)) {
const type = new Type(parsedType.unionName || '');
type.union = [];
// @ts-ignore
for (let t = parsedType; t; t = t.union) {
for (let /** @type {ParsedType | null} */ t = parsedType; t; t = t.union) {
const nestedUnion = !!t.unionName && t !== parsedType;
type.union.push(Type.fromParsedType(t, !nestedUnion));
if (nestedUnion)
@ -539,7 +528,6 @@ class Type {
if (parsedType.args || parsedType.retType) {
const type = new Type('function');
type.args = [];
// @ts-ignore
for (let t = parsedType.args; t; t = t.next)
type.args.push(Type.fromParsedType(t));
type.returnType = parsedType.retType ? Type.fromParsedType(parsedType.retType) : undefined;
@ -549,8 +537,7 @@ class Type {
if (parsedType.template) {
const type = new Type(parsedType.name);
type.templates = [];
// @ts-ignore
for (let t = parsedType.template; t; t = t.next)
for (let /** @type {ParsedType | null} */ t = parsedType.template; t; t = t.next)
type.templates.push(Type.fromParsedType(t));
return type;
}
@ -613,17 +600,6 @@ class Type {
return [];
}
/**
* @returns {Member[] | undefined}
*/
sortedProperties() {
if (!this.properties)
return this.properties;
const sortedProperties = [...this.properties];
sortedProperties.sort((p1, p2) => p1.name.localeCompare(p2.name));
return sortedProperties;
}
/**
* @param {string} lang
* @param {LanguageOptions=} options
@ -768,11 +744,10 @@ function patchLinksInText(classOrMember, text, classesMap, membersMap, linkRende
let alias = p2;
if (classOrMember) {
// param/option reference can only be in method or same method parameter comments.
// @ts-ignore
const method = classOrMember.enclosingMethod;
const param = method.argsArray.find(a => a.name === p2);
const method = /** @type {Member} */(classOrMember).enclosingMethod;
const param = method?.argsArray.find(a => a.name === p2);
if (!param)
throw new Error(`Referenced parameter ${match} not found in the parent method ${method.name} `);
throw new Error(`Referenced parameter ${match} not found in the parent method ${method?.name} `);
alias = param.alias;
}
return linkRenderer({ param: alias, href }) || match;

View File

@ -17,7 +17,6 @@
// @ts-check
const path = require('path');
const Documentation = require('./documentation');
const { parseApi } = require('./api_parser');
const PROJECT_DIR = path.join(__dirname, '..', '..');
@ -38,14 +37,14 @@ const PROJECT_DIR = path.join(__dirname, '..', '..');
}
/**
* @param {Documentation} documentation
* @param {import('./documentation').Documentation} documentation
*/
function serialize(documentation) {
return documentation.classesArray.map(serializeClass);
}
/**
* @param {Documentation.Class} clazz
* @param {import('./documentation').Class} clazz
*/
function serializeClass(clazz) {
const result = { name: clazz.name, spec: clazz.spec };
@ -65,7 +64,7 @@ function serializeClass(clazz) {
}
/**
* @param {Documentation.Member} member
* @param {import('./documentation').Member} member
*/
function serializeMember(member) {
const result = /** @type {any} */ ({ ...member });
@ -76,14 +75,20 @@ function serializeMember(member) {
return result;
}
/**
* @param {import('./documentation').Member} arg
*/
function serializeProperty(arg) {
const result = { ...arg, parent: undefined };
sanitize(result);
if (arg.type)
result.type = serializeType(arg.type, arg.name === 'options');
result.type = serializeType(arg.type);
return result;
}
/**
* @param {object} result
*/
function sanitize(result) {
delete result.args;
delete result.argsArray;
@ -92,14 +97,13 @@ function sanitize(result) {
}
/**
* @param {Documentation.Type} type
* @param {boolean} sortProperties
* @param {import('./documentation').Type} type
*/
function serializeType(type, sortProperties = false) {
function serializeType(type) {
/** @type {any} */
const result = { ...type };
if (type.properties)
result.properties = (sortProperties ? type.sortedProperties() : type.properties).map(serializeProperty);
result.properties = type.properties.map(serializeProperty);
if (type.union)
result.union = type.union.map(type => serializeType(type));
if (type.templates)

View File

@ -91,7 +91,7 @@ class TypesGenerator {
if (!docClass)
return '';
handledClasses.add(className);
return this.writeComment(docClass.comment) + '\n';
return this.writeComment(docClass.comment, '') + '\n';
}, (className, methodName, overloadIndex) => {
if (className === 'SuiteFunction' && methodName === '__call') {
const cls = this.documentation.classes.get('Test');
@ -218,7 +218,7 @@ class TypesGenerator {
classToString(classDesc) {
const parts = [];
if (classDesc.comment) {
parts.push(this.writeComment(classDesc.comment))
parts.push(this.writeComment(classDesc.comment, ''))
}
const shouldExport = !this.doNotExportClassNames.has(classDesc.name);
parts.push(`${shouldExport ? 'export ' : ''}interface ${classDesc.name} ${classDesc.extends ? `extends ${classDesc.extends} ` : ''}{`);
@ -258,7 +258,7 @@ class TypesGenerator {
const descriptions = [];
for (let [eventName, value] of classDesc.events) {
eventName = eventName.toLowerCase();
const type = this.stringifyComplexType(value && value.type, 'out', ' ', classDesc.name, eventName, 'payload');
const type = this.stringifyComplexType(value && value.type, 'out', ' ', [classDesc.name, eventName, 'payload']);
const argName = this.argNameForType(type);
const params = argName ? `${argName}: ${type}` : '';
descriptions.push({
@ -311,8 +311,8 @@ class TypesGenerator {
return parts.join('\n');
}
const jsdoc = this.memberJSDOC(member, indent);
const args = this.argsFromMember(member, indent, classDesc.name);
let type = this.stringifyComplexType(member.type, 'out', indent, classDesc.name, member.alias);
const args = this.argsFromMember(member, indent, [classDesc.name]);
let type = this.stringifyComplexType(member.type, 'out', indent, [classDesc.name, member.alias]);
if (member.async)
type = `Promise<${type}>`;
// do this late, because we still want object definitions for overridden types
@ -351,7 +351,12 @@ class TypesGenerator {
return this.documentation.classes.get(classDesc.extends);
}
writeComment(comment, indent = '') {
/**
* @param {string} comment
* @param {string} indent
* @returns {string}
*/
writeComment(comment, indent) {
const parts = [];
const out = [];
const pushLine = (line) => {
@ -387,26 +392,30 @@ class TypesGenerator {
/**
* @param {docs.Type|null} type
* @param {'in' | 'out'} direction
* @param {string} indent
* @param {string[]} namespace
* @returns {string}
*/
stringifyComplexType(type, direction, indent, ...namespace) {
stringifyComplexType(type, direction, indent, namespace) {
if (!type)
return 'void';
return this.stringifySimpleType(type, direction, indent, ...namespace);
return this.stringifySimpleType(type, direction, indent, namespace);
}
/**
* @param {docs.Member[]} properties
* @param {string} name
* @param {string=} indent
* @param {string} indent
* @returns {string}
*/
stringifyObjectType(properties, name, indent = '') {
stringifyObjectType(properties, name, indent) {
const parts = [];
parts.push(`{`);
parts.push(properties.map(member => {
const comment = this.memberJSDOC(member, indent + ' ');
const args = this.argsFromMember(member, indent + ' ', name);
const type = this.stringifyComplexType(member.type, 'out', indent + ' ', name, member.name);
const args = this.argsFromMember(member, indent + ' ', [name]);
const type = this.stringifyComplexType(member.type, 'out', indent + ' ', [name, member.name]);
return `${comment}${this.nameForProperty(member)}${args}: ${type};`;
}).join('\n\n'));
parts.push(indent + '}');
@ -416,14 +425,16 @@ class TypesGenerator {
/**
* @param {docs.Type | null | undefined} type
* @param {'in' | 'out'} direction
* @returns{string}
* @param {string} indent
* @param {string[]} namespace
* @returns {string}
*/
stringifySimpleType(type, direction, indent = '', ...namespace) {
stringifySimpleType(type, direction, indent, namespace) {
if (!type)
return 'void';
if (type.name === 'Object' && type.templates) {
const keyType = this.stringifySimpleType(type.templates[0], direction, indent, ...namespace);
const valueType = this.stringifySimpleType(type.templates[1], direction, indent, ...namespace);
const keyType = this.stringifySimpleType(type.templates[0], direction, indent, namespace);
const valueType = this.stringifySimpleType(type.templates[1], direction, indent, namespace);
return `{ [key: ${keyType}]: ${valueType}; }`;
}
let out = type.name;
@ -434,7 +445,7 @@ class TypesGenerator {
if (type.name === 'Object' && type.properties && type.properties.length) {
const name = namespace.map(n => n[0].toUpperCase() + n.substring(1)).join('');
const shouldExport = exported[name];
const properties = namespace[namespace.length - 1] === 'options' ? type.sortedProperties() : type.properties;
const properties = type.properties;
if (!properties)
throw new Error(`Object type must have properties`);
if (!this.objectDefinitions.some(o => o.name === name))
@ -448,10 +459,10 @@ class TypesGenerator {
if (type.args) {
const stringArgs = type.args.map(a => ({
type: this.stringifySimpleType(a, direction, indent, ...namespace),
type: this.stringifySimpleType(a, direction, indent, namespace),
name: a.name.toLowerCase()
}));
out = `((${stringArgs.map(({ name, type }) => `${name}: ${type}`).join(', ')}) => ${this.stringifySimpleType(type.returnType, 'out', indent, ...namespace)})`;
out = `((${stringArgs.map(({ name, type }) => `${name}: ${type}`).join(', ')}) => ${this.stringifySimpleType(type.returnType, 'out', indent, namespace)})`;
} else if (type.name === 'function') {
out = 'Function';
}
@ -460,19 +471,22 @@ class TypesGenerator {
if (out === 'Any')
return 'any';
if (type.templates)
out += '<' + type.templates.map(t => this.stringifySimpleType(t, direction, indent, ...namespace)).join(', ') + '>';
out += '<' + type.templates.map(t => this.stringifySimpleType(t, direction, indent, namespace)).join(', ') + '>';
if (type.union)
out = type.union.map(t => this.stringifySimpleType(t, direction, indent, ...namespace)).join('|');
out = type.union.map(t => this.stringifySimpleType(t, direction, indent, namespace)).join('|');
return out.trim();
}
/**
* @param {docs.Member} member
* @param {string} indent
* @param {string[]} namespace
* @returns {string}
*/
argsFromMember(member, indent, ...namespace) {
argsFromMember(member, indent, namespace) {
if (member.kind === 'property')
return '';
return '(' + member.argsArray.map(arg => `${this.nameForProperty(arg)}: ${this.stringifyComplexType(arg.type, 'in', indent, ...namespace, member.alias, arg.alias)}`).join(', ') + ')';
return '(' + member.argsArray.map(arg => `${this.nameForProperty(arg)}: ${this.stringifyComplexType(arg.type, 'in', indent, [...namespace, member.alias, arg.alias])}`).join(', ') + ')';
}
/**