-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(typescript): typescript definitions
- Loading branch information
Showing
16 changed files
with
72,853 additions
and
53 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
const { writeFileSync } = require("fs"); | ||
const { join: pathJoin } = require("path"); | ||
|
||
const camelCase = require("lodash.camelcase"); | ||
const prettier = require("prettier"); | ||
const { stringToJsdocComment } = require("string-to-jsdoc-comment"); | ||
const sortKeys = require("sort-keys"); | ||
|
||
const GHE_VERSIONS = require("./ghe-versions"); | ||
const { isDeprecated } = require("./util"); | ||
|
||
generateTypes(); | ||
|
||
async function generateTypes() { | ||
for (const version of GHE_VERSIONS) { | ||
const ROUTES = await getRoutes(version); | ||
|
||
const namespaces = Object.keys(ROUTES).reduce((namespaces, namespace) => { | ||
const methods = Object.keys(ROUTES[namespace]).reduce( | ||
(methods, methodName) => { | ||
const entry = ROUTES[namespace][methodName]; | ||
|
||
const description = [ | ||
entry.description, | ||
entry.deprecated && `@deprecated ${entry.deprecated}`, | ||
] | ||
.filter(Boolean) | ||
.join("\n"); | ||
|
||
return methods.concat({ | ||
name: methodName, | ||
route: `${entry.method} ${entry.url}`, | ||
hasRequiredPreviews: entry.hasRequiredPreviews, | ||
jsdoc: stringToJsdocComment(description), | ||
}); | ||
}, | ||
[] | ||
); | ||
|
||
return namespaces.concat({ | ||
namespace: camelCase(namespace), | ||
methods, | ||
}); | ||
}, []); | ||
|
||
const RestEndpointMethodParameterAndResponseTypes = []; | ||
for (const namespace of namespaces) { | ||
const namespaceMethods = []; | ||
for (const method of namespace.methods) { | ||
namespaceMethods.push( | ||
`${method.name}: { | ||
parameters: RequestParameters & Omit<Endpoints["${method.route}"]["parameters"], "baseUrl" | "headers" | "mediaType">, | ||
response: Endpoints["${method.route}"]["response"] | ||
}` | ||
); | ||
} | ||
|
||
RestEndpointMethodParameterAndResponseTypes.push(`${ | ||
namespace.namespace | ||
}: { | ||
${namespaceMethods.join("\n")} | ||
}`); | ||
} | ||
|
||
const RestEndpointMethodNamespaceTypes = []; | ||
for (const namespace of namespaces) { | ||
const namespaceMethods = []; | ||
for (const method of namespace.methods) { | ||
namespaceMethods.push( | ||
[ | ||
method.jsdoc, | ||
`${method.name}: { | ||
(params?: RestEndpointMethodTypes["${namespace.namespace}"]["${method.name}"]["parameters"]): Promise<RestEndpointMethodTypes["${namespace.namespace}"]["${method.name}"]["response"]> | ||
defaults: RequestInterface["defaults"]; | ||
endpoint: EndpointInterface<{ url: string }>; | ||
}`, | ||
].join("\n") | ||
); | ||
} | ||
|
||
RestEndpointMethodNamespaceTypes.push(`${namespace.namespace}: { | ||
${namespaceMethods.join("\n")} | ||
}`); | ||
} | ||
|
||
const methodTypesSource = prettier.format( | ||
[ | ||
`import { EndpointInterface, RequestInterface } from "@octokit/types";`, | ||
`import { RestEndpointMethodTypes } from "./ghe-${version}-parameters-and-response-types";`, | ||
"", | ||
`export type RestEndpointMethods = { | ||
${RestEndpointMethodNamespaceTypes.join("\n")} | ||
}`, | ||
].join("\n"), | ||
{ | ||
parser: "typescript", | ||
} | ||
); | ||
const parametersAndResponsesTypes = prettier.format( | ||
[ | ||
`import { Endpoints, RequestParameters } from "@octokit/types";`, | ||
"", | ||
`export type RestEndpointMethodTypes = { | ||
${RestEndpointMethodParameterAndResponseTypes.join("\n")} | ||
}`, | ||
].join("\n"), | ||
{ | ||
parser: "typescript", | ||
} | ||
); | ||
|
||
const methodTypesFilePath = pathJoin( | ||
process.cwd(), | ||
"src", | ||
"generated", | ||
`ghe-${version}-method-types.ts` | ||
); | ||
|
||
writeFileSync(methodTypesFilePath, methodTypesSource, "utf8"); | ||
console.log(`Types written to ${methodTypesFilePath}`); | ||
|
||
const parametersAndResponseFilePath = pathJoin( | ||
process.cwd(), | ||
"src", | ||
"generated", | ||
`ghe-${version}-parameters-and-response-types.ts` | ||
); | ||
|
||
writeFileSync( | ||
parametersAndResponseFilePath, | ||
parametersAndResponsesTypes, | ||
"utf8" | ||
); | ||
console.log(`Types written to ${parametersAndResponseFilePath}`); | ||
} | ||
} | ||
|
||
async function getRoutes(version) { | ||
const newRoutes = {}; | ||
const ENDPOINTS = require(`./generated/ghe${version}-endpoints.json`); | ||
|
||
ENDPOINTS.forEach((endpoint) => { | ||
if (isDeprecated(endpoint)) return; | ||
|
||
const scope = endpoint.scope; | ||
|
||
if (!newRoutes[scope]) { | ||
newRoutes[scope] = {}; | ||
} | ||
|
||
const idName = endpoint.id; | ||
const url = endpoint.url | ||
.toLowerCase() | ||
// stecial case for "Upload a release asset": remove ":origin" prefix | ||
.replace(/^:origin/, ""); | ||
|
||
// new route | ||
newRoutes[scope][idName] = { | ||
method: endpoint.method, | ||
url, | ||
description: endpoint.description, | ||
hasRequiredPreviews: !!endpoint.previews.length, | ||
deprecated: newRoutes[scope][idName] | ||
? newRoutes[scope][idName].deprecated | ||
: undefined, | ||
}; | ||
|
||
if (endpoint.renamed) { | ||
const { before, after } = endpoint.renamed; | ||
if (!newRoutes[before.scope]) { | ||
newRoutes[before.scope] = {}; | ||
} | ||
|
||
if (!newRoutes[before.scope][before.id]) { | ||
newRoutes[before.scope][before.id] = newRoutes[scope][idName]; | ||
} | ||
|
||
newRoutes[before.scope][ | ||
before.id | ||
].deprecated = `octokit.rest.${before.scope}.${before.id}() has been renamed to octokit.rest.${after.scope}.${after.id}() (${endpoint.renamed.date})`; | ||
} | ||
|
||
if (endpoint.isDeprecated) { | ||
newRoutes[scope][ | ||
idName | ||
].deprecated = `octokit.rest.${scope}.${idName}() is deprecated, see ${endpoint.documentationUrl}`; | ||
} | ||
}); | ||
|
||
return sortKeys(newRoutes, { deep: true }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
module.exports = { | ||
isDeprecated, | ||
}; | ||
|
||
/** | ||
* we ignore all legacy endpoints except the ones that were recently added | ||
* @param { Endpoint } endpoint | ||
*/ | ||
function isDeprecated(endpoint) { | ||
const deprecated = endpoint.isLegacy || endpoint.isDeprecated; | ||
|
||
if (!deprecated) { | ||
return false; | ||
} | ||
|
||
// if (endpoint.isLegacy && /^\/teams\/\{team_id\}/.test(endpoint.url)) { | ||
// return false; | ||
// } | ||
|
||
if ( | ||
endpoint.method === "DELETE" && | ||
endpoint.url === "/reactions/{reaction_id}" | ||
) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} |
Oops, something went wrong.