Skip to content

Commit

Permalink
feat(typescript): typescript definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
gr2m committed Jun 29, 2021
1 parent e8ec227 commit 303e650
Show file tree
Hide file tree
Showing 16 changed files with 72,853 additions and 53 deletions.
18,822 changes: 18,781 additions & 41 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"test": "jest --coverage",
"update-endpoints": "npm-run-all update-endpoints:*",
"update-endpoints:fetch-json": "node scripts/update-endpoints/fetch-json",
"update-endpoints:code": "node scripts/update-endpoints/code"
"update-endpoints:code": "node scripts/update-endpoints/code",
"update-endpoints:types": "node scripts/update-endpoints/types"
},
"repository": "github:octokit/plugin-enterprise-server.js",
"keywords": [
Expand Down Expand Up @@ -44,11 +45,13 @@
"fetch-mock": "^9.0.0",
"github-openapi-graphql-query": "^1.0.5",
"jest": "^27.0.0",
"lodash.camelcase": "^4.3.0",
"npm-run-all": "^4.1.5",
"prettier": "2.3.2",
"semantic-release": "^17.0.0",
"semantic-release-plugin-update-version-in-files": "^1.0.0",
"sort-keys": "^4.2.0",
"string-to-jsdoc-comment": "^1.0.0",
"ts-jest": "^27.0.0-next.12",
"typescript": "^4.0.2"
},
Expand Down
7 changes: 5 additions & 2 deletions scripts/update-endpoints/code.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,16 +110,19 @@ async function generateRoutes() {
(version) => `
import ENDPOINTS_${version} from "./generated/ghe-${version}-endpoints";
import ADMIN_ENDPOINTS_${version} from "./generated/ghe-${version}-admin-endpoints";
import { RestEndpointMethods as RestEndpointMethods_${version} } from "./generated/ghe-${version}-method-types";
`
).join("\n");
const methods = GHE_VERSIONS.map(
(version) => `
export function enterpriseServer${version}Admin(octokit: Octokit) {
export function enterpriseServer${version}Admin(octokit: Octokit): { enterpriseAdmin: RestEndpointMethods_${version}["enterpriseAdmin"] } {
// @ts-ignore - not worth the hassle
return endpointsToMethods(octokit, ADMIN_ENDPOINTS_${version});
}
enterpriseServer${version}Admin.VERSION = VERSION;
export function enterpriseServer${version}(octokit: Octokit) {
export function enterpriseServer${version}(octokit: Octokit): RestEndpointMethods_${version} {
// @ts-ignore - not worth the hassle
return endpointsToMethods(octokit, ENDPOINTS_${version});
}
enterpriseServer${version}.VERSION = VERSION;
Expand Down
191 changes: 191 additions & 0 deletions scripts/update-endpoints/types.js
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 });
}
28 changes: 28 additions & 0 deletions scripts/update-endpoints/util.js
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;
}
Loading

0 comments on commit 303e650

Please sign in to comment.