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
|
### option: Route.continue.postData
|
||||||
* since: v1.8
|
* since: v1.8
|
||||||
|
* langs: js, python, java
|
||||||
- `postData` <[string]|[Buffer]>
|
- `postData` <[string]|[Buffer]>
|
||||||
|
|
||||||
If set changes the post data of request
|
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
|
### option: Route.continue.headers
|
||||||
* since: v1.8
|
* since: v1.8
|
||||||
- `headers` <[Object]<[string], [string]>>
|
- `headers` <[Object]<[string], [string]>>
|
||||||
|
|
@ -378,10 +386,18 @@ If set changes the request method (e.g. GET or POST)
|
||||||
|
|
||||||
### option: Route.fallback.postData
|
### option: Route.fallback.postData
|
||||||
* since: v1.23
|
* since: v1.23
|
||||||
|
* langs: js, python, java
|
||||||
- `postData` <[string]|[Buffer]>
|
- `postData` <[string]|[Buffer]>
|
||||||
|
|
||||||
If set changes the post data of request
|
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
|
### option: Route.fallback.headers
|
||||||
* since: v1.23
|
* since: v1.23
|
||||||
- `headers` <[Object]<[string], [string]>>
|
- `headers` <[Object]<[string], [string]>>
|
||||||
|
|
|
||||||
|
|
@ -103,8 +103,8 @@ First, add fixtures that will load the extension:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// fixtures.ts
|
// fixtures.ts
|
||||||
import { test as base, expect, chromium, type BrowserContext } from "@playwright/test";
|
import { test as base, expect, chromium, type BrowserContext } from '@playwright/test';
|
||||||
import path from "path";
|
import path from 'path';
|
||||||
|
|
||||||
export const test = base.extend<{
|
export const test = base.extend<{
|
||||||
context: BrowserContext;
|
context: BrowserContext;
|
||||||
|
|
@ -185,16 +185,16 @@ def extension_id(context) -> Generator[str, None, None]:
|
||||||
Then use these fixtures in a test:
|
Then use these fixtures in a test:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { test, expect } from "./fixtures";
|
import { test, expect } from './fixtures';
|
||||||
|
|
||||||
test("example test", async ({ page }) => {
|
test('example test', async ({ page }) => {
|
||||||
await page.goto("https://example.com");
|
await page.goto('https://example.com');
|
||||||
await expect(page.locator("body")).toHaveText("Changed by my-extension");
|
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 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
|
* }} Metainfo
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* csharpOptionOverloadsShortNotation?: boolean,
|
||||||
|
* }} LanguageOptions
|
||||||
|
*/
|
||||||
|
|
||||||
class Documentation {
|
class Documentation {
|
||||||
/**
|
/**
|
||||||
* @param {!Array<!Documentation.Class>} classesArray
|
* @param {!Array<!Documentation.Class>} classesArray
|
||||||
|
|
@ -104,13 +110,14 @@ class Documentation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} lang
|
* @param {string} lang
|
||||||
|
* @param {LanguageOptions=} options
|
||||||
*/
|
*/
|
||||||
filterForLanguage(lang) {
|
filterForLanguage(lang, options = {}) {
|
||||||
const classesArray = [];
|
const classesArray = [];
|
||||||
for (const clazz of this.classesArray) {
|
for (const clazz of this.classesArray) {
|
||||||
if (clazz.langs.only && !clazz.langs.only.includes(lang))
|
if (clazz.langs.only && !clazz.langs.only.includes(lang))
|
||||||
continue;
|
continue;
|
||||||
clazz.filterForLanguage(lang);
|
clazz.filterForLanguage(lang, options);
|
||||||
classesArray.push(clazz);
|
classesArray.push(clazz);
|
||||||
}
|
}
|
||||||
this.classesArray = classesArray;
|
this.classesArray = classesArray;
|
||||||
|
|
@ -259,13 +266,14 @@ Documentation.Class = class {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} lang
|
* @param {string} lang
|
||||||
|
* @param {LanguageOptions=} options
|
||||||
*/
|
*/
|
||||||
filterForLanguage(lang) {
|
filterForLanguage(lang, options = {}) {
|
||||||
const membersArray = [];
|
const membersArray = [];
|
||||||
for (const member of this.membersArray) {
|
for (const member of this.membersArray) {
|
||||||
if (member.langs.only && !member.langs.only.includes(lang))
|
if (member.langs.only && !member.langs.only.includes(lang))
|
||||||
continue;
|
continue;
|
||||||
member.filterForLanguage(lang);
|
member.filterForLanguage(lang, options);
|
||||||
membersArray.push(member);
|
membersArray.push(member);
|
||||||
}
|
}
|
||||||
this.membersArray = membersArray;
|
this.membersArray = membersArray;
|
||||||
|
|
@ -406,31 +414,41 @@ Documentation.Member = class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} lang
|
* @param {string} lang
|
||||||
|
* @param {LanguageOptions=} options
|
||||||
*/
|
*/
|
||||||
filterForLanguage(lang) {
|
filterForLanguage(lang, options = {}) {
|
||||||
if (!this.type)
|
if (!this.type)
|
||||||
return;
|
return;
|
||||||
if (this.langs.aliases && this.langs.aliases[lang])
|
if (this.langs.aliases && this.langs.aliases[lang])
|
||||||
this.alias = this.langs.aliases[lang];
|
this.alias = this.langs.aliases[lang];
|
||||||
if (this.langs.types && this.langs.types[lang])
|
if (this.langs.types && this.langs.types[lang])
|
||||||
this.type = this.langs.types[lang];
|
this.type = this.langs.types[lang];
|
||||||
this.type.filterForLanguage(lang);
|
this.type.filterForLanguage(lang, options);
|
||||||
const argsArray = [];
|
const argsArray = [];
|
||||||
for (const arg of this.argsArray) {
|
for (const arg of this.argsArray) {
|
||||||
if (arg.langs.only && !arg.langs.only.includes(lang))
|
if (arg.langs.only && !arg.langs.only.includes(lang))
|
||||||
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);
|
overriddenArg.filterForLanguage(lang, options);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (overriddenArg.name === 'options' && !overriddenArg.type.properties.length)
|
if (overriddenArg.name === 'options' && !overriddenArg.type.properties.length)
|
||||||
continue;
|
continue;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
overriddenArg.type.filterForLanguage(lang);
|
overriddenArg.type.filterForLanguage(lang, options);
|
||||||
argsArray.push(overriddenArg);
|
argsArray.push(overriddenArg);
|
||||||
}
|
}
|
||||||
this.argsArray = argsArray;
|
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() {
|
filterOutExperimental() {
|
||||||
|
|
@ -642,15 +660,16 @@ Documentation.Type = class {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} lang
|
* @param {string} lang
|
||||||
|
* @param {LanguageOptions=} options
|
||||||
*/
|
*/
|
||||||
filterForLanguage(lang) {
|
filterForLanguage(lang, options = {}) {
|
||||||
if (!this.properties)
|
if (!this.properties)
|
||||||
return;
|
return;
|
||||||
const properties = [];
|
const properties = [];
|
||||||
for (const prop of this.properties) {
|
for (const prop of this.properties) {
|
||||||
if (prop.langs.only && !prop.langs.only.includes(lang))
|
if (prop.langs.only && !prop.langs.only.includes(lang))
|
||||||
continue;
|
continue;
|
||||||
prop.filterForLanguage(lang);
|
prop.filterForLanguage(lang, options);
|
||||||
properties.push(prop);
|
properties.push(prop);
|
||||||
}
|
}
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
|
|
@ -839,4 +858,73 @@ function generateSourceCodeComment(spec) {
|
||||||
return md.render(comments, 120);
|
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;
|
module.exports = Documentation;
|
||||||
|
|
|
||||||
|
|
@ -287,7 +287,7 @@ function renderConstructors(name, type, out) {
|
||||||
function renderMember(member, parent, options, out) {
|
function renderMember(member, parent, options, out) {
|
||||||
const name = toMemberName(member);
|
const name = toMemberName(member);
|
||||||
if (member.kind === 'method') {
|
if (member.kind === 'method') {
|
||||||
renderMethod(member, parent, name, { mode: 'options', trimRunAndPrefix: options.trimRunAndPrefix }, out);
|
renderMethod(member, parent, name, { trimRunAndPrefix: options.trimRunAndPrefix }, out);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -348,12 +348,6 @@ function getPropertyOverloads(type, member, name, parent) {
|
||||||
if (member.type.expression === '[string]|[float]')
|
if (member.type.expression === '[string]|[float]')
|
||||||
jsonName = `${member.name}String`;
|
jsonName = `${member.name}String`;
|
||||||
overloads.push({ type, name, jsonName });
|
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;
|
return overloads;
|
||||||
}
|
}
|
||||||
|
|
@ -463,7 +457,6 @@ function generateEnumNameIfApplicable(type) {
|
||||||
* @param {Documentation.Class | Documentation.Type} parent
|
* @param {Documentation.Class | Documentation.Type} parent
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* @param {{
|
* @param {{
|
||||||
* mode: 'options'|'named'|'base',
|
|
||||||
* nodocs?: boolean,
|
* nodocs?: boolean,
|
||||||
* abstract?: boolean,
|
* abstract?: boolean,
|
||||||
* public?: boolean,
|
* public?: boolean,
|
||||||
|
|
@ -556,16 +549,12 @@ function renderMethod(member, parent, name, options, out) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (arg.name === 'options') {
|
if (arg.name === 'options') {
|
||||||
if (options.mode === 'options' || options.mode === 'base') {
|
const optionsType = rewriteSuggestedOptionsName(member.clazz.name + name.replace('<T>', '') + 'Options');
|
||||||
const optionsType = rewriteSuggestedOptionsName(member.clazz.name + name.replace('<T>', '') + 'Options');
|
if (!optionTypes.has(optionsType) || arg.type.properties.length > optionTypes.get(optionsType).properties.length)
|
||||||
if (!optionTypes.has(optionsType) || arg.type.properties.length > optionTypes.get(optionsType).properties.length)
|
optionTypes.set(optionsType, arg.type);
|
||||||
optionTypes.set(optionsType, arg.type);
|
args.push(`${optionsType}? options = default`);
|
||||||
args.push(`${optionsType}? options = default`);
|
argTypeMap.set(`${optionsType}? options = default`, 'options');
|
||||||
argTypeMap.set(`${optionsType}? options = default`, 'options');
|
addParamsDoc('options', ['Call options']);
|
||||||
addParamsDoc('options', ['Call options']);
|
|
||||||
} else {
|
|
||||||
arg.type.properties.forEach(processArg);
|
|
||||||
}
|
|
||||||
return;
|
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
|
.sort((a, b) => b.alias === 'options' ? -1 : 0) // move options to the back to the arguments list
|
||||||
.forEach(processArg);
|
.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 (!explodedArgs.length) {
|
||||||
if (!options.nodocs) {
|
if (!options.nodocs) {
|
||||||
out.push(...XmlDoc.renderXmlDoc(member.spec, maxDocumentationColumnWidth));
|
out.push(...XmlDoc.renderXmlDoc(member.spec, maxDocumentationColumnWidth));
|
||||||
|
|
@ -670,7 +628,7 @@ function renderMethod(member, parent, name, options, out) {
|
||||||
}
|
}
|
||||||
if (member.deprecated)
|
if (member.deprecated)
|
||||||
out.push(`[System.Obsolete]`);
|
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 {
|
} else {
|
||||||
let containsOptionalExplodedArgs = false;
|
let containsOptionalExplodedArgs = false;
|
||||||
explodedArgs.forEach((explodedArg, argIndex) => {
|
explodedArgs.forEach((explodedArg, argIndex) => {
|
||||||
|
|
@ -692,7 +650,7 @@ function renderMethod(member, parent, name, options, out) {
|
||||||
overloadedArgs.push(arg);
|
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)
|
if (argIndex < explodedArgs.length - 1)
|
||||||
out.push(''); // output a special blank line
|
out.push(''); // output a special blank line
|
||||||
});
|
});
|
||||||
|
|
@ -712,7 +670,7 @@ function renderMethod(member, parent, name, options, out) {
|
||||||
if (!options.nodocs)
|
if (!options.nodocs)
|
||||||
printArgDoc(argType, paramDocs.get(argType), out);
|
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 {string} name
|
||||||
* @param {boolean} convert
|
* @param {boolean} convert
|
||||||
|
|
@ -895,7 +845,7 @@ function toAsync(name, convert) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} suggestedName
|
* @param {string} suggestedName
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function rewriteSuggestedOptionsName(suggestedName) {
|
function rewriteSuggestedOptionsName(suggestedName) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue