Skip to content

Commit

Permalink
feat: migrate to ESM (#968)
Browse files Browse the repository at this point in the history
* feat: migrate to ESM

* build: fixup `generate-types` script

* build: update `ts-node` config to use ESM

* build: disable `verbatimModuleSyntax` for `ts-node`

There is currently a bug in ts-node where it completely ignores the `module` and `moduleResolution` options
kulshekhar/ts-jest#4198

* test: use ESM export for jest
  • Loading branch information
wolfy1339 committed Feb 14, 2024
1 parent cd653a1 commit 5518092
Show file tree
Hide file tree
Showing 16 changed files with 67 additions and 63 deletions.
5 changes: 3 additions & 2 deletions jest.config.ts
Expand Up @@ -10,11 +10,13 @@ const config: Config.InitialOptions = {
lines: 100,
},
},
extensionsToTreatAsEsm: ['.ts'],
transform: {
"^.+\\.tsx?$": [
"ts-jest",
{
tsconfig: "test/tsconfig.json",
useESM: true,
},
],
},
Expand All @@ -27,5 +29,4 @@ const config: Config.InitialOptions = {
testRegex: /test\/.*\/.*.test.ts/u.source,
};

// We have to use a CommonJS export here due to `verbatimModuleSyntax`
module.exports = config;
export default config;
60 changes: 38 additions & 22 deletions package-lock.json

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

8 changes: 4 additions & 4 deletions package.json
@@ -1,6 +1,7 @@
{
"name": "@octokit/webhooks",
"version": "0.0.0-development",
"type": "module",
"description": "GitHub webhook events toolset for Node.js",
"keywords": [],
"repository": "github:octokit/webhooks.js",
Expand All @@ -9,11 +10,11 @@
"scripts": {
"build": "node scripts/build.mjs && tsc -p tsconfig.json",
"coverage": "jest --coverage && open coverage/lcov-report/index.html",
"generate-types": "ts-node --transpile-only scripts/generate-types.ts",
"generate-types": "node --loader=ts-node/esm scripts/generate-types.ts",
"lint": "prettier --check 'src/**/*.{ts,json}' 'scripts/**/*' 'test/**/*.ts' README.md package.json",
"lint:fix": "prettier --write 'src/**/*.{ts,json}' 'scripts/**/*' 'test/**/*.ts' README.md package.json",
"pretest": "npm run -s lint",
"test": "jest --coverage",
"test": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" npx jest --coverage",
"validate:ts": "tsc --noEmit --noImplicitAny --target es2020 --esModuleInterop --moduleResolution node16 --module node16 --allowImportingTsExtensions test/typescript-validate.ts"
},
"prettier": {},
Expand Down Expand Up @@ -43,14 +44,13 @@
"@octokit/request-error": "^5.0.0",
"@octokit/webhooks-methods": "^4.0.0",
"@wolfy1339/openapi-webhooks-types": "5.1.3",
"aggregate-error": "^3.1.0"
"aggregate-error": "^5.0.0"
},
"devDependencies": {
"@jest/types": "^29.0.0",
"@octokit/tsconfig": "^2.0.0",
"@types/jest": "^29.0.0",
"@types/node": "^20.0.0",
"@types/prettier": "^2.0.0",
"@wolfy1339/openapi-webhooks": "5.1.3",
"axios": "^1.0.0",
"esbuild": "^0.20.0",
Expand Down
2 changes: 1 addition & 1 deletion scripts/build.mjs
Expand Up @@ -43,7 +43,7 @@ async function main() {
bundle: true,
platform: "node",
target: "node18",
format: "cjs",
format: "esm",
...sharedOptions,
}),
// Build an ESM browser bundle
Expand Down
2 changes: 1 addition & 1 deletion scripts/generate-types.ts
Expand Up @@ -5,7 +5,7 @@ import * as fs from "node:fs";
import type { OpenAPI3, OperationObject, PathItemObject } from "./types.js";
import { format } from "prettier";

const schema = require("@wolfy1339/openapi-webhooks").schemas[
const schema = (await import("@wolfy1339/openapi-webhooks")).default.schemas[
"api.github.com"
] as OpenAPI3;

Expand Down
3 changes: 0 additions & 3 deletions src/event-handler/receive.ts
@@ -1,4 +1,3 @@
// @ts-ignore to address #245
import AggregateError from "aggregate-error";
import type {
EmitterWebhookEvent,
Expand Down Expand Up @@ -35,7 +34,6 @@ export function receiverHandle(state: State, event: EmitterWebhookEvent) {
if (event instanceof Error) {
const error = Object.assign(new AggregateError([event]), {
event,
errors: [event],
});

errorHandlers.forEach((handler) => wrapErrorHandler(handler, error));
Expand Down Expand Up @@ -85,7 +83,6 @@ export function receiverHandle(state: State, event: EmitterWebhookEvent) {
const error = new AggregateError(errors) as WebhookEventHandlerError;
Object.assign(error, {
event,
errors,
});

errorHandlers.forEach((handler) => wrapErrorHandler(handler, error));
Expand Down
6 changes: 2 additions & 4 deletions src/middleware/node/middleware.ts
@@ -1,8 +1,6 @@
// remove type imports from http for Deno compatibility
// see https://github.com/octokit/octokit.js/issues/2075#issuecomment-817361886
// import type { IncomingMessage, ServerResponse } from "node:http";
type IncomingMessage = any;
type ServerResponse = any;
import type { IncomingMessage, ServerResponse } from "node:http";

import type { WebhookEventName } from "../../generated/webhook-identifiers.js";

Expand Down Expand Up @@ -112,7 +110,7 @@ export async function middleware(

if (didTimeout) return true;

const err = Array.from(error as WebhookEventHandlerError)[0];
const err = Array.from((error as WebhookEventHandlerError).errors)[0];
const errorMessage = err.message
? `${err.name}: ${err.message}`
: "Error: An Unspecified error occurred";
Expand Down
18 changes: 1 addition & 17 deletions src/types.ts
Expand Up @@ -3,6 +3,7 @@ import type { webhooks as OpenAPIWebhooks } from "@wolfy1339/openapi-webhooks-ty
import type { EventPayloadMap } from "./generated/webhook-identifiers.js";
import type { Logger } from "./createLogger.js";
import type { emitterEventNames } from "./generated/webhook-names.js";
import type AggregateError from "aggregate-error";

export type WebhookEventName = keyof EventPayloadMap;
export type ExtractEvents<TEventName> =
Expand Down Expand Up @@ -75,20 +76,3 @@ export interface WebhookEventHandlerError<TTransformed = unknown>
? EmitterWebhookEvent
: EmitterWebhookEvent & TTransformed;
}

/**
* Workaround for TypeScript incompatibility with types exported by aggregate-error.
* Credit: https://git.io/JUEEr
* @copyright Sindre Sorhus
* @license MIT (https://git.io/JUEEK)
* @see https://github.com/octokit/webhooks.js/pull/270/files
*/
declare class AggregateError<T extends Error = Error>
extends Error
implements Iterable<T>
{
readonly name: "AggregateError";
constructor(errors: ReadonlyArray<T | { [key: string]: any } | string>);

[Symbol.iterator](): IterableIterator<T>;
}
10 changes: 5 additions & 5 deletions test/integration/event-handler-test.ts
Expand Up @@ -91,12 +91,12 @@ describe("when a handler throws an error", () => {
} catch (error: any) {
expect(error.message).toMatch(/oops/);

const errors = Array.from(error);
const errors = Array.from(error.errors);

expect(errors.length).toBe(1);
expect((Array.from(error) as { message: string }[])[0].message).toBe(
"oops",
);
expect(
(Array.from(error.errors) as { message: string }[])[0].message,
).toBe("oops");

expect(error instanceof Error).toBeTruthy();
}
Expand Down Expand Up @@ -194,7 +194,7 @@ test("multiple errors in same event handler", async () => {
});
} catch (error: any) {
expect(error.message).toMatch("oops");
expect(Array.from(error).length).toBe(2);
expect(Array.from(error.errors).length).toBe(2);

expect(error instanceof Error);
}
Expand Down
4 changes: 3 additions & 1 deletion test/integration/node-middleware.test.ts
Expand Up @@ -2,9 +2,11 @@ import { createServer } from "node:http";
import { readFileSync } from "node:fs";

import { sign } from "@octokit/webhooks-methods";
import { jest } from "@jest/globals";

// import without types
const express = require("express");
// @ts-expect-error
const express = (await import("express")).default;

import { createNodeMiddleware, Webhooks } from "../../src/index.ts";

Expand Down
1 change: 1 addition & 0 deletions test/integration/smoke-test.ts
Expand Up @@ -3,6 +3,7 @@ import {
createEventHandler,
emitterEventNames,
} from "../../src/index.ts";
import { jest } from "@jest/globals";

test("@octokit/webhooks", () => {
const emitWarningSpy = jest.spyOn(process, "emitWarning");
Expand Down
2 changes: 1 addition & 1 deletion test/typescript-validate.ts
Expand Up @@ -182,7 +182,7 @@ export default async function () {

webhooks.onError((error) => {
console.log(error.event.name);
const [firstError] = Array.from(error);
const [firstError] = Array.from(error.errors);
console.log(firstError.status);
console.log(firstError.headers);
console.log(firstError.request);
Expand Down
1 change: 1 addition & 0 deletions test/unit/createLogger-test.ts
@@ -1,4 +1,5 @@
import { createLogger } from "../../src/createLogger.ts";
import { jest } from "@jest/globals";

const noop = () => {};

Expand Down
1 change: 1 addition & 0 deletions test/unit/event-handler-on-test.ts
@@ -1,5 +1,6 @@
import { receiverOn } from "../../src/event-handler/on.ts";
import type { State } from "../../src/types.ts";
import { jest } from "@jest/globals";

function noop() {}

Expand Down
1 change: 1 addition & 0 deletions test/unit/event-handler-wrap-error-handler-test.ts
@@ -1,4 +1,5 @@
import { wrapErrorHandler } from "../../src/event-handler/wrap-error-handler.ts";
import { jest } from "@jest/globals";

const noop = () => {};

Expand Down
6 changes: 4 additions & 2 deletions tsconfig.json
Expand Up @@ -3,11 +3,13 @@
"include": ["src/**/*"],
"ts-node": {
"compilerOptions": {
"module": "CommonJS",
"esModuleInterop": true
"verbatimModuleSyntax": false
}
},
"compilerOptions": {
"lib": ["ESNext"],
"module": "Node16",
"moduleResolution": "node16",
"esModuleInterop": true,
"declaration": true,
"outDir": "pkg/dist-types",
Expand Down

0 comments on commit 5518092

Please sign in to comment.