docs: linkify params and options (#32823)
References https://github.com/microsoft/playwright/issues/32590.
This commit is contained in:
Родитель
a9d5c39d40
Коммит
a2bdb2fd79
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -94,18 +94,20 @@ export interface FullResult {
|
|||
*
|
||||
* Here is a typical order of reporter calls:
|
||||
* - [reporter.onBegin(config, suite)](https://playwright.dev/docs/api/class-reporter#reporter-on-begin) is called
|
||||
* once with a root suite that contains all other suites and tests. Learn more about [suites hierarchy]{@link
|
||||
* Suite}.
|
||||
* once with a root suite that contains all other suites and tests. Learn more about
|
||||
* [suites hierarchy][Suite](https://playwright.dev/docs/api/class-suite).
|
||||
* - [reporter.onTestBegin(test, result)](https://playwright.dev/docs/api/class-reporter#reporter-on-test-begin) is
|
||||
* called for each test run. It is given a {@link TestCase} that is executed, and a {@link TestResult} that is
|
||||
* almost empty. Test result will be populated while the test runs (for example, with steps and stdio) and will
|
||||
* get final `status` once the test finishes.
|
||||
* called for each test run. It is given a [TestCase](https://playwright.dev/docs/api/class-testcase) that is
|
||||
* executed, and a [TestResult](https://playwright.dev/docs/api/class-testresult) that is almost empty. Test
|
||||
* result will be populated while the test runs (for example, with steps and stdio) and will get final `status`
|
||||
* once the test finishes.
|
||||
* - [reporter.onStepBegin(test, result, step)](https://playwright.dev/docs/api/class-reporter#reporter-on-step-begin)
|
||||
* and
|
||||
* [reporter.onStepEnd(test, result, step)](https://playwright.dev/docs/api/class-reporter#reporter-on-step-end)
|
||||
* are called for each executed step inside the test. When steps are executed, test run has not finished yet.
|
||||
* - [reporter.onTestEnd(test, result)](https://playwright.dev/docs/api/class-reporter#reporter-on-test-end) is
|
||||
* called when test run has finished. By this time, {@link TestResult} is complete and you can use
|
||||
* called when test run has finished. By this time, [TestResult](https://playwright.dev/docs/api/class-testresult)
|
||||
* is complete and you can use
|
||||
* [testResult.status](https://playwright.dev/docs/api/class-testresult#test-result-status),
|
||||
* [testResult.error](https://playwright.dev/docs/api/class-testresult#test-result-error) and more.
|
||||
* - [reporter.onEnd(result)](https://playwright.dev/docs/api/class-reporter#reporter-on-end) is called once after
|
||||
|
@ -128,12 +130,13 @@ export interface FullResult {
|
|||
* **Merged report API notes**
|
||||
*
|
||||
* When merging multiple [`blob`](https://playwright.dev/docs/test-reporters#blob-reporter) reports via
|
||||
* [`merge-reports`](https://playwright.dev/docs/test-sharding#merge-reports-cli) CLI command, the same {@link Reporter} API is called to
|
||||
* produce final reports and all existing reporters should work without any changes. There some subtle differences
|
||||
* though which might affect some custom reporters.
|
||||
* - Projects from different shards are always kept as separate {@link TestProject} objects. E.g. if project
|
||||
* 'Desktop Chrome' was sharded across 5 machines then there will be 5 instances of projects with the same name in
|
||||
* the config passed to
|
||||
* [`merge-reports`](https://playwright.dev/docs/test-sharding#merge-reports-cli) CLI command, the same
|
||||
* [Reporter](https://playwright.dev/docs/api/class-reporter) API is called to produce final reports and all existing
|
||||
* reporters should work without any changes. There some subtle differences though which might affect some custom
|
||||
* reporters.
|
||||
* - Projects from different shards are always kept as separate
|
||||
* [TestProject](https://playwright.dev/docs/api/class-testproject) objects. E.g. if project 'Desktop Chrome' was
|
||||
* sharded across 5 machines then there will be 5 instances of projects with the same name in the config passed to
|
||||
* [reporter.onBegin(config, suite)](https://playwright.dev/docs/api/class-reporter#reporter-on-begin).
|
||||
*/
|
||||
export interface Reporter {
|
||||
|
@ -151,8 +154,8 @@ export interface Reporter {
|
|||
*/
|
||||
onEnd?(result: FullResult): Promise<{ status?: FullResult['status'] } | undefined | void> | void;
|
||||
/**
|
||||
* Called once before running tests. All tests have been already discovered and put into a hierarchy of {@link
|
||||
* Suite}s.
|
||||
* Called once before running tests. All tests have been already discovered and put into a hierarchy of
|
||||
* [Suite](https://playwright.dev/docs/api/class-suite)s.
|
||||
* @param config Resolved configuration.
|
||||
* @param suite The root suite that contains all projects, files and test cases.
|
||||
*/
|
||||
|
@ -321,16 +324,16 @@ export {};
|
|||
|
||||
/**
|
||||
* `Suite` is a group of tests. All tests in Playwright Test form the following hierarchy:
|
||||
* - Root suite has a child suite for each {@link FullProject}.
|
||||
* - Root suite has a child suite for each [FullProject](https://playwright.dev/docs/api/class-fullproject).
|
||||
* - Project suite #1. Has a child suite for each test file in the project.
|
||||
* - File suite #1
|
||||
* - {@link TestCase} #1
|
||||
* - {@link TestCase} #2
|
||||
* - [TestCase](https://playwright.dev/docs/api/class-testcase) #1
|
||||
* - [TestCase](https://playwright.dev/docs/api/class-testcase) #2
|
||||
* - Suite corresponding to a
|
||||
* [test.describe([title, details, callback])](https://playwright.dev/docs/api/class-test#test-describe)
|
||||
* group
|
||||
* - {@link TestCase} #1 in a group
|
||||
* - {@link TestCase} #2 in a group
|
||||
* - [TestCase](https://playwright.dev/docs/api/class-testcase) #1 in a group
|
||||
* - [TestCase](https://playwright.dev/docs/api/class-testcase) #2 in a group
|
||||
* - < more test cases ... >
|
||||
* - File suite #2
|
||||
* - < more file suites ... >
|
||||
|
@ -376,7 +379,7 @@ export interface Suite {
|
|||
parent?: Suite;
|
||||
|
||||
/**
|
||||
* Child suites. See {@link Suite} for the hierarchy of suites.
|
||||
* Child suites. See [Suite](https://playwright.dev/docs/api/class-suite) for the hierarchy of suites.
|
||||
*/
|
||||
suites: Array<Suite>;
|
||||
|
||||
|
@ -578,7 +581,7 @@ export interface TestError {
|
|||
}
|
||||
|
||||
/**
|
||||
* A result of a single {@link TestCase} run.
|
||||
* A result of a single [TestCase](https://playwright.dev/docs/api/class-testcase) run.
|
||||
*/
|
||||
export interface TestResult {
|
||||
/**
|
||||
|
|
|
@ -45,9 +45,8 @@ const md = require('../markdown');
|
|||
* @typedef {function({
|
||||
* clazz?: Class,
|
||||
* member?: Member,
|
||||
* param?: string,
|
||||
* option?: string,
|
||||
* optionFullPath?: string,
|
||||
* param?: { name: string, alias: string },
|
||||
* option?: { name: string, alias: string },
|
||||
* href?: string,
|
||||
* }): string|undefined} Renderer
|
||||
*/
|
||||
|
@ -742,7 +741,7 @@ function patchLinksInText(classOrMember, text, classesMap, membersMap, linkRende
|
|||
return linkRenderer({ member, href }) || match;
|
||||
}
|
||||
if (p1 === 'param' || p1 === 'option') {
|
||||
let /** @type {string } */ alias;
|
||||
let /** @type {string } */ name;
|
||||
let /** @type {Member} */ member;
|
||||
if (p2.includes('.')) {
|
||||
// fully-qualified name
|
||||
|
@ -751,7 +750,7 @@ function patchLinksInText(classOrMember, text, classesMap, membersMap, linkRende
|
|||
if (!maybeMember)
|
||||
throw new Error(`Undefined reference: ${match}\n=========\n${text}`);
|
||||
member = maybeMember;
|
||||
alias = rest.join('.');
|
||||
name = rest.join('.');
|
||||
} else {
|
||||
// non-fully-qualified param/option reference from the same method.
|
||||
if (!classOrMember || !(classOrMember instanceof Member)) {
|
||||
|
@ -762,23 +761,23 @@ function patchLinksInText(classOrMember, text, classesMap, membersMap, linkRende
|
|||
if (!maybeMember)
|
||||
throw new Error(`Undefined reference: ${match}\n=========\n${text}`);
|
||||
member = maybeMember;
|
||||
alias = p2;
|
||||
name = p2;
|
||||
}
|
||||
if (p1 === 'param') {
|
||||
const param = member.argsArray.find(a => a.name === alias);
|
||||
const param = member.argsArray.find(a => a.name === name);
|
||||
if (!param)
|
||||
throw new Error(`Referenced parameter ${match} not found in the parent method ${member.name}\n=========\n${text}`);
|
||||
alias = param.alias;
|
||||
return linkRenderer({ member, param: alias, href }) || match;
|
||||
return linkRenderer({ member, param: { name, alias: param.alias }, href }) || match;
|
||||
} else {
|
||||
// p1 === 'option'
|
||||
const options = member.argsArray.find(a => a.name === 'options');
|
||||
const parts = alias.split('.');
|
||||
const option = options?.type?.properties?.find(a => a.name === parts[0]);
|
||||
const parts = name.split('.');
|
||||
const optionName = parts[0];
|
||||
const option = options?.type?.properties?.find(a => a.name === optionName);
|
||||
if (!option)
|
||||
throw new Error(`Referenced option ${match} not found in the parent method ${member.name}\n=========\n${text}`);
|
||||
parts[0] = option.alias;
|
||||
return linkRenderer({ member, option: parts[0], optionFullPath: parts.join('.'), href }) || match;
|
||||
return linkRenderer({ member, option: { name: optionName, alias: parts.join('.') }, href }) || match;
|
||||
}
|
||||
}
|
||||
throw new Error(`Undefined link prefix, expected event|method|property|param|option, got: ` + match);
|
||||
|
|
|
@ -25,9 +25,9 @@ const PROJECT_DIR = path.join(__dirname, '..', '..');
|
|||
documentation.setLinkRenderer(item => {
|
||||
const { clazz, param, option } = item;
|
||||
if (param)
|
||||
return `\`${param}\``;
|
||||
return `\`${param.alias}\``;
|
||||
if (option)
|
||||
return `\`${option}\``;
|
||||
return `\`${option.alias}\``;
|
||||
if (clazz)
|
||||
return `\`${clazz.name}\``;
|
||||
});
|
||||
|
|
|
@ -61,9 +61,9 @@ documentation.setLinkRenderer(item => {
|
|||
else if (item.member)
|
||||
return `<see cref="I${toTitleCase(item.member.clazz.name)}.${toMemberName(item.member)}${asyncSuffix}"/>`;
|
||||
else if (item.option)
|
||||
return `<paramref name="${item.option}"/>`;
|
||||
return `<paramref name="${item.option.name}"/>`;
|
||||
else if (item.param)
|
||||
return `<paramref name="${item.param}"/>`;
|
||||
return `<paramref name="${item.param.name}"/>`;
|
||||
else
|
||||
throw new Error('Unknown link format.');
|
||||
});
|
||||
|
|
|
@ -20,7 +20,16 @@
|
|||
const toKebabCase = require('lodash/kebabCase.js')
|
||||
const Documentation = require('./documentation');
|
||||
|
||||
function createMarkdownLink(languagePath, member, text) {
|
||||
/**
|
||||
* @param {string} languagePath
|
||||
* @param {Documentation.Member} member
|
||||
* @param {string} text
|
||||
* @param {string=} paramOrOption
|
||||
* @returns {string}
|
||||
*/
|
||||
function createMarkdownLink(languagePath, member, text, paramOrOption) {
|
||||
if (!member.clazz)
|
||||
throw new Error('Member without a class!');
|
||||
const className = toKebabCase(member.clazz.name);
|
||||
const memberName = toKebabCase(member.name);
|
||||
let hash = null;
|
||||
|
@ -28,6 +37,8 @@ function createMarkdownLink(languagePath, member, text) {
|
|||
hash = `${className}-${memberName}`.toLowerCase();
|
||||
else if (member.kind === 'event')
|
||||
hash = `${className}-event-${memberName}`.toLowerCase();
|
||||
if (paramOrOption)
|
||||
hash += '-option-' + toKebabCase(paramOrOption).toLowerCase();
|
||||
return `[${text}](https://playwright.dev${languagePath}/docs/api/class-${member.clazz.name.toLowerCase()}#${hash})`;
|
||||
};
|
||||
|
||||
|
@ -41,26 +52,21 @@ function createClassMarkdownLink(languagePath, clazz) {
|
|||
};
|
||||
|
||||
/**
|
||||
* @param {string} language
|
||||
* @param {string} language
|
||||
* @param {OutputType} outputType
|
||||
* @returns {Documentation.Renderer}
|
||||
*/
|
||||
function docsLinkRendererForLanguage(language, outputType) {
|
||||
const languagePath = languageToRelativeDocsPath(language);
|
||||
return ({ clazz, member, param, option }) => {
|
||||
if (param)
|
||||
return `\`${param}\``;
|
||||
if (option)
|
||||
return `\`${option}\``;
|
||||
if (clazz) {
|
||||
if (outputType === 'Types')
|
||||
return `{@link ${clazz.name}}`;
|
||||
if (outputType === 'ReleaseNotesMd')
|
||||
return createClassMarkdownLink(languagePath, clazz);
|
||||
throw new Error(`Unexpected output type ${outputType}`);
|
||||
}
|
||||
if (clazz)
|
||||
return createClassMarkdownLink(languagePath, clazz);
|
||||
if (!member || !member.clazz)
|
||||
throw new Error('Internal error');
|
||||
if (param)
|
||||
return createMarkdownLink(languagePath, member, `\`${param.alias}\``, param.name);
|
||||
if (option)
|
||||
return createMarkdownLink(languagePath, member, `\`${option.alias}\``, option.name);
|
||||
const className = member.clazz.varName === 'playwrightAssertions' ? '' : member.clazz.varName + '.';
|
||||
if (member.kind === 'method') {
|
||||
const args = outputType === 'ReleaseNotesMd' ? '' : renderJSSignature(member.argsArray);
|
||||
|
|
Загрузка…
Ссылка в новой задаче