Skip to content

Commit

Permalink
fix(mw.Api): return type of multiple methods
Browse files Browse the repository at this point in the history
refactor(mw.Api): add autocompletion for token types (and legacy ones) with `postWithToken`/`getToken`/`badToken`
refactor(mw.Api): add autocompletion for `getToken` API arguments
check other authors/commits at wikimedia-gadgets#36
  • Loading branch information
AnYiEE committed Feb 16, 2024
1 parent 4184883 commit 0f3962e
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 36 deletions.
24 changes: 24 additions & 0 deletions api_params/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,30 @@ type password = string;
type upload = File; // XXX
type OneOrMore<T> = T | T[];

export type ApiAssert = 'anon' | 'bot' | 'user';

export type ApiTokenType =
| 'createaccount'
| 'csrf'
| 'deleteglobalaccount'
| 'login'
| 'patrol'
| 'rollback'
| 'setglobalaccountstatus'
| 'userrights'
| 'watch';

export type ApiLegacyTokenType =
| 'block'
| 'delete'
| 'edit'
| 'email'
| 'import'
| 'move'
| 'options'
| 'protect'
| 'unblock';

export interface ApiParams {
action?: string;
format?: 'json' | 'jsonfm' | 'xml' | 'xmlfm' | 'php' | 'none';
Expand Down
145 changes: 109 additions & 36 deletions mw/Api.d.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,82 @@
import {
ApiParams as _ApiParams,
ApiParams,
ApiEditPageParams,
ApiLegacyTokenType,
ApiParseParams,
ApiQueryAllMessagesParams,
ApiRollbackParams,
ApiTokenType,
ApiUploadParams,
ApiAssert,
ApiQueryTokensParams,
} from '../api_params';
import {TitleLike} from './Title';
import {UserInfo} from './user';

type TypeOrArray<T> = T extends any ? T | T[] : never; // T[] would be a mixed array
type ReplaceValue<T extends U | U[], U, V> = T extends U[] ? V[] : V;

type ApiParams = Record<string, string | string[] | boolean | number | number[]> | _ApiParams;
type UnknownApiParams = Record<string, string | string[] | boolean | number | number[]> | ApiParams;
type ApiResponse = Record<string, any>; // it will always be a JSON object, the rest is uncertain ...

interface Revision {
content: string;
timestamp: string;
}

type EditResult = EditFailureResult | EditNoChangeResult | EditChangedResult;

interface EditFailureResult {
result: 'Failure';
}

interface EditSuccessResult {
contentmodel: string | false;
pageid: number;
result: 'Success';
tempusercreated?: true;
tempusercreatedredirect?: string;
title: string;
watched?: true;
watchlistexpiry?: string;
}

interface EditNoChangeResult extends EditSuccessResult {
nochange: true;
}

interface EditChangedResult extends EditSuccessResult {
oldrevid: number;
newrevid: number;
newtimestamp: string;
}

interface AssertUser {
assert: 'anon' | 'user';
assertUser: string;
}

interface WatchStatus {
ns: number;
title: string;
watched: boolean;
}

interface RollbackInfo {
/**
* The revision being restored (the last revision before revision(s) by the reverted user).
*/
last_revid: number;
/**
* The revision being reverted (previously the current revision of the page).
*/
old_revid: number;
pageid: number;
revid: number;
summary: string;
title: string;
}

interface FinishUpload {
/**
* Call this function to finish the upload.
Expand All @@ -47,7 +94,7 @@ export interface ApiOptions {
/**
* Default query parameters for API requests
*/
parameters: ApiParams;
parameters: UnknownApiParams;
/**
* Default options for {@link jQuery.ajax}
*/
Expand Down Expand Up @@ -107,12 +154,12 @@ declare global {
/**
* Perform the API call.
*
* @param {ApiParams} parameters
* @param {UnknownApiParams} parameters
* @param {JQuery.AjaxSettings} [ajaxOptions]
* @returns {JQuery.Promise<ApiResponse>} API response data and the jqXHR object
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api-method-ajax
*/
ajax(parameters: ApiParams, ajaxOptions?: JQuery.AjaxSettings): JQuery.Promise<ApiResponse>;
ajax(parameters: UnknownApiParams, ajaxOptions?: JQuery.AjaxSettings): JQuery.Promise<ApiResponse>;

/**
* Extend an API parameter object with an assertion that the user won't change.
Expand All @@ -125,11 +172,11 @@ declare global {
* * `apierror-assertnameduserfailed`: when both the client-side logic and the server thinks the user is logged in but they see it logged in under a different username.
*
* @since 1.27
* @param {ApiParams} query Query parameters. The object will not be changed
* @returns {JQuery.Promise<AssertUser>}
* @param {UnknownApiParams} query Query parameters. The object will not be changed
* @returns {AssertUser}
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api.plugin.user-method-assertCurrentUser
*/
assertCurrentUser(query: ApiParams): JQuery.Promise<AssertUser>;
assertCurrentUser<T extends UnknownApiParams>(query: T): Omit<T, keyof AssertUser> & AssertUser;

/**
* Indicate that the cached token for a certain action of the API is bad.
Expand All @@ -142,6 +189,9 @@ declare global {
* @param {string} type Token type
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api-method-badToken
*/
badToken(type: ApiTokenType): void;
/** @deprecated Use "csrf" instead */
badToken(type: ApiLegacyTokenType): void;
badToken(type: string): void;

/**
Expand Down Expand Up @@ -196,10 +246,10 @@ declare global {
* @param {TitleLike} title Page title
* @param {ApiEditPageParams} params Edit API parameters
* @param {string} content Page content
* @returns {JQuery.Promise<ApiResponse>} API response
* @returns {JQuery.Promise<EditResult>} API response
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api.plugin.edit-method-create
*/
create(title: TitleLike, params: ApiEditPageParams, content: string): JQuery.Promise<ApiResponse>;
create(title: TitleLike, params: ApiEditPageParams, content: string): JQuery.Promise<EditResult>;

/**
* Edit an existing page.
Expand Down Expand Up @@ -259,20 +309,23 @@ declare global {
* @since 1.28
* @param {TitleLike} title Page title
* @param {function(Revision):string|ApiEditPageParams} transform Callback that prepares the edit
* @returns {JQuery.Promise<any>}
* @returns {JQuery.Promise<EditResult>}
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api.plugin.edit-method-edit
*/
edit(title: TitleLike, transform: (revision: Revision) => string | ApiEditPageParams): JQuery.Promise<any>;
edit(
title: TitleLike,
transform: (revision: Revision) => string | ApiEditPageParams
): JQuery.Promise<EditResult>;

/**
* Perform API get request.
*
* @param {ApiParams} parameters
* @param {UnknownApiParams} parameters
* @param {JQuery.AjaxSettings} [ajaxOptions]
* @returns {JQuery.Promise<ApiResponse>}
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api-method-get
*/
get(parameters: ApiParams, ajaxOptions?: JQuery.AjaxSettings): JQuery.Promise<ApiResponse>;
get(parameters: UnknownApiParams, ajaxOptions?: JQuery.AjaxSettings): JQuery.Promise<ApiResponse>;

/**
* Get the categories that a particular page on the wiki belongs to.
Expand Down Expand Up @@ -346,21 +399,30 @@ declare global {
* @since 1.27
* @param {string|string[]} messages Messages to retrieve
* @param {ApiQueryAllMessagesParams} [options] Additional parameters for the API call
* @returns {JQuery.Promise<ApiResponse>}
* @returns {JQuery.Promise<Partial<Record<T, string>>>}
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api.plugin.messages-method-getMessages
*/
getMessages(messages: string | string[], options?: ApiQueryAllMessagesParams): JQuery.Promise<ApiResponse>;
getMessages<T extends string>(
messages: T | T[],
options?: ApiQueryAllMessagesParams
): JQuery.Promise<Partial<Record<T, string>>>;

/**
* Get a token for a certain action from the API.
*
* @since 1.22
* @param {string} type Token type
* @param {ApiParams|string} [additionalParams] Additional parameters for the API (since 1.35). When given a string, it's treated as the `assert` parameter (since 1.25)
* @param {UnknownApiParams|ApiAssert} [additionalParams] Additional parameters for the API (since 1.35). When given a string, it's treated as the `assert` parameter (since 1.25)
* @returns {JQuery.Promise<string>} Received token
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api-method-getToken
*/
getToken(type: string, additionalParams?: ApiParams | string): JQuery.Promise<string>;
getToken(type: ApiTokenType, additionalParams?: ApiQueryTokensParams | ApiAssert): JQuery.Promise<string>;
/** @deprecated Use "csrf" instead */
getToken(
type: ApiLegacyTokenType,
additionalParams?: ApiQueryTokensParams | ApiAssert
): JQuery.Promise<string>;
getToken(type: string, additionalParams?: ApiQueryTokensParams | ApiAssert): JQuery.Promise<string>;

/**
* Get the current user's groups and rights.
Expand All @@ -385,21 +447,21 @@ declare global {
*
* @param {string|string[]} messages Messages to retrieve
* @param {ApiQueryAllMessagesParams} [options] Additional parameters for the API call
* @returns {JQuery.Promise<ApiResponse>}
* @returns {JQuery.Promise<boolean>}
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api.plugin.messages-method-loadMessages
*/
loadMessages(messages: string | string[], options?: ApiQueryAllMessagesParams): JQuery.Promise<ApiResponse>;
loadMessages(messages: string | string[], options?: ApiQueryAllMessagesParams): JQuery.Promise<boolean>;

/**
* Load a set of messages and add them to `mw.messages`. Only messages that are not already known are loaded. If all messages are known, the returned promise is resolved immediately.
*
* @since 1.27
* @param {string[]} messages Messages to retrieve
* @param {ApiQueryAllMessagesParams} [options] Additional parameters for the API call
* @returns {JQuery.Promise<ApiResponse>}
* @returns {JQuery.Promise<boolean>}
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api.plugin.messages-method-loadMessagesIfMissing
*/
loadMessagesIfMissing(messages: string[], options?: ApiQueryAllMessagesParams): JQuery.Promise<ApiResponse>;
loadMessagesIfMissing(messages: string[], options?: ApiQueryAllMessagesParams): JQuery.Promise<boolean>;

/**
* @param {string} username
Expand Down Expand Up @@ -440,22 +502,22 @@ declare global {
/**
* Perform API post request.
*
* @param {ApiParams} parameters
* @param {UnknownApiParams} parameters
* @param {JQuery.AjaxSettings} [ajaxOptions]
* @returns {JQuery.Promise<ApiResponse>}
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api-method-post
*/
post(parameters: ApiParams, ajaxOptions?: JQuery.AjaxSettings): JQuery.Promise<ApiResponse>;
post(parameters: UnknownApiParams, ajaxOptions?: JQuery.AjaxSettings): JQuery.Promise<ApiResponse>;

/**
* Post to API with csrf token. If we have no token, get one and try to post. If we have a cached token try using that, and if it fails, blank out the cached token and start over.
*
* @param {APIParams} params API parameters
* @param {UnknownApiParams} params API parameters
* @param {JQuery.AjaxSettings} [ajaxOptions]
* @returns {JQuery.Promise<ApiResponse>}
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api.plugin.edit-method-postWithEditToken
*/
postWithEditToken(params: ApiParams, ajaxOptions?: JQuery.AjaxSettings): JQuery.Promise<ApiResponse>;
postWithEditToken(params: UnknownApiParams, ajaxOptions?: JQuery.AjaxSettings): JQuery.Promise<ApiResponse>;

/**
* Post to API with specified type of token. If we have no token, get one and try to post.
Expand All @@ -472,14 +534,25 @@ declare global {
*
* @since 1.22
* @param {string} tokenType The name of the token, like `options` or `edit`
* @param {ApiParams} params API parameters
* @param {UnknownApiParams} params API parameters
* @param {JQuery.AjaxSettings} [ajaxOptions]
* @returns {JQuery.Promise<ApiResponse>}
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api-method-postWithToken
*/
postWithToken(
tokenType: ApiTokenType,
params: UnknownApiParams,
ajaxOptions?: JQuery.AjaxSettings
): JQuery.Promise<ApiResponse>;
/** @deprecated Use "csrf" instead */
postWithToken(
tokenType: ApiLegacyTokenType,
params: UnknownApiParams,
ajaxOptions?: JQuery.AjaxSettings
): JQuery.Promise<ApiResponse>;
postWithToken(
tokenType: string,
params: ApiParams,
params: UnknownApiParams,
ajaxOptions?: JQuery.AjaxSettings
): JQuery.Promise<ApiResponse>;

Expand All @@ -490,10 +563,10 @@ declare global {
* @param {TitleLike} page
* @param {string} user
* @param {ApiRollbackParams} [params] Additional parameters
* @returns {JQuery.Promise<ApiResponse>}
* @returns {JQuery.Promise<RollbackInfo>}
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api.plugin.rollback-method-rollback
*/
rollback(page: TitleLike, user: string, params?: ApiRollbackParams): JQuery.Promise<ApiResponse>;
rollback(page: TitleLike, user: string, params?: ApiRollbackParams): JQuery.Promise<RollbackInfo>;

/**
* Asynchronously save the value of a single user option using the API. See `saveOptions()`.
Expand Down Expand Up @@ -526,12 +599,12 @@ declare global {
* Convenience method for `action=watch&unwatch=1`.
*
* @param {TypeOrArray<TitleLike>} pages
* @returns {JQuery.Promise<{ watch: TypeOrArray<WatchStatus> }>}
* @returns {JQuery.Promise<TypeOrArray<WatchStatus>>}
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api.plugin.watch-method-unwatch
*/
unwatch<P extends TypeOrArray<TitleLike>>(
pages: P
): JQuery.Promise<{watch: ReplaceValue<P, TitleLike, WatchStatus>}>;
): JQuery.Promise<ReplaceValue<P, TitleLike, WatchStatus>>;

/**
* Upload a file to MediaWiki.
Expand Down Expand Up @@ -584,13 +657,13 @@ declare global {
* @since 1.35: expiry parameter can be passed when watchlist expiry is enabled
* @param {TypeOrArray<TitleLike>} pages
* @param {string} [expiry]
* @returns {JQuery.Promise<{ watch: TypeOrArray<WatchStatus> }>}
* @returns {JQuery.Promise<TypeOrArray<WatchStatus>>}
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api.plugin.watch-method-watch
*/
watch<P extends TypeOrArray<TitleLike>>(
pages: P,
expiry?: string
): JQuery.Promise<{watch: ReplaceValue<P, TitleLike, WatchStatus>}>;
): JQuery.Promise<ReplaceValue<P, TitleLike, WatchStatus>>;

/**
* Given a non-empty object, return one of its keys.
Expand All @@ -606,11 +679,11 @@ declare global {
* Massage parameters from the nice format we accept into a format suitable for the API.
*
* @private
* @param {ApiParams} parameters (modified in-place)
* @param {UnknownApiParams} parameters (modified in-place)
* @param {boolean} useUS Whether to use U+001F when joining multi-valued parameters.
* @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api-method-preprocessParameters
*/
private preprocessParameters(parameters: ApiParams, useUS: boolean): void;
private preprocessParameters(parameters: UnknownApiParams, useUS: boolean): void;

/**
* Launch the upload anew if it failed because of network issues.
Expand Down

0 comments on commit 0f3962e

Please sign in to comment.