|
1 | 1 | import type { Octokit } from "@octokit/core";
|
2 |
| -import type { |
3 |
| - EndpointOptions, |
4 |
| - RequestParameters, |
5 |
| - RequestMethod, |
6 |
| - Route, |
7 |
| - Url, |
8 |
| -} from "@octokit/types"; |
9 |
| -import type { |
10 |
| - EndpointsDefaultsAndDecorations, |
11 |
| - EndpointDecorations, |
12 |
| -} from "./types"; |
| 2 | +import type { EndpointOptions, RequestParameters, Route } from "@octokit/types"; |
| 3 | +import ENDPOINTS from "./generated/endpoints"; |
13 | 4 | import type { RestEndpointMethods } from "./generated/method-types";
|
| 5 | +import type { EndpointDecorations } from "./types"; |
14 | 6 |
|
15 |
| -type EndpointMethods = { |
16 |
| - [methodName: string]: typeof Octokit.prototype.request; |
| 7 | +// The following code was refactored in: https://github.com/octokit/plugin-rest-endpoint-methods.js/pull/622 |
| 8 | +// to optimise the runtime performance of Octokit initialization. |
| 9 | +// |
| 10 | +// This optimization involves two key changes: |
| 11 | +// 1. Pre-Computation: The endpoint methods are pre-computed once at module load |
| 12 | +// time instead of each invocation of `endpointsToMethods()`. |
| 13 | +// 2. Lazy initialization and caching: We use a Proxy for each scope to only |
| 14 | +// initialize methods that are actually called. This reduces runtime overhead |
| 15 | +// as the initialization involves deep merging of objects. The initialized |
| 16 | +// methods are then cached for future use. |
| 17 | + |
| 18 | +const endpointMethodsMap = new Map(); |
| 19 | +for (const [scope, endpoints] of Object.entries(ENDPOINTS)) { |
| 20 | + for (const [methodName, endpoint] of Object.entries(endpoints)) { |
| 21 | + const [route, defaults, decorations] = endpoint; |
| 22 | + const [method, url] = route.split(/ /); |
| 23 | + const endpointDefaults = Object.assign( |
| 24 | + { |
| 25 | + method, |
| 26 | + url, |
| 27 | + }, |
| 28 | + defaults |
| 29 | + ); |
| 30 | + |
| 31 | + if (!endpointMethodsMap.has(scope)) { |
| 32 | + endpointMethodsMap.set(scope, new Map()); |
| 33 | + } |
| 34 | + |
| 35 | + endpointMethodsMap.get(scope).set(methodName, { |
| 36 | + scope, |
| 37 | + methodName, |
| 38 | + endpointDefaults, |
| 39 | + decorations, |
| 40 | + }); |
| 41 | + } |
| 42 | +} |
| 43 | + |
| 44 | +type ProxyTarget = { |
| 45 | + octokit: Octokit; |
| 46 | + scope: string; |
| 47 | + cache: Record<string, (...args: any[]) => any>; |
17 | 48 | };
|
18 | 49 |
|
19 |
| -export function endpointsToMethods( |
20 |
| - octokit: Octokit, |
21 |
| - endpointsMap: EndpointsDefaultsAndDecorations |
22 |
| -) { |
23 |
| - const newMethods = {} as { [key: string]: object }; |
| 50 | +const handler = { |
| 51 | + get({ octokit, scope, cache }: ProxyTarget, methodName: string) { |
| 52 | + if (cache[methodName]) { |
| 53 | + return cache[methodName]; |
| 54 | + } |
| 55 | + |
| 56 | + const { decorations, endpointDefaults } = endpointMethodsMap |
| 57 | + .get(scope) |
| 58 | + .get(methodName); |
24 | 59 |
|
25 |
| - for (const [scope, endpoints] of Object.entries(endpointsMap)) { |
26 |
| - for (const [methodName, endpoint] of Object.entries(endpoints)) { |
27 |
| - const [route, defaults, decorations] = endpoint; |
28 |
| - const [method, url] = route.split(/ /) as [RequestMethod, Url]; |
29 |
| - const endpointDefaults: EndpointOptions = Object.assign( |
30 |
| - { method, url }, |
31 |
| - defaults |
| 60 | + if (decorations) { |
| 61 | + cache[methodName] = decorate( |
| 62 | + octokit, |
| 63 | + scope, |
| 64 | + methodName, |
| 65 | + endpointDefaults, |
| 66 | + decorations |
32 | 67 | );
|
| 68 | + } else { |
| 69 | + cache[methodName] = octokit.request.defaults(endpointDefaults); |
| 70 | + } |
33 | 71 |
|
34 |
| - if (!newMethods[scope]) { |
35 |
| - newMethods[scope] = {}; |
36 |
| - } |
| 72 | + return cache[methodName]; |
| 73 | + }, |
| 74 | +}; |
37 | 75 |
|
38 |
| - const scopeMethods = newMethods[scope] as EndpointMethods; |
39 |
| - |
40 |
| - if (decorations) { |
41 |
| - scopeMethods[methodName] = decorate( |
42 |
| - octokit, |
43 |
| - scope, |
44 |
| - methodName, |
45 |
| - endpointDefaults, |
46 |
| - decorations |
47 |
| - ); |
48 |
| - continue; |
49 |
| - } |
| 76 | +export function endpointsToMethods(octokit: Octokit): RestEndpointMethods { |
| 77 | + const newMethods = {} as { [key: string]: object }; |
50 | 78 |
|
51 |
| - scopeMethods[methodName] = octokit.request.defaults(endpointDefaults); |
52 |
| - } |
| 79 | + for (const scope of endpointMethodsMap.keys()) { |
| 80 | + newMethods[scope] = new Proxy({ octokit, scope, cache: {} }, handler); |
53 | 81 | }
|
54 | 82 |
|
55 | 83 | return newMethods as RestEndpointMethods;
|
|
0 commit comments