Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚧 [Help Wanted] types for endpoint(options) #50

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions scripts/update-endpoints/templates/endpoints.ts.template
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,31 @@
import { OctokitResponse } from "../OctokitResponse";
import { RequestHeaders } from "../RequestHeaders";
import { RequestRequestOptions } from "../RequestRequestOptions";
import { RequestParameters } from "../RequestParameters";
import { RequestOptions } from "../RequestOptions";

type RequiredPreview<T> = {
mediaType: {
previews: [T, ...string[]];
};
};

type Endpoint<
Parameters extends RequestParameters,
Request extends RequestOptions,
Response extends OctokitResponse<any>
> = {
parameters: Parameters;
request: Request;
response: Response;
};

export interface Endpoints {
{{#each endpointsByRoute}}
/**
* @see {{documentationUrl}}
*/
"{{@key}}": {
parameters: {{optionsTypeName}},
request: {{requestOptionsTypeName}},
response: OctokitResponse<{{responseTypeName}}>,
},
"{{@key}}": Endpoint<{{optionsTypeName}}, {{requestOptionsTypeName}}, OctokitResponse<{{responseTypeName}}>>,
{{/each}}
}

Expand Down
93 changes: 88 additions & 5 deletions src/EndpointInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,103 @@ import { EndpointDefaults } from "./EndpointDefaults";
import { RequestOptions } from "./RequestOptions";
import { RequestParameters } from "./RequestParameters";
import { Route } from "./Route";
import { Url } from "./Url";
import { RequestMethod } from "./RequestMethod";

import { Endpoints } from "./generated/Endpoints";

type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;

type EndpointsByUrlAndMethod = UnionToIntersection<
{
[K in keyof Endpoints]: {
[TUrl in Endpoints[K]["request"]["url"]]: {
[TMethod in Endpoints[K]["request"]["method"]]: {
route: {
url: TUrl;
method: TMethod;
};
parameters: Endpoints[K]["parameters"];
request: Endpoints[K]["request"];
};
};
};
}[keyof Endpoints]
>;

type UnknownRouteObject = {
method?: RequestMethod;
url: string;
};
type UnknownEndpointParameters = RequestParameters & UnknownRouteObject;

type KnownOrUnknownEndpointsByUrlAndMethod<
T extends UnknownEndpointParameters
> = T["url"] extends keyof EndpointsByUrlAndMethod
? T["method"] extends keyof EndpointsByUrlAndMethod[T["url"]]
? EndpointsByUrlAndMethod[T["url"]][T["method"]] extends {
parameters: infer TParams;
request: infer TRequest;
}
? { parameters: TParams; request: TRequest }
: never
: never
: {
parameters: UnknownEndpointParameters;
request: RequestOptions;
};

// https://stackoverflow.com/a/61281317/206879
type KnownOptions<T> = T extends {
[k in keyof T]: {
[k: string]: infer OptionValue;
};
}
? OptionValue
: never;

type KnownRouteObjects = KnownOptions<EndpointsByUrlAndMethod>["route"];
type KnownRouteObject = { method: RequestMethod; url: Url };
type RouteObjectFrom<T extends KnownRouteObject> = {
method: T["method"];
url: T["url"];
};

export interface EndpointInterface<D extends object = object> {
/**
* Transforms a GitHub REST API endpoint into generic request options
*
* @param {object} endpoint Must set `url` unless it's set defaults. Plus URL, query or body parameters, as well as `headers`, `mediaType.{format|previews}`, `request`, or `baseUrl`.
*/
<O extends RequestParameters = RequestParameters>(
options: O & { method?: string } & ("url" extends keyof D
? { url?: string }
: { url: string })
): RequestOptions & Pick<D & O, keyof RequestOptions>;
// WIP: does not allow optionsk for unknown routes, does not respect `D`
<O extends KnownRouteObjects>(
options: O &
KnownOrUnknownEndpointsByUrlAndMethod<O>["parameters"] &
RequestParameters
): KnownOrUnknownEndpointsByUrlAndMethod<O>["request"];

// WIP: does not validate required parameters for known route:
// <O extends RequestParameters>(
// options: O extends KnownRouteObject
// ? RouteObjectFrom<D & O> extends KnownRouteObjects
// ? KnownOrUnknownEndpointsByUrlAndMethod<
// RouteObjectFrom<D & O>
// >["parameters"]
// : O & { method?: string } & ("url" extends keyof D
// ? { url?: string }
// : { url: string })
// : O & { method?: string } & ("url" extends keyof D
// ? { url?: string }
// : { url: string })
// ): O extends KnownRouteObject
// ? RouteObjectFrom<D & O> extends KnownRouteObjects
// ? KnownOrUnknownEndpointsByUrlAndMethod<RouteObjectFrom<D & O>>["request"]
// : RequestOptions & Pick<D & O, keyof RequestOptions>
// : RequestOptions & Pick<D & O, keyof RequestOptions>;

/**
* Transforms a GitHub REST API endpoint into generic request options
Expand Down
Loading