From 388e6c154ef3dba7da955606a81c908dc680af6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20LES=C3=89N=C3=89CHAL?= Date: Wed, 1 Jul 2026 16:56:59 +0200 Subject: [PATCH 1/3] Update types --- index.d.ts | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/index.d.ts b/index.d.ts index 9f325ea..df462cf 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1313,12 +1313,6 @@ export interface DiscussionToolsApiDiscussionToolsEditParams extends ApiParams { * - **addtopic**: Add a new discussion section and the first comment in it. */ paction?: "addcomment" | "addtopic"; - /** - * Automatically subscribe the user to the talk page thread? - * - * Defaults to `default`. - */ - autosubscribe?: "default" | "no" | "yes"; /** * The page to perform actions on. */ @@ -3703,7 +3697,7 @@ export interface PageTriageApiPageTriageStatsParams extends ApiParams { */ show_predicted_issues_copyvio?: boolean; /** - * Whether to include only pages created by bots. + * Whether to include only pages created by bots. */ showbots?: boolean; /** @@ -3739,31 +3733,31 @@ export interface PageTriageApiPageTriageStatsParams extends ApiParams { */ afc_state?: number; /** - * Whether to include only pages with no category. + * Whether to include only pages with no category. */ no_category?: boolean; /** - * Whether to include only pages with no references. + * Whether to include only pages with no references. */ unreferenced?: boolean; /** - * Whether to include only pages with no inbound links. + * Whether to include only pages with no inbound links. */ no_inbound_links?: boolean; /** - * Whether to include only pages that were previously deleted. + * Whether to include only pages that were previously deleted. */ recreated?: boolean; /** - * Whether to include only pages created by non-autoconfirmed users. + * Whether to include only pages created by non-autoconfirmed users. */ non_autoconfirmed_users?: boolean; /** - * Whether to include only pages created by newly autoconfirmed users. + * Whether to include only pages created by newly autoconfirmed users. */ learners?: boolean; /** - * Whether to include only pages created by blocked users. + * Whether to include only pages created by blocked users. */ blocked_users?: boolean; /** @@ -4091,6 +4085,7 @@ export interface ApiParseParams extends ApiParams { * - **properties**: Gives various properties defined in the parsed wikitext. * - **limitreportdata**: Gives the limit report in a structured way. Gives no data, when `disablelimitreport` is set. * - **limitreporthtml**: Gives the HTML version of the limit report. Gives no data, when `disablelimitreport` is set. + * - **parseroutput**: Internal. Gives the JSON-serialized `ParserOutput` object for the parsed content. The format of this property may change at any time; {@link https://www.mediawiki.org/wiki/Manual:Parser_cache/Serialization_compatibility mw:Manual:Parser cache/Serialization compatibility} does not provide any guarantee of API stability. * - **parsetree**: The XML parse tree of revision content (requires content model `wikitext`) * - **parsewarnings**: Gives the warnings that occurred while parsing content (as wikitext). * - **parsewarningshtml**: Gives the warnings that occurred while parsing content (as HTML). @@ -4114,6 +4109,7 @@ export interface ApiParseParams extends ApiParams { | "limitreporthtml" | "links" | "modules" + | "parseroutput" | "parsetree" | "parsewarnings" | "parsewarningshtml" @@ -7298,6 +7294,7 @@ export interface ApiQueryAllImagesParams extends ApiQueryParams { * - **dimensions**: Alias for size. * - **sha1**: Adds SHA-1 hash for the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **mime**: Adds MIME type of the file. If the file has been revision deleted, a `filehidden` property will be returned. + * - **thumburls**: Adds thumbnail URLs of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **mediatype**: Adds the media type of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **metadata**: Lists Exif metadata for the version of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **commonmetadata**: Lists file format generic metadata for the version of the file. If the file has been revision deleted, a `filehidden` property will be returned. @@ -7323,6 +7320,7 @@ export interface ApiQueryAllImagesParams extends ApiQueryParams { | "parsedcomment" | "sha1" | "size" + | "thumburls" | "timestamp" | "url" | "user" @@ -10097,6 +10095,7 @@ export interface ApiQueryImageInfoParams extends ApiQueryParams { * - **sha1**: Adds SHA-1 hash for the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **mime**: Adds MIME type of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **thumbmime**: Adds MIME type of the image thumbnail (requires url and param iiurlwidth). If the file has been revision deleted, a `filehidden` property will be returned. + * - **thumburls**: Adds thumbnail URLs of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **mediatype**: Adds the media type of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **metadata**: Lists Exif metadata for the version of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **commonmetadata**: Lists file format generic metadata for the version of the file. If the file has been revision deleted, a `filehidden` property will be returned. @@ -10126,6 +10125,7 @@ export interface ApiQueryImageInfoParams extends ApiQueryParams { | "sha1" | "size" | "thumbmime" + | "thumburls" | "timestamp" | "uploadwarning" | "url" @@ -12331,6 +12331,7 @@ export interface ApiQuerySiteinfoParams extends ApiQueryParams { * - **autopromote**: Returns the automatic promotion configuration. * - **autopromoteonce**: Returns the automatic promotion configuration that are only done once. * - **copyuploaddomains**: Returns the list of allowed copy upload domains + * - **crosssiteajaxdomains**: Returns the list of allowed CORS domains * - **sbom**: Returns a Software Bill of Materials (SBOM) for the MediaWiki installation in the CycloneDX 1.6 format. * * Defaults to `general`. @@ -12341,6 +12342,7 @@ export interface ApiQuerySiteinfoParams extends ApiQueryParams { | "autopromoteonce" | "clientlibraries" | "copyuploaddomains" + | "crosssiteajaxdomains" | "dbrepllag" | "defaultoptions" | "doubleunderscores" @@ -12438,6 +12440,7 @@ export interface ApiQueryStashImageInfoParams extends ApiQueryParams { * - **sha1**: Adds SHA-1 hash for the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **mime**: Adds MIME type of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **thumbmime**: Adds MIME type of the image thumbnail (requires url and param siiurlwidth). If the file has been revision deleted, a `filehidden` property will be returned. + * - **thumburls**: Adds thumbnail URLs of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **metadata**: Lists Exif metadata for the version of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **commonmetadata**: Lists file format generic metadata for the version of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **extmetadata**: Lists formatted metadata combined from multiple sources. Results are HTML formatted. If the file has been revision deleted, a `filehidden` property will be returned. @@ -12460,6 +12463,7 @@ export interface ApiQueryStashImageInfoParams extends ApiQueryParams { | "sha1" | "size" | "thumbmime" + | "thumburls" | "timestamp" | "url" >; @@ -12925,6 +12929,7 @@ export interface TimedMediaHandlerApiQueryVideoInfoParams extends ApiQueryParams * - **sha1**: Adds SHA-1 hash for the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **mime**: Adds MIME type of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **thumbmime**: Adds MIME type of the image thumbnail (requires url and param viurlwidth). If the file has been revision deleted, a `filehidden` property will be returned. + * - **thumburls**: Adds thumbnail URLs of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **mediatype**: Adds the media type of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **metadata**: Lists Exif metadata for the version of the file. If the file has been revision deleted, a `filehidden` property will be returned. * - **commonmetadata**: Lists file format generic metadata for the version of the file. If the file has been revision deleted, a `filehidden` property will be returned. @@ -12957,6 +12962,7 @@ export interface TimedMediaHandlerApiQueryVideoInfoParams extends ApiQueryParams | "sha1" | "size" | "thumbmime" + | "thumburls" | "timedtext" | "timestamp" | "uploadwarning" From 7485dc4f0fab3585edcec8fa5745aac89c832354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20LES=C3=89N=C3=89CHAL?= Date: Wed, 1 Jul 2026 17:01:48 +0200 Subject: [PATCH 2/3] feat: Add templated parameters --- index.d.ts | 60 ++++++++++++++++++++++++++++++++++ scripts/api-types-generator.js | 44 ++++++++++++++++++++++--- 2 files changed, 99 insertions(+), 5 deletions(-) diff --git a/index.d.ts b/index.d.ts index df462cf..2bfe742 100644 --- a/index.d.ts +++ b/index.d.ts @@ -720,6 +720,22 @@ export interface ApiComparePagesParams extends ApiParams { * This parameter specifies the slots that are to be modified. Use `fromtext-{slot}`, `fromcontentmodel-{slot}`, and `fromcontentformat-{slot}` to specify content for each slot. */ fromslots?: OneOrMore<"main">; + /** + * Text of the specified slot. If omitted, the slot is removed from the revision. + */ + [k: `fromtext-${string}`]: string; + /** + * When `fromtext-{slot}` is the content of a single section, this is the section identifier. It will be merged into the revision specified by `fromtitle`, `fromid` or `fromrev` as if for a section edit. + */ + [k: `fromsection-${string}`]: string; + /** + * Content serialization format of `fromtext-{slot}`. + */ + [k: `fromcontentformat-${string}`]: string; + /** + * Content model of `fromtext-{slot}`. If not supplied, it will be guessed based on the other parameters. + */ + [k: `fromcontentmodel-${string}`]: string; /** * Do a pre-save transform on `fromtext-{slot}`. */ @@ -770,6 +786,22 @@ export interface ApiComparePagesParams extends ApiParams { * This parameter specifies the slots that are to be modified. Use `totext-{slot}`, `tocontentmodel-{slot}`, and `tocontentformat-{slot}` to specify content for each slot. */ toslots?: OneOrMore<"main">; + /** + * Text of the specified slot. If omitted, the slot is removed from the revision. + */ + [k: `totext-${string}`]: string; + /** + * When `totext-{slot}` is the content of a single section, this is the section identifier. It will be merged into the revision specified by `totitle`, `toid` or `torev` as if for a section edit. + */ + [k: `tosection-${string}`]: string; + /** + * Content serialization format of `totext-{slot}`. + */ + [k: `tocontentformat-${string}`]: string; + /** + * Content model of `totext-{slot}`. If not supplied, it will be guessed based on the other parameters. + */ + [k: `tocontentmodel-${string}`]: string; /** * Do a pre-save transform on `totext`. */ @@ -6558,6 +6590,18 @@ export interface VisualEditorApiVisualEditorEditParams extends ApiParams { * - **ge-task-revise-tone**: Use when saving a GrowthExperiments "{@link https://www.mediawiki.org/wiki/Growth/Revise_Tone Revise Tone}" structured edit. */ plugins?: string | string[]; + /** + * Arbitrary data sent by a plugin with the API request. + * + * - **For the `ge-task-link-recommendation` plugin**: A JSON string of an object with these keys: + * + * - `acceptedTargets`: (optional) Array with the titles of pages, the recommended link to which was accepted by the user. + * - `rejectedTargets`: (optional) Array with the titles of pages, the recommended link to which was rejected by the user. + * - `skippedTargets`: (optional) Array with the titles of pages, the recommended link to which was skipped (ignored) by the user. + * + * - **For the `ge-task-revise-tone` plugin**: No data should be included for this plugin. + */ + [k: `data-${string}`]: string; /** * Whether the shown hCaptcha CAPTCHA was force shown, such as by an AbuseFilter extension consequence (and so used a more restrictive sitekey). Set this if the JS configuration variable with the same name is true or if the first attempt to use this API returned a 'forcecaptcha' error with a specified sitekey. */ @@ -7083,6 +7127,10 @@ export interface ApiQueryAllDeletedRevisionsParams extends ApiQueryParams { * Which revision slots to return data for, when slot-related properties are included in `adrprops`. If omitted, data from the `main` slot will be returned in a backwards-compatible format. */ adrslots?: OneOrMore<"main">; + /** + * Content serialization format used for output of content. + */ + [k: `adrcontentformat-${string}`]: string; /** * Limit how many revisions will be returned. If `adrprop=content`, `adrprop=parsetree`, `adrdiffto` or `adrdifftotext` is used, the limit is 50. If `adrparse` is used, the limit is 1. */ @@ -7689,6 +7737,10 @@ export interface ApiQueryAllRevisionsParams extends ApiQueryParams { * Which revision slots to return data for, when slot-related properties are included in `arvprops`. If omitted, data from the `main` slot will be returned in a backwards-compatible format. */ arvslots?: OneOrMore<"main">; + /** + * Content serialization format used for output of content. + */ + [k: `arvcontentformat-${string}`]: string; /** * Limit how many revisions will be returned. If `arvprop=content`, `arvprop=parsetree`, `arvdiffto` or `arvdifftotext` is used, the limit is 50. If `arvparse` is used, the limit is 1. */ @@ -8803,6 +8855,10 @@ export interface ApiQueryDeletedRevisionsParams extends ApiQueryParams { * Which revision slots to return data for, when slot-related properties are included in `drvprops`. If omitted, data from the `main` slot will be returned in a backwards-compatible format. */ drvslots?: OneOrMore<"main">; + /** + * Content serialization format used for output of content. + */ + [k: `drvcontentformat-${string}`]: string; /** * Limit how many revisions will be returned. If `drvprop=content`, `drvprop=parsetree`, `drvdiffto` or `drvdifftotext` is used, the limit is 50. If `drvparse` is used, the limit is 1. */ @@ -12050,6 +12106,10 @@ export interface ApiQueryRevisionsParams extends ApiQueryParams { * Which revision slots to return data for, when slot-related properties are included in `rvprops`. If omitted, data from the `main` slot will be returned in a backwards-compatible format. */ rvslots?: OneOrMore<"main">; + /** + * Content serialization format used for output of content. + */ + [k: `rvcontentformat-${string}`]: string; /** * Limit how many revisions will be returned. If `rvprop=content`, `rvprop=parsetree`, `rvdiffto` or `rvdifftotext` is used, the limit is 50. If `rvparse` is used, the limit is 1. */ diff --git a/scripts/api-types-generator.js b/scripts/api-types-generator.js index d81d71f..e5cd45b 100644 --- a/scripts/api-types-generator.js +++ b/scripts/api-types-generator.js @@ -175,6 +175,17 @@ const literalToJSdoc = (lit, multi) => { } }; +/** + * Replace template variables in a module parameter name. + * + * @param {string} name Parameter name. + * @param {string[]} templateVars Template variables that *may* appear in the name. + */ +function replaceTemplateVars(name, templateVars) { + const varPattern = new RegExp(`\\{(${templateVars.join("|")})\\}`, "g"); + return name.replaceAll(varPattern, "${string}"); +} + function processParamInfo(prefix, param) { let type = param.type; @@ -203,7 +214,12 @@ function processParamInfo(prefix, param) { } let name = prefix + param.name; - if (name.includes("-")) { + let isOptional = true; + if (param.templatevars !== undefined) { + name = replaceTemplateVars(name, Object.keys(param.templatevars)); + name = `[k: \`${name}\`]`; + isOptional = false; + } else if (name.includes("-")) { name = `"${name}"`; } @@ -220,7 +236,7 @@ function processParamInfo(prefix, param) { jsdoc.deprecated = true; } - return `${jsdoc.toString()}\n${name}?: ${type};`; + return `${jsdoc.toString()}\n${name}${isOptional ? "?:" : ":"} ${type};`; } function getInterfaceName(module) { @@ -230,6 +246,23 @@ function getInterfaceName(module) { .replace(/ApiApi/g, "Api"); } +/** + * Merge 2 parameter arrays into a new array, ordered by index. + * + * @param {any[]} params1 1st parameter array, ordered by index. + * @param {any[]} params2 2nd parameter array, ordered by index. + */ +function mergeParameterArrays(params1, params2) { + const params = []; + let i1 = 0, + i2 = 0; + while (i1 < params1.length && i2 < params2.length) { + params.push(params1[i1].index < params2[i2].index ? params1[i1++] : params2[i2++]); + } + params.push(...params1.slice(i1), ...params2.slice(i2)); + return params; +} + function processModuleInfo(parent, module) { const jsdoc = new JSdoc(); jsdoc.description = htmlToJSdoc(module.description); @@ -240,12 +273,13 @@ function processModuleInfo(parent, module) { if (module.deprecated) { jsdoc.deprecated = true; } + + const parameters = mergeParameterArrays(module.parameters, module.templatedparameters); + return [ jsdoc.toString(), `export interface ${getInterfaceName(module)}Params extends ${parent}Params {`, - ...module.parameters.map((param) => - processParamInfo(module.prefix, param).replace(/^/gm, "\t"), - ), + ...parameters.map((param) => processParamInfo(module.prefix, param).replace(/^/gm, "\t")), "}", ].join("\n"); } From 6aa26b3edd14e49b86183ec21bbf1ce836470709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20LES=C3=89N=C3=89CHAL?= Date: Wed, 1 Jul 2026 17:21:29 +0200 Subject: [PATCH 3/3] fix: Slot variables only allowing `main` --- index.d.ts | 12 ++++++------ scripts/api-types-generator.js | 32 +++++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/index.d.ts b/index.d.ts index 2bfe742..ba848bc 100644 --- a/index.d.ts +++ b/index.d.ts @@ -719,7 +719,7 @@ export interface ApiComparePagesParams extends ApiParams { * * This parameter specifies the slots that are to be modified. Use `fromtext-{slot}`, `fromcontentmodel-{slot}`, and `fromcontentformat-{slot}` to specify content for each slot. */ - fromslots?: OneOrMore<"main">; + fromslots?: string | string[]; /** * Text of the specified slot. If omitted, the slot is removed from the revision. */ @@ -785,7 +785,7 @@ export interface ApiComparePagesParams extends ApiParams { * * This parameter specifies the slots that are to be modified. Use `totext-{slot}`, `tocontentmodel-{slot}`, and `tocontentformat-{slot}` to specify content for each slot. */ - toslots?: OneOrMore<"main">; + toslots?: string | string[]; /** * Text of the specified slot. If omitted, the slot is removed from the revision. */ @@ -7126,7 +7126,7 @@ export interface ApiQueryAllDeletedRevisionsParams extends ApiQueryParams { /** * Which revision slots to return data for, when slot-related properties are included in `adrprops`. If omitted, data from the `main` slot will be returned in a backwards-compatible format. */ - adrslots?: OneOrMore<"main">; + adrslots?: string | string[]; /** * Content serialization format used for output of content. */ @@ -7736,7 +7736,7 @@ export interface ApiQueryAllRevisionsParams extends ApiQueryParams { /** * Which revision slots to return data for, when slot-related properties are included in `arvprops`. If omitted, data from the `main` slot will be returned in a backwards-compatible format. */ - arvslots?: OneOrMore<"main">; + arvslots?: string | string[]; /** * Content serialization format used for output of content. */ @@ -8854,7 +8854,7 @@ export interface ApiQueryDeletedRevisionsParams extends ApiQueryParams { /** * Which revision slots to return data for, when slot-related properties are included in `drvprops`. If omitted, data from the `main` slot will be returned in a backwards-compatible format. */ - drvslots?: OneOrMore<"main">; + drvslots?: string | string[]; /** * Content serialization format used for output of content. */ @@ -12105,7 +12105,7 @@ export interface ApiQueryRevisionsParams extends ApiQueryParams { /** * Which revision slots to return data for, when slot-related properties are included in `rvprops`. If omitted, data from the `main` slot will be returned in a backwards-compatible format. */ - rvslots?: OneOrMore<"main">; + rvslots?: string | string[]; /** * Content serialization format used for output of content. */ diff --git a/scripts/api-types-generator.js b/scripts/api-types-generator.js index e5cd45b..67d6fac 100644 --- a/scripts/api-types-generator.js +++ b/scripts/api-types-generator.js @@ -186,14 +186,25 @@ function replaceTemplateVars(name, templateVars) { return name.replaceAll(varPattern, "${string}"); } -function processParamInfo(prefix, param) { +/** + * Format an API module parameter as a TS property. + * + * @param {string} prefix Prefix to prepend to all parameter names. + * @param {any} param API module parameter data. + * @param {Set} allTemplateVars Template variables used by parameters from this module. + */ +function processParamInfo(prefix, param, allTemplateVars) { let type = param.type; - // Convert the API type to a TypeScript type - // Avoid being over-specific + // Convert the API type to a TS type if (Array.isArray(type)) { const enumSet = new Set(type); - if (GENERALIZE_ENUM_TYPE_CONTAINING.some((s) => s.isSubsetOf(enumSet))) { + if ( + // is its value used as a template variable for another parameter? + allTemplateVars.has(param.name) || + // is it extensible? + GENERALIZE_ENUM_TYPE_CONTAINING.some((s) => s.isSubsetOf(enumSet)) + ) { type = "string"; } } else if (type === "text" || type === "title" || type === "user" || type === "raw") { @@ -263,6 +274,12 @@ function mergeParameterArrays(params1, params2) { return params; } +/** + * Format an API module as a TS interface. + * + * @param {string} parent Parent interface name. + * @param {any} module API module data. + */ function processModuleInfo(parent, module) { const jsdoc = new JSdoc(); jsdoc.description = htmlToJSdoc(module.description); @@ -275,11 +292,16 @@ function processModuleInfo(parent, module) { } const parameters = mergeParameterArrays(module.parameters, module.templatedparameters); + const allTemplateVars = new Set( + module.templatedparameters.flatMap((p) => Object.values(p.templatevars)), + ); return [ jsdoc.toString(), `export interface ${getInterfaceName(module)}Params extends ${parent}Params {`, - ...parameters.map((param) => processParamInfo(module.prefix, param).replace(/^/gm, "\t")), + ...parameters.map((param) => + processParamInfo(module.prefix, param, allTemplateVars).replace(/^/gm, "\t"), + ), "}", ].join("\n"); }