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

feat(types): use OpenAPI spec #841

Merged
merged 33 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
8d50153
feat: use OpenAPI spec
wolfy1339 Apr 15, 2023
be322a2
style: prettier
wolfy1339 Apr 15, 2023
5962551
fix: resolve typescript errors
wolfy1339 Apr 15, 2023
f84e6f1
refactor: reduce the need for a payload map
wolfy1339 Apr 15, 2023
eb0fca6
style: run prettier
wolfy1339 Apr 15, 2023
44e5c19
test: fixup types for fixtures
wolfy1339 Apr 15, 2023
9aed845
chore: update push event payload
wolfy1339 Apr 15, 2023
b769e00
fix: add `push` event to the event payload map
wolfy1339 Apr 15, 2023
ecc7581
fix: get the proper event name when we have an action
wolfy1339 Apr 15, 2023
141af6a
fix: don't convert the event name when we don't have an action
wolfy1339 Apr 15, 2023
471c4f5
fix: correct event name when we have an action
wolfy1339 Apr 15, 2023
324898f
build: upgrade OpenAPI types
wolfy1339 Apr 30, 2023
9317e36
build: add script to update generated files + readme
wolfy1339 May 21, 2023
5c63549
fix: always add events to the map regardless of if they have an action
wolfy1339 May 21, 2023
9f81488
build: regenerate identifiers map
wolfy1339 May 21, 2023
440bcf9
docs: regenerate README with new URL
wolfy1339 May 21, 2023
5a33b5a
style: remove unused variables
wolfy1339 May 21, 2023
88a566a
Merge branch 'main' into openapi
wolfy1339 Nov 19, 2023
1e62dbf
style: prettier
wolfy1339 Nov 19, 2023
d26c246
build: update types
wolfy1339 Nov 19, 2023
1235f02
build(deps): update openapi spec
wolfy1339 Nov 19, 2023
e6edbce
build(deps): update openapi specs
wolfy1339 Nov 19, 2023
4f5ee13
test: `user` can be null
wolfy1339 Nov 19, 2023
d0b019c
Merge branch 'main' into openapi
wolfy1339 Dec 4, 2023
eaa9185
chore: various small fixes
wolfy1339 Dec 4, 2023
409e417
build: cleanup deps
wolfy1339 Dec 4, 2023
334d6ff
build: replace `generate-types` script with OpenAPI version
wolfy1339 Dec 4, 2023
d1ab1f8
feat: update `@wolfy1339/openapi-webhooks`
wolfy1339 Dec 4, 2023
65d5666
fix: remove un-needed type casting
wolfy1339 Dec 4, 2023
a5e95b7
style: prettier
wolfy1339 Dec 4, 2023
128d795
refactor(types): reduce need for duplication and simplify
wolfy1339 Dec 4, 2023
fe86a17
test: use OpenAPI types
wolfy1339 Dec 4, 2023
0e63ff7
Merge remote-tracking branch 'origin/beta' into openapi
wolfy1339 Feb 11, 2024
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
138 changes: 73 additions & 65 deletions README.md

Large diffs are not rendered by default.

33 changes: 13 additions & 20 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,16 @@
"dependencies": {
"@octokit/request-error": "^5.0.0",
"@octokit/webhooks-methods": "^4.0.0",
"@octokit/webhooks-types": "7.3.2",
"@wolfy1339/openapi-webhooks-types": "5.1.3",
"aggregate-error": "^3.1.0"
},
"devDependencies": {
"@jest/types": "^29.0.0",
"@octokit/tsconfig": "^2.0.0",
"@octokit/webhooks-schemas": "7.3.2",
"@types/jest": "^29.0.0",
"@types/json-schema": "^7.0.7",
"@types/node": "^20.0.0",
"@types/prettier": "^2.0.0",
"@wolfy1339/openapi-webhooks": "5.1.3",
"axios": "^1.0.0",
"esbuild": "^0.20.0",
"express": "^4.17.1",
Expand Down
107 changes: 41 additions & 66 deletions scripts/generate-types.ts
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -2,76 +2,34 @@

import { strict as assert } from "node:assert";
import * as fs from "node:fs";
import type { JSONSchema7, JSONSchema7Definition } from "json-schema";
import type { OpenAPI3, OperationObject, PathItemObject } from "./types.js";
import { format } from "prettier";

type JSONSchemaWithRef = JSONSchema7 & Required<Pick<JSONSchema7, "$ref">>;

interface Schema extends JSONSchema7 {
definitions: Record<string, JSONSchema7>;
oneOf: JSONSchemaWithRef[];
}

const schema = require("@octokit/webhooks-schemas") as Schema;

const guessAtEventName = (name: string) => {
const [, eventName] = /^(.+)[$_-]event/u.exec(name) ?? [];

assert.ok(eventName, `unable to guess event name for "${name}"`);

return eventName;
};
const guessAtActionName = (name: string) => name.replace("$", ".");

const getDefinitionName = (ref: string): string => {
assert.ok(
ref.startsWith("#/definitions/"),
`${ref} does not reference a valid definition`,
);

const [, name] = /^#\/definitions\/(.+)$/u.exec(ref) ?? [];

assert.ok(name, `unable to find definition name ${ref}`);

return name;
};

type NameAndActions = [name: string, actions: string[]];

const buildEventProperties = ([
eventName,
actions,
]: NameAndActions): string[] => [
guessAtEventName(eventName),
...actions.map(guessAtActionName),
];

const isJSONSchemaWithRef = (
object: JSONSchema7Definition,
): object is JSONSchemaWithRef =>
typeof object === "object" && object.$ref !== undefined;

const listEvents = () => {
return schema.oneOf.map<NameAndActions>(({ $ref }) => {
const name = getDefinitionName($ref);
const definition = schema.definitions[name];

assert.ok(definition, `unable to find definition named ${name}`);

if (definition.oneOf?.every(isJSONSchemaWithRef)) {
return [name, definition.oneOf.map((def) => getDefinitionName(def.$ref))];
}

return [name, []];
});
};
const schema = require("@wolfy1339/openapi-webhooks").schemas[
"api.github.com"
] as OpenAPI3;

const getEmitterEvents = (): string[] => {
return listEvents().reduce<string[]>(
(properties, event) => properties.concat(buildEventProperties(event)),
[],
);
return Array.from(events).sort();
};
const eventsMap: Record<string, Set<string>> = {};
const events = new Set<string>();

for (let webhookDefinitionKey of Object.keys(schema.webhooks!)) {
const webhookDefinition = schema.webhooks![
webhookDefinitionKey
] as PathItemObject;
const operationDefinition = webhookDefinition.post as OperationObject;
const emitterEventName = operationDefinition
.operationId!.replace(/-/g, "_")
.replace("/", ".");

const [eventName] = emitterEventName.split(".");
events.add(eventName);
events.add(emitterEventName);
eventsMap[eventName] ||= new Set<string>();
eventsMap[eventName].add(webhookDefinitionKey);
}

const outDir = "src/generated/";

Expand All @@ -84,7 +42,7 @@ const generateTypeScriptFile = async (name: string, contents: string[]) => {

const asCode = (str: string): string => `\`${str}\``;
const asLink = (event: string): string => {
const link = `https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#${event.replace(
const link = `https://docs.github.com/en/webhooks-and-events/webhook-events-and-payloads#${event.replace(
/[^a-z_0-9]/g,
"",
)}`;
Expand Down Expand Up @@ -153,6 +111,23 @@ const run = async () => {
"] as const;",
]);

await generateTypeScriptFile("webhook-identifiers", [
"// THIS FILE IS GENERATED - DO NOT EDIT DIRECTLY",
"// make edits in scripts/generate-types.ts",
"",
"import type { WebhookEventDefinition } from '../types.js';",
"",
"export type EventPayloadMap = {",
...Object.keys(eventsMap).map(
(key) =>
`"${key}": ${Array.from(eventsMap[key])
.map((event) => `WebhookEventDefinition<` + `"${event}">`)
.join(" | ")}`,
),
"}",
"export type WebhookEventName = keyof EventPayloadMap;",
]);

await updateReadme(emitterEvents);
};

Expand Down
Loading