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); method.argsArray.push(options);
} }
p.required = false; 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.alias = match[1];
this.overloadIndex = (+match[2]) - 1; this.overloadIndex = (+match[2]) - 1;
} }
/**
* Param is true and option false
* @type {Boolean | null}
*/
this.paramOrOption = null;
} }
index() { index() {
@ -384,10 +379,8 @@ class Member {
for (const arg of this.argsArray) { for (const arg of this.argsArray) {
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));
}
indexArg(arg); indexArg(arg);
} }
} }
@ -410,11 +403,9 @@ class Member {
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, options); overriddenArg.filterForLanguage(lang, options);
// @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, options);
overriddenArg.type.filterForLanguage(lang, options);
argsArray.push(overriddenArg); argsArray.push(overriddenArg);
} }
this.argsArray = argsArray; 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); 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.alias = this.alias;
result.async = this.async; result.async = this.async;
result.paramOrOption = this.paramOrOption;
return result; return result;
} }
@ -526,8 +516,7 @@ class Type {
if (!inUnion && (parsedType.union || parsedType.unionName)) { if (!inUnion && (parsedType.union || parsedType.unionName)) {
const type = new Type(parsedType.unionName || ''); const type = new Type(parsedType.unionName || '');
type.union = []; type.union = [];
// @ts-ignore for (let /** @type {ParsedType | null} */ 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(Type.fromParsedType(t, !nestedUnion)); type.union.push(Type.fromParsedType(t, !nestedUnion));
if (nestedUnion) if (nestedUnion)
@ -539,7 +528,6 @@ class Type {
if (parsedType.args || parsedType.retType) { if (parsedType.args || parsedType.retType) {
const type = new Type('function'); const type = new 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(Type.fromParsedType(t)); type.args.push(Type.fromParsedType(t));
type.returnType = parsedType.retType ? Type.fromParsedType(parsedType.retType) : undefined; type.returnType = parsedType.retType ? Type.fromParsedType(parsedType.retType) : undefined;
@ -549,8 +537,7 @@ class Type {
if (parsedType.template) { if (parsedType.template) {
const type = new Type(parsedType.name); const type = new Type(parsedType.name);
type.templates = []; type.templates = [];
// @ts-ignore for (let /** @type {ParsedType | null} */ t = parsedType.template; t; t = t.next)
for (let t = parsedType.template; t; t = t.next)
type.templates.push(Type.fromParsedType(t)); type.templates.push(Type.fromParsedType(t));
return type; return type;
} }
@ -613,17 +600,6 @@ class Type {
return []; 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 {string} lang
* @param {LanguageOptions=} options * @param {LanguageOptions=} options
@ -768,11 +744,10 @@ function patchLinksInText(classOrMember, text, classesMap, membersMap, linkRende
let alias = p2; let alias = p2;
if (classOrMember) { if (classOrMember) {
// param/option reference can only be in method or same method parameter comments. // param/option reference can only be in method or same method parameter comments.
// @ts-ignore const method = /** @type {Member} */(classOrMember).enclosingMethod;
const method = classOrMember.enclosingMethod; const param = method?.argsArray.find(a => a.name === p2);
const param = method.argsArray.find(a => a.name === p2);
if (!param) 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; alias = param.alias;
} }
return linkRenderer({ param: alias, href }) || match; return linkRenderer({ param: alias, href }) || match;

View file

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

View file

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