mirror of
https://github.com/microsoft/playwright.git
synced 2024-10-27 05:46:28 +03:00
chore: remove support for "experimental" from documentation (#30880)
Also add support for "hidden" and make `generate_types/index` actually pass tsc checks.
This commit is contained in:
parent
437b14a903
commit
b67b9634c1
@ -77,7 +77,10 @@ class ApiParser {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const clazz = new docs.Class(extractMetainfo(node), name, [], extendsName, extractComments(node));
|
||||
const metainfo = extractMetainfo(node);
|
||||
const clazz = new docs.Class(metainfo, name, [], extendsName, extractComments(node));
|
||||
if (metainfo.hidden)
|
||||
return;
|
||||
this.classes.set(clazz.name, clazz);
|
||||
}
|
||||
|
||||
@ -103,13 +106,14 @@ class ApiParser {
|
||||
returnType = new docs.Type('void');
|
||||
|
||||
const comments = extractComments(spec);
|
||||
const metainfo = extractMetainfo(spec);
|
||||
let member;
|
||||
if (match[1] === 'event')
|
||||
member = docs.Member.createEvent(extractMetainfo(spec), name, returnType, comments);
|
||||
member = docs.Member.createEvent(metainfo, name, returnType, comments);
|
||||
if (match[1] === 'property')
|
||||
member = docs.Member.createProperty(extractMetainfo(spec), name, returnType, comments, !optional);
|
||||
member = docs.Member.createProperty(metainfo, name, returnType, comments, !optional);
|
||||
if (['method', 'async method', 'optional method', 'optional async method'].includes(match[1])) {
|
||||
member = docs.Member.createMethod(extractMetainfo(spec), name, [], returnType, comments);
|
||||
member = docs.Member.createMethod(metainfo, name, [], returnType, comments);
|
||||
if (match[1].includes('async'))
|
||||
member.async = true;
|
||||
if (match[1].includes('optional'))
|
||||
@ -119,6 +123,11 @@ class ApiParser {
|
||||
throw new Error('Unknown member: ' + spec.text);
|
||||
|
||||
const clazz = /** @type {docs.Class} */(this.classes.get(match[2]));
|
||||
if (!clazz)
|
||||
throw new Error(`Unknown class ${match[2]} for member: ` + spec.text);
|
||||
if (metainfo.hidden)
|
||||
return;
|
||||
|
||||
const existingMember = clazz.membersArray.find(m => m.name === name && m.kind === member.kind);
|
||||
if (existingMember && isTypeOverride(existingMember, member)) {
|
||||
for (const lang of member?.langs?.only || []) {
|
||||
@ -157,6 +166,8 @@ class ApiParser {
|
||||
throw new Error('Invalid member name ' + spec.text);
|
||||
if (match[1] === 'param') {
|
||||
const arg = this.parseProperty(spec);
|
||||
if (!arg)
|
||||
return;
|
||||
arg.name = name;
|
||||
const existingArg = method.argsArray.find(m => m.name === arg.name);
|
||||
if (existingArg && isTypeOverride(existingArg, arg)) {
|
||||
@ -171,13 +182,15 @@ class ApiParser {
|
||||
}
|
||||
} else {
|
||||
// match[1] === 'option'
|
||||
const p = this.parseProperty(spec);
|
||||
if (!p)
|
||||
return;
|
||||
let options = method.argsArray.find(o => o.name === 'options');
|
||||
if (!options) {
|
||||
const type = new docs.Type('Object', []);
|
||||
options = docs.Member.createProperty({ langs: {}, experimental: false, since: 'v1.0', deprecated: undefined, discouraged: undefined }, 'options', type, undefined, false);
|
||||
options = docs.Member.createProperty({ langs: {}, since: 'v1.0', deprecated: undefined, discouraged: undefined }, 'options', type, undefined, false);
|
||||
method.argsArray.push(options);
|
||||
}
|
||||
const p = this.parseProperty(spec);
|
||||
p.required = false;
|
||||
// @ts-ignore
|
||||
options.type.properties.push(p);
|
||||
@ -186,6 +199,7 @@ class ApiParser {
|
||||
|
||||
/**
|
||||
* @param {MarkdownHeaderNode} spec
|
||||
* @returns {docs.Member | null}
|
||||
*/
|
||||
parseProperty(spec) {
|
||||
const param = childrenWithoutProperties(spec)[0];
|
||||
@ -196,12 +210,15 @@ class ApiParser {
|
||||
const name = text.substring(0, typeStart).replace(/\`/g, '').trim();
|
||||
const comments = extractComments(spec);
|
||||
const { type, optional } = this.parseType(/** @type {MarkdownLiNode} */(param));
|
||||
return docs.Member.createProperty(extractMetainfo(spec), name, type, comments, !optional);
|
||||
const metainfo = extractMetainfo(spec);
|
||||
if (metainfo.hidden)
|
||||
return null;
|
||||
return docs.Member.createProperty(metainfo, name, type, comments, !optional);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {MarkdownLiNode} spec
|
||||
* @return {{ type: docs.Type, optional: boolean, experimental: boolean }}
|
||||
* @return {{ type: docs.Type, optional: boolean }}
|
||||
*/
|
||||
parseType(spec) {
|
||||
const arg = parseVariable(spec.text);
|
||||
@ -210,16 +227,16 @@ class ApiParser {
|
||||
const { name, text } = parseVariable(/** @type {string} */(child.text));
|
||||
const comments = /** @type {MarkdownNode[]} */ ([{ type: 'text', text }]);
|
||||
const childType = this.parseType(child);
|
||||
properties.push(docs.Member.createProperty({ langs: {}, experimental: childType.experimental, since: 'v1.0', deprecated: undefined, discouraged: undefined }, name, childType.type, comments, !childType.optional));
|
||||
properties.push(docs.Member.createProperty({ langs: {}, since: 'v1.0', deprecated: undefined, discouraged: undefined }, name, childType.type, comments, !childType.optional));
|
||||
}
|
||||
const type = docs.Type.parse(arg.type, properties);
|
||||
return { type, optional: arg.optional, experimental: arg.experimental };
|
||||
return { type, optional: arg.optional };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} line
|
||||
* @returns {{ name: string, type: string, text: string, optional: boolean, experimental: boolean }}
|
||||
* @returns {{ name: string, type: string, text: string, optional: boolean }}
|
||||
*/
|
||||
function parseVariable(line) {
|
||||
let match = line.match(/^`([^`]+)` (.*)/);
|
||||
@ -234,12 +251,9 @@ function parseVariable(line) {
|
||||
const name = match[1];
|
||||
let remainder = match[2];
|
||||
let optional = false;
|
||||
let experimental = false;
|
||||
while ('?e'.includes(remainder[0])) {
|
||||
while ('?'.includes(remainder[0])) {
|
||||
if (remainder[0] === '?')
|
||||
optional = true;
|
||||
else if (remainder[0] === 'e')
|
||||
experimental = true;
|
||||
remainder = remainder.substring(1);
|
||||
}
|
||||
if (!remainder.startsWith('<'))
|
||||
@ -252,7 +266,7 @@ function parseVariable(line) {
|
||||
if (c === '>')
|
||||
--depth;
|
||||
if (depth === 0)
|
||||
return { name, type: remainder.substring(1, i), text: remainder.substring(i + 2), optional, experimental };
|
||||
return { name, type: remainder.substring(1, i), text: remainder.substring(i + 2), optional };
|
||||
}
|
||||
throw new Error('Should not be reached, line: ' + line);
|
||||
}
|
||||
@ -344,15 +358,15 @@ function parseApi(apiDir, paramsPath) {
|
||||
|
||||
/**
|
||||
* @param {MarkdownHeaderNode} spec
|
||||
* @returns {import('./documentation').Metainfo}
|
||||
* @returns {import('./documentation').Metainfo & { hidden: boolean }}
|
||||
*/
|
||||
function extractMetainfo(spec) {
|
||||
return {
|
||||
langs: extractLangs(spec),
|
||||
since: extractSince(spec),
|
||||
experimental: extractExperimental(spec),
|
||||
deprecated: extractAttribute(spec, 'deprecated'),
|
||||
discouraged: extractAttribute(spec, 'discouraged'),
|
||||
hidden: extractHidden(spec),
|
||||
};
|
||||
}
|
||||
|
||||
@ -402,9 +416,9 @@ function extractSince(spec) {
|
||||
* @param {MarkdownHeaderNode} spec
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function extractExperimental(spec) {
|
||||
function extractHidden(spec) {
|
||||
for (const child of spec.children) {
|
||||
if (child.type === 'li' && child.liType === 'bullet' && child.text === 'experimental')
|
||||
if (child.type === 'li' && child.liType === 'bullet' && child.text === 'hidden')
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -429,7 +443,7 @@ function extractSince(spec) {
|
||||
*/
|
||||
function childrenWithoutProperties(spec) {
|
||||
return (spec.children || []).filter(c => {
|
||||
const isProperty = c.type === 'li' && c.liType === 'bullet' && (c.text.startsWith('langs:') || c.text.startsWith('since:') || c.text.startsWith('deprecated:') || c.text.startsWith('discouraged:') || c.text === 'experimental');
|
||||
const isProperty = c.type === 'li' && c.liType === 'bullet' && (c.text.startsWith('langs:') || c.text.startsWith('since:') || c.text.startsWith('deprecated:') || c.text.startsWith('discouraged:') || c.text === 'hidden');
|
||||
return !isProperty;
|
||||
});
|
||||
}
|
||||
|
@ -57,7 +57,6 @@ const md = require('../markdown');
|
||||
* since: string,
|
||||
* deprecated?: string | undefined,
|
||||
* discouraged?: string | undefined,
|
||||
* experimental: boolean
|
||||
* }} Metainfo
|
||||
*/
|
||||
|
||||
@ -132,18 +131,6 @@ class Documentation {
|
||||
this.index();
|
||||
}
|
||||
|
||||
filterOutExperimental() {
|
||||
const classesArray = [];
|
||||
for (const clazz of this.classesArray) {
|
||||
if (clazz.experimental)
|
||||
continue;
|
||||
clazz.filterOutExperimental();
|
||||
classesArray.push(clazz);
|
||||
}
|
||||
this.classesArray = classesArray;
|
||||
this.index();
|
||||
}
|
||||
|
||||
index() {
|
||||
for (const cls of this.classesArray) {
|
||||
this.classes.set(cls.name, cls);
|
||||
@ -231,7 +218,6 @@ class Documentation {
|
||||
*/
|
||||
constructor(metainfo, name, membersArray, extendsName = null, spec = undefined) {
|
||||
this.langs = metainfo.langs;
|
||||
this.experimental = metainfo.experimental;
|
||||
this.since = metainfo.since;
|
||||
this.deprecated = metainfo.deprecated;
|
||||
this.discouraged = metainfo.discouraged;
|
||||
@ -286,7 +272,7 @@ class Documentation {
|
||||
}
|
||||
|
||||
clone() {
|
||||
const cls = new Class({ langs: this.langs, experimental: this.experimental, since: this.since, deprecated: this.deprecated, discouraged: this.discouraged }, this.name, this.membersArray.map(m => m.clone()), this.extends, this.spec);
|
||||
const cls = new Class({ langs: this.langs, since: this.since, deprecated: this.deprecated, discouraged: this.discouraged }, this.name, this.membersArray.map(m => m.clone()), this.extends, this.spec);
|
||||
cls.comment = this.comment;
|
||||
return cls;
|
||||
}
|
||||
@ -306,17 +292,6 @@ class Documentation {
|
||||
this.membersArray = membersArray;
|
||||
}
|
||||
|
||||
filterOutExperimental() {
|
||||
const membersArray = [];
|
||||
for (const member of this.membersArray) {
|
||||
if (member.experimental)
|
||||
continue;
|
||||
member.filterOutExperimental();
|
||||
membersArray.push(member);
|
||||
}
|
||||
this.membersArray = membersArray;
|
||||
}
|
||||
|
||||
sortMembers() {
|
||||
/**
|
||||
* @param {Member} member
|
||||
@ -362,7 +337,6 @@ class Member {
|
||||
constructor(kind, metainfo, name, type, argsArray, spec = undefined, required = true) {
|
||||
this.kind = kind;
|
||||
this.langs = metainfo.langs;
|
||||
this.experimental = metainfo.experimental;
|
||||
this.since = metainfo.since;
|
||||
this.deprecated = metainfo.deprecated;
|
||||
this.discouraged = metainfo.discouraged;
|
||||
@ -447,22 +421,8 @@ class Member {
|
||||
}
|
||||
}
|
||||
|
||||
filterOutExperimental() {
|
||||
if (!this.type)
|
||||
return;
|
||||
this.type.filterOutExperimental();
|
||||
const argsArray = [];
|
||||
for (const arg of this.argsArray) {
|
||||
if (arg.experimental || !arg.type)
|
||||
continue;
|
||||
arg.type.filterOutExperimental();
|
||||
argsArray.push(arg);
|
||||
}
|
||||
this.argsArray = argsArray;
|
||||
}
|
||||
|
||||
clone() {
|
||||
const result = new Member(this.kind, { langs: this.langs, experimental: this.experimental, 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.async = this.async;
|
||||
result.paramOrOption = this.paramOrOption;
|
||||
@ -671,19 +631,6 @@ class Type {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
filterOutExperimental() {
|
||||
if (!this.properties)
|
||||
return;
|
||||
const properties = [];
|
||||
for (const prop of this.properties) {
|
||||
if (prop.experimental)
|
||||
continue;
|
||||
prop.filterOutExperimental();
|
||||
properties.push(prop);
|
||||
}
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Type[]} result
|
||||
*/
|
||||
|
@ -36,7 +36,6 @@ class TypesGenerator {
|
||||
* ignoreMissing?: Set<string>,
|
||||
* doNotExportClassNames?: Set<string>,
|
||||
* doNotGenerate?: Set<string>,
|
||||
* includeExperimental?: boolean,
|
||||
* }} options
|
||||
*/
|
||||
constructor(options) {
|
||||
@ -50,8 +49,6 @@ class TypesGenerator {
|
||||
this.doNotExportClassNames = options.doNotExportClassNames || new Set();
|
||||
this.doNotGenerate = options.doNotGenerate || new Set();
|
||||
this.documentation.filterForLanguage('js');
|
||||
if (!options.includeExperimental)
|
||||
this.documentation.filterOutExperimental();
|
||||
this.documentation.copyDocsFromSuperclasses([]);
|
||||
this.injectDisposeAsync();
|
||||
}
|
||||
@ -65,7 +62,7 @@ class TypesGenerator {
|
||||
continue;
|
||||
if (!member.async)
|
||||
continue;
|
||||
newMember = new docs.Member('method', { langs: {}, since: '1.0', experimental: false }, '[Symbol.asyncDispose]', null, []);
|
||||
newMember = new docs.Member('method', { langs: {}, since: '1.0' }, '[Symbol.asyncDispose]', null, []);
|
||||
newMember.async = true;
|
||||
break;
|
||||
}
|
||||
@ -98,12 +95,20 @@ class TypesGenerator {
|
||||
}, (className, methodName, overloadIndex) => {
|
||||
if (className === 'SuiteFunction' && methodName === '__call') {
|
||||
const cls = this.documentation.classes.get('Test');
|
||||
if (!cls)
|
||||
throw new Error(`Unknown class "Test"`);
|
||||
const method = cls.membersArray.find(m => m.alias === 'describe');
|
||||
if (!method)
|
||||
throw new Error(`Unknown method "Test.describe"`);
|
||||
return this.memberJSDOC(method, ' ').trimLeft();
|
||||
}
|
||||
if (className === 'TestFunction' && methodName === '__call') {
|
||||
const cls = this.documentation.classes.get('Test');
|
||||
if (!cls)
|
||||
throw new Error(`Unknown class "Test"`);
|
||||
const method = cls.membersArray.find(m => m.alias === '(call)');
|
||||
if (!method)
|
||||
throw new Error(`Unknown method "Test.(call)"`);
|
||||
return this.memberJSDOC(method, ' ').trimLeft();
|
||||
}
|
||||
|
||||
@ -137,6 +142,8 @@ class TypesGenerator {
|
||||
.filter(cls => !handledClasses.has(cls.name));
|
||||
{
|
||||
const playwright = this.documentation.classesArray.find(c => c.name === 'Playwright');
|
||||
if (!playwright)
|
||||
throw new Error(`Unknown class "Playwright"`);
|
||||
playwright.membersArray = playwright.membersArray.filter(member => !['errors', 'devices'].includes(member.name));
|
||||
playwright.index();
|
||||
}
|
||||
@ -327,19 +334,20 @@ class TypesGenerator {
|
||||
hasOwnMethod(classDesc, member) {
|
||||
if (this.handledMethods.has(`${classDesc.name}.${member.alias}#${member.overloadIndex}`))
|
||||
return false;
|
||||
while (classDesc = this.parentClass(classDesc)) {
|
||||
if (classDesc.members.has(member.alias))
|
||||
let parent = /** @type {docs.Class | undefined} */ (classDesc);
|
||||
while (parent = this.parentClass(parent)) {
|
||||
if (parent.members.has(member.alias))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {docs.Class} classDesc
|
||||
* @param {docs.Class | undefined} classDesc
|
||||
*/
|
||||
parentClass(classDesc) {
|
||||
if (!classDesc.extends)
|
||||
return null;
|
||||
if (!classDesc || !classDesc.extends)
|
||||
return;
|
||||
return this.documentation.classes.get(classDesc.extends);
|
||||
}
|
||||
|
||||
@ -427,6 +435,8 @@ class TypesGenerator {
|
||||
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;
|
||||
if (!properties)
|
||||
throw new Error(`Object type must have properties`);
|
||||
if (!this.objectDefinitions.some(o => o.name === name))
|
||||
this.objectDefinitions.push({ name, properties });
|
||||
if (shouldExport) {
|
||||
@ -503,15 +513,13 @@ class TypesGenerator {
|
||||
]);
|
||||
|
||||
/**
|
||||
* @param {boolean} includeExperimental
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async function generateCoreTypes(includeExperimental) {
|
||||
async function generateCoreTypes() {
|
||||
const documentation = coreDocumentation.clone();
|
||||
const generator = new TypesGenerator({
|
||||
documentation,
|
||||
doNotGenerate: assertionClasses,
|
||||
includeExperimental,
|
||||
});
|
||||
let types = await generator.generateTypes(path.join(__dirname, 'overrides.d.ts'));
|
||||
const namedDevices = Object.keys(devices).map(name => ` ${JSON.stringify(name)}: DeviceDescriptor;`).join('\n');
|
||||
@ -534,10 +542,9 @@ class TypesGenerator {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} includeExperimental
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async function generateTestTypes(includeExperimental) {
|
||||
async function generateTestTypes() {
|
||||
const documentation = coreDocumentation.mergeWith(testDocumentation);
|
||||
const generator = new TypesGenerator({
|
||||
documentation,
|
||||
@ -574,16 +581,14 @@ class TypesGenerator {
|
||||
'TestFunction',
|
||||
]),
|
||||
doNotExportClassNames: assertionClasses,
|
||||
includeExperimental,
|
||||
});
|
||||
return await generator.generateTypes(path.join(__dirname, 'overrides-test.d.ts'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} includeExperimental
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async function generateReporterTypes(includeExperimental) {
|
||||
async function generateReporterTypes() {
|
||||
const documentation = coreDocumentation.mergeWith(testDocumentation).mergeWith(reporterDocumentation);
|
||||
const generator = new TypesGenerator({
|
||||
documentation,
|
||||
@ -601,7 +606,6 @@ class TypesGenerator {
|
||||
'JSONReportTestResult',
|
||||
'JSONReportTestStep',
|
||||
]),
|
||||
includeExperimental,
|
||||
});
|
||||
return await generator.generateTypes(path.join(__dirname, 'overrides-testReporter.d.ts'));
|
||||
}
|
||||
@ -629,9 +633,9 @@ class TypesGenerator {
|
||||
if (!fs.existsSync(playwrightTypesDir))
|
||||
fs.mkdirSync(playwrightTypesDir)
|
||||
writeFile(path.join(coreTypesDir, 'protocol.d.ts'), fs.readFileSync(path.join(PROJECT_DIR, 'packages', 'playwright-core', 'src', 'server', 'chromium', 'protocol.d.ts'), 'utf8'), false);
|
||||
writeFile(path.join(coreTypesDir, 'types.d.ts'), await generateCoreTypes(false), true);
|
||||
writeFile(path.join(playwrightTypesDir, 'test.d.ts'), await generateTestTypes(false), true);
|
||||
writeFile(path.join(playwrightTypesDir, 'testReporter.d.ts'), await generateReporterTypes(false), true);
|
||||
writeFile(path.join(coreTypesDir, 'types.d.ts'), await generateCoreTypes(), true);
|
||||
writeFile(path.join(playwrightTypesDir, 'test.d.ts'), await generateTestTypes(), true);
|
||||
writeFile(path.join(playwrightTypesDir, 'testReporter.d.ts'), await generateReporterTypes(), true);
|
||||
process.exit(0);
|
||||
})().catch(e => {
|
||||
console.error(e);
|
||||
|
Loading…
Reference in New Issue
Block a user