chore: multiply overloaded options in csharp (#18818)
This way we'll get the same treatment in docs generator as well as dotnet api generator. This also adds non-suffixed aliases for string options, e.g. `Name` in addition to `NameString` and `NameRegex`. Fixes #18407.
This commit is contained in:
parent
210a57ea3b
commit
0387d96cd5
|
|
@ -112,10 +112,18 @@ If set changes the request method (e.g. GET or POST)
|
|||
|
||||
### option: Route.continue.postData
|
||||
* since: v1.8
|
||||
* langs: js, python, java
|
||||
- `postData` <[string]|[Buffer]>
|
||||
|
||||
If set changes the post data of request
|
||||
|
||||
### option: Route.continue.postData
|
||||
* since: v1.8
|
||||
* langs: csharp
|
||||
- `postData` <[Buffer]>
|
||||
|
||||
If set changes the post data of request
|
||||
|
||||
### option: Route.continue.headers
|
||||
* since: v1.8
|
||||
- `headers` <[Object]<[string], [string]>>
|
||||
|
|
@ -378,10 +386,18 @@ If set changes the request method (e.g. GET or POST)
|
|||
|
||||
### option: Route.fallback.postData
|
||||
* since: v1.23
|
||||
* langs: js, python, java
|
||||
- `postData` <[string]|[Buffer]>
|
||||
|
||||
If set changes the post data of request
|
||||
|
||||
### option: Route.fallback.postData
|
||||
* since: v1.23
|
||||
* langs: csharp
|
||||
- `postData` <[Buffer]>
|
||||
|
||||
If set changes the post data of request
|
||||
|
||||
### option: Route.fallback.headers
|
||||
* since: v1.23
|
||||
- `headers` <[Object]<[string], [string]>>
|
||||
|
|
|
|||
|
|
@ -103,8 +103,8 @@ First, add fixtures that will load the extension:
|
|||
|
||||
```ts
|
||||
// fixtures.ts
|
||||
import { test as base, expect, chromium, type BrowserContext } from "@playwright/test";
|
||||
import path from "path";
|
||||
import { test as base, expect, chromium, type BrowserContext } from '@playwright/test';
|
||||
import path from 'path';
|
||||
|
||||
export const test = base.extend<{
|
||||
context: BrowserContext;
|
||||
|
|
@ -185,16 +185,16 @@ def extension_id(context) -> Generator[str, None, None]:
|
|||
Then use these fixtures in a test:
|
||||
|
||||
```ts
|
||||
import { test, expect } from "./fixtures";
|
||||
import { test, expect } from './fixtures';
|
||||
|
||||
test("example test", async ({ page }) => {
|
||||
await page.goto("https://example.com");
|
||||
await expect(page.locator("body")).toHaveText("Changed by my-extension");
|
||||
test('example test', async ({ page }) => {
|
||||
await page.goto('https://example.com');
|
||||
await expect(page.locator('body')).toHaveText('Changed by my-extension');
|
||||
});
|
||||
|
||||
test("popup page", async ({ page, extensionId }) => {
|
||||
test('popup page', async ({ page, extensionId }) => {
|
||||
await page.goto(`chrome-extension://${extensionId}/popup.html`);
|
||||
await expect(page.locator("body")).toHaveText("my-extension popup");
|
||||
await expect(page.locator('body')).toHaveText('my-extension popup');
|
||||
});
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,12 @@ const md = require('../markdown');
|
|||
* }} Metainfo
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* csharpOptionOverloadsShortNotation?: boolean,
|
||||
* }} LanguageOptions
|
||||
*/
|
||||
|
||||
class Documentation {
|
||||
/**
|
||||
* @param {!Array<!Documentation.Class>} classesArray
|
||||
|
|
@ -104,13 +110,14 @@ class Documentation {
|
|||
|
||||
/**
|
||||
* @param {string} lang
|
||||
* @param {LanguageOptions=} options
|
||||
*/
|
||||
filterForLanguage(lang) {
|
||||
filterForLanguage(lang, options = {}) {
|
||||
const classesArray = [];
|
||||
for (const clazz of this.classesArray) {
|
||||
if (clazz.langs.only && !clazz.langs.only.includes(lang))
|
||||
continue;
|
||||
clazz.filterForLanguage(lang);
|
||||
clazz.filterForLanguage(lang, options);
|
||||
classesArray.push(clazz);
|
||||
}
|
||||
this.classesArray = classesArray;
|
||||
|
|
@ -259,13 +266,14 @@ Documentation.Class = class {
|
|||
|
||||
/**
|
||||
* @param {string} lang
|
||||
* @param {LanguageOptions=} options
|
||||
*/
|
||||
filterForLanguage(lang) {
|
||||
filterForLanguage(lang, options = {}) {
|
||||
const membersArray = [];
|
||||
for (const member of this.membersArray) {
|
||||
if (member.langs.only && !member.langs.only.includes(lang))
|
||||
continue;
|
||||
member.filterForLanguage(lang);
|
||||
member.filterForLanguage(lang, options);
|
||||
membersArray.push(member);
|
||||
}
|
||||
this.membersArray = membersArray;
|
||||
|
|
@ -408,29 +416,39 @@ Documentation.Member = class {
|
|||
|
||||
/**
|
||||
* @param {string} lang
|
||||
* @param {LanguageOptions=} options
|
||||
*/
|
||||
filterForLanguage(lang) {
|
||||
filterForLanguage(lang, options = {}) {
|
||||
if (!this.type)
|
||||
return;
|
||||
if (this.langs.aliases && this.langs.aliases[lang])
|
||||
this.alias = this.langs.aliases[lang];
|
||||
if (this.langs.types && this.langs.types[lang])
|
||||
this.type = this.langs.types[lang];
|
||||
this.type.filterForLanguage(lang);
|
||||
this.type.filterForLanguage(lang, options);
|
||||
const argsArray = [];
|
||||
for (const arg of this.argsArray) {
|
||||
if (arg.langs.only && !arg.langs.only.includes(lang))
|
||||
continue;
|
||||
const overriddenArg = (arg.langs.overrides && arg.langs.overrides[lang]) || arg;
|
||||
overriddenArg.filterForLanguage(lang);
|
||||
overriddenArg.filterForLanguage(lang, options);
|
||||
// @ts-ignore
|
||||
if (overriddenArg.name === 'options' && !overriddenArg.type.properties.length)
|
||||
continue;
|
||||
// @ts-ignore
|
||||
overriddenArg.type.filterForLanguage(lang);
|
||||
overriddenArg.type.filterForLanguage(lang, options);
|
||||
argsArray.push(overriddenArg);
|
||||
}
|
||||
this.argsArray = argsArray;
|
||||
|
||||
const optionsArg = this.argsArray.find(arg => arg.name === 'options');
|
||||
if (lang === 'csharp' && optionsArg) {
|
||||
try {
|
||||
patchCSharpOptionOverloads(optionsArg, options);
|
||||
} catch (e) {
|
||||
throw new Error(`Error processing csharp options in ${this.clazz?.name}.${this.name}: ` + e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filterOutExperimental() {
|
||||
|
|
@ -642,15 +660,16 @@ Documentation.Type = class {
|
|||
|
||||
/**
|
||||
* @param {string} lang
|
||||
* @param {LanguageOptions=} options
|
||||
*/
|
||||
filterForLanguage(lang) {
|
||||
filterForLanguage(lang, options = {}) {
|
||||
if (!this.properties)
|
||||
return;
|
||||
const properties = [];
|
||||
for (const prop of this.properties) {
|
||||
if (prop.langs.only && !prop.langs.only.includes(lang))
|
||||
continue;
|
||||
prop.filterForLanguage(lang);
|
||||
prop.filterForLanguage(lang, options);
|
||||
properties.push(prop);
|
||||
}
|
||||
this.properties = properties;
|
||||
|
|
@ -839,4 +858,73 @@ function generateSourceCodeComment(spec) {
|
|||
return md.render(comments, 120);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Documentation.Member} optionsArg
|
||||
* @param {LanguageOptions=} options
|
||||
*/
|
||||
function patchCSharpOptionOverloads(optionsArg, options = {}) {
|
||||
const props = optionsArg.type?.properties;
|
||||
if (!props)
|
||||
return;
|
||||
const propsToDelete = new Set();
|
||||
const propsToAdd = [];
|
||||
for (const prop of props) {
|
||||
const union = prop.type?.union;
|
||||
if (!union)
|
||||
continue;
|
||||
const isEnum = union[0].name.startsWith('"');
|
||||
const isNullable = union.length === 2 && union.some(type => type.name === 'null');
|
||||
if (isEnum || isNullable)
|
||||
continue;
|
||||
|
||||
const shortNotation = [];
|
||||
propsToDelete.add(prop);
|
||||
for (const type of union) {
|
||||
const suffix = csharpOptionOverloadSuffix(prop.name, type.name);
|
||||
if (options.csharpOptionOverloadsShortNotation) {
|
||||
if (type.name === 'string')
|
||||
shortNotation.push(prop.alias);
|
||||
else
|
||||
shortNotation.push(prop.alias + suffix);
|
||||
continue;
|
||||
}
|
||||
|
||||
const newProp = prop.clone();
|
||||
newProp.name = prop.name + suffix;
|
||||
newProp.alias = prop.alias + suffix;
|
||||
newProp.type = type;
|
||||
propsToAdd.push(newProp);
|
||||
|
||||
if (type.name === 'string') {
|
||||
const stringProp = prop.clone();
|
||||
stringProp.type = type;
|
||||
propsToAdd.push(stringProp);
|
||||
}
|
||||
}
|
||||
if (options.csharpOptionOverloadsShortNotation) {
|
||||
const newProp = prop.clone();
|
||||
newProp.alias = newProp.name = shortNotation.join('|');
|
||||
propsToAdd.push(newProp);
|
||||
}
|
||||
}
|
||||
for (const prop of propsToDelete)
|
||||
props.splice(props.indexOf(prop), 1);
|
||||
props.push(...propsToAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} option
|
||||
* @param {string} type
|
||||
*/
|
||||
function csharpOptionOverloadSuffix(option, type) {
|
||||
switch (type) {
|
||||
case 'string': return 'String';
|
||||
case 'RegExp': return 'Regex';
|
||||
case 'function': return 'Func';
|
||||
case 'Buffer': return 'Byte';
|
||||
case 'Serializable': return 'Object';
|
||||
}
|
||||
throw new Error(`CSharp option "${option}" has unsupported type overload "${type}"`);
|
||||
}
|
||||
|
||||
module.exports = Documentation;
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ function renderConstructors(name, type, out) {
|
|||
function renderMember(member, parent, options, out) {
|
||||
const name = toMemberName(member);
|
||||
if (member.kind === 'method') {
|
||||
renderMethod(member, parent, name, { mode: 'options', trimRunAndPrefix: options.trimRunAndPrefix }, out);
|
||||
renderMethod(member, parent, name, { trimRunAndPrefix: options.trimRunAndPrefix }, out);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -348,12 +348,6 @@ function getPropertyOverloads(type, member, name, parent) {
|
|||
if (member.type.expression === '[string]|[float]')
|
||||
jsonName = `${member.name}String`;
|
||||
overloads.push({ type, name, jsonName });
|
||||
} else {
|
||||
for (const overload of member.type.union) {
|
||||
const t = translateType(overload, parent, t => generateNameDefault(member, name, t, parent));
|
||||
const suffix = toOverloadSuffix(t);
|
||||
overloads.push({ type: t, name: name + suffix, jsonName: member.name + suffix });
|
||||
}
|
||||
}
|
||||
return overloads;
|
||||
}
|
||||
|
|
@ -463,7 +457,6 @@ function generateEnumNameIfApplicable(type) {
|
|||
* @param {Documentation.Class | Documentation.Type} parent
|
||||
* @param {string} name
|
||||
* @param {{
|
||||
* mode: 'options'|'named'|'base',
|
||||
* nodocs?: boolean,
|
||||
* abstract?: boolean,
|
||||
* public?: boolean,
|
||||
|
|
@ -556,16 +549,12 @@ function renderMethod(member, parent, name, options, out) {
|
|||
return;
|
||||
|
||||
if (arg.name === 'options') {
|
||||
if (options.mode === 'options' || options.mode === 'base') {
|
||||
const optionsType = rewriteSuggestedOptionsName(member.clazz.name + name.replace('<T>', '') + 'Options');
|
||||
if (!optionTypes.has(optionsType) || arg.type.properties.length > optionTypes.get(optionsType).properties.length)
|
||||
optionTypes.set(optionsType, arg.type);
|
||||
args.push(`${optionsType}? options = default`);
|
||||
argTypeMap.set(`${optionsType}? options = default`, 'options');
|
||||
addParamsDoc('options', ['Call options']);
|
||||
} else {
|
||||
arg.type.properties.forEach(processArg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -632,37 +621,6 @@ function renderMethod(member, parent, name, options, out) {
|
|||
.sort((a, b) => b.alias === 'options' ? -1 : 0) // move options to the back to the arguments list
|
||||
.forEach(processArg);
|
||||
|
||||
let body = ';';
|
||||
if (options.mode === 'base') {
|
||||
// Generate options -> named transition.
|
||||
const tokens = [];
|
||||
for (const arg of member.argsArray) {
|
||||
if (arg.name === 'action' && options.trimRunAndPrefix)
|
||||
continue;
|
||||
if (arg.name !== 'options') {
|
||||
tokens.push(toArgumentName(arg.name));
|
||||
continue;
|
||||
}
|
||||
for (const opt of arg.type.properties) {
|
||||
// TODO: use translate type here?
|
||||
if (opt.type.union && !opt.type.union[0].name.startsWith('"') && opt.type.union[0].name !== 'null' && opt.type.expression !== '[string]|[Buffer]') {
|
||||
// Explode overloads.
|
||||
for (const t of opt.type.union) {
|
||||
const suffix = toOverloadSuffix(translateType(t, parent));
|
||||
tokens.push(`${opt.name}${suffix}: options.${toMemberName(opt)}${suffix}`);
|
||||
}
|
||||
} else {
|
||||
tokens.push(`${opt.alias || opt.name}: options.${toMemberName(opt)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
body = `
|
||||
{
|
||||
options ??= new ${member.clazz.name}${name}Options();
|
||||
return ${toAsync(name, member.async)}(${tokens.join(', ')});
|
||||
}`;
|
||||
}
|
||||
|
||||
if (!explodedArgs.length) {
|
||||
if (!options.nodocs) {
|
||||
out.push(...XmlDoc.renderXmlDoc(member.spec, maxDocumentationColumnWidth));
|
||||
|
|
@ -670,7 +628,7 @@ function renderMethod(member, parent, name, options, out) {
|
|||
}
|
||||
if (member.deprecated)
|
||||
out.push(`[System.Obsolete]`);
|
||||
out.push(`${modifiers}${type} ${toAsync(name, member.async)}(${args.join(', ')})${body}`);
|
||||
out.push(`${modifiers}${type} ${toAsync(name, member.async)}(${args.join(', ')});`);
|
||||
} else {
|
||||
let containsOptionalExplodedArgs = false;
|
||||
explodedArgs.forEach((explodedArg, argIndex) => {
|
||||
|
|
@ -692,7 +650,7 @@ function renderMethod(member, parent, name, options, out) {
|
|||
overloadedArgs.push(arg);
|
||||
}
|
||||
}
|
||||
out.push(`${modifiers}${type} ${toAsync(name, member.async)}(${overloadedArgs.join(', ')})${body}`);
|
||||
out.push(`${modifiers}${type} ${toAsync(name, member.async)}(${overloadedArgs.join(', ')});`);
|
||||
if (argIndex < explodedArgs.length - 1)
|
||||
out.push(''); // output a special blank line
|
||||
});
|
||||
|
|
@ -712,7 +670,7 @@ function renderMethod(member, parent, name, options, out) {
|
|||
if (!options.nodocs)
|
||||
printArgDoc(argType, paramDocs.get(argType), out);
|
||||
});
|
||||
out.push(`${type} ${name}(${filteredArgs.join(', ')})${body}`);
|
||||
out.push(`${type} ${name}(${filteredArgs.join(', ')});`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -874,14 +832,6 @@ function printArgDoc(name, value, out) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} typeName
|
||||
* @return {string}
|
||||
*/
|
||||
function toOverloadSuffix(typeName) {
|
||||
return toTitleCase(typeName.replace(/[<].*[>]/, '').replace(/[^a-zA-Z]/g, ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {boolean} convert
|
||||
|
|
|
|||
Loading…
Reference in a new issue