Skip to content

Commit

Permalink
Merge branch 'main' into test-node-23
Browse files Browse the repository at this point in the history
  • Loading branch information
RobinTail authored Dec 23, 2024
2 parents 8dd958d + cac42a0 commit ba2736e
Show file tree
Hide file tree
Showing 19 changed files with 449 additions and 585 deletions.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@

## Version 2

### v2.2.0

- Naming of circular types is now numeric:
- Deprecated `serializer` property on the `Integration` constructor argument (no longer used).

```diff
- type Type2048581c137c5b2130eb860e3ae37da196dfc25b = {
+ type Type1 = {
title: string;
- features: Type2048581c137c5b2130eb860e3ae37da196dfc25b;
+ features: Type1;
}[];
```

### v2.1.1

- Documentation update on compatibility with Express Zod API v21;
- Tested compatibility with Express v5;
- Removed redundant `event` argument for `Action::execute()`.

### v2.1.0

- Featuring `onError` hook for handling errors of various natures:
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ assign it to the `target` property.
import { createServer } from "express-zod-api";
import { attachSockets } from "zod-sockets";

const { httpServer, httpsServer } = await createServer();
attachSockets({ target: httpsServer || httpServer });
const { servers } = await createServer();
attachSockets({ target: servers.pop()! });
```

## Logger compatibility
Expand Down Expand Up @@ -456,7 +456,7 @@ import { attachSockets, createSimpleConfig, ActionsFactory } from "zod-sockets";
import { Server } from "socket.io";
import { z } from "zod";

const { logger, httpsServer, httpServer } = await createServer();
const { logger, servers } = await createServer();

const config = createSimpleConfig({
emission: {
Expand All @@ -476,7 +476,7 @@ await attachSockets({
config,
logger,
io: new Server(),
target: httpsServer || httpServer,
target: servers.pop()!,
actions: [
factory.build({
event: "subscribe",
Expand Down
6 changes: 3 additions & 3 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import prettierRules from "eslint-plugin-prettier/recommended";
import unicornPlugin from "eslint-plugin-unicorn";
import allowedDepsPlugin from "eslint-plugin-allowed-dependencies";

export default [
export default tsPlugin.config(
{
languageOptions: { globals: globals.node },
plugins: {
Expand All @@ -15,7 +15,7 @@ export default [
},
},
jsPlugin.configs.recommended,
...tsPlugin.configs.recommended,
tsPlugin.configs.recommended,
prettierOverrides,
prettierRules,
// Things to turn off globally
Expand Down Expand Up @@ -69,4 +69,4 @@ export default [
"prettier/prettier": "off",
},
},
];
);
2 changes: 1 addition & 1 deletion example/example-documentation.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
asyncapi: 3.0.0
info:
title: Example APP
version: 2.1.0
version: 2.2.0
contact:
name: Anna Bocharova
url: https://robintail.cz
Expand Down
13 changes: 8 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zod-sockets",
"version": "2.1.0",
"version": "2.2.0",
"description": "Socket.IO solution with I/O validation and the ability to generate AsyncAPI specification and a contract for consumers",
"type": "module",
"main": "dist/index.cjs",
Expand Down Expand Up @@ -68,30 +68,33 @@
"zod": "^3.23.0"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.16.2",
"@arethetypeswrong/cli": "^0.17.0",
"@tsconfig/node18": "^18.2.4",
"@types/node": "^22.0.0",
"@types/ramda": "^0.30.0",
"@types/semver": "^7.5.8",
"@vitest/coverage-istanbul": "^2.0.4",
"@vitest/coverage-istanbul": "^2.1.5",
"eslint": "^9.4.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-allowed-dependencies": "^1.0.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^56.0.0",
"husky": "^9.0.10",
"make-coverage-badge": "^1.2.0",
"prettier": "3.3.3",
"prettier": "3.4.2",
"semver": "^7.6.3",
"socket.io": "^4.7.4",
"socket.io-client": "^4.7.4",
"tsup": "^8.0.1",
"tsx": "^4.7.0",
"typescript": "^5.3.3",
"typescript-eslint": "^8.0.1",
"vitest": "^2.0.4",
"vitest": "^2.1.5",
"zod": "^3.22.4"
},
"resolutions": {
"**/vite": "^6"
},
"keywords": [
"nodejs",
"socket",
Expand Down
6 changes: 3 additions & 3 deletions src/__snapshots__/integration.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ exports[`Integration > print() > should handle circular references 1`] = `
export namespace Root {
/** @desc The actual path of the Root namespace */
export const path = "/";
type Type2048581c137c5b2130eb860e3ae37da196dfc25b = {
type Type1 = {
title: string;
features: Type2048581c137c5b2130eb860e3ae37da196dfc25b;
features: Type1;
}[];
export interface Emission {
time: (currentIsoTime: string) => void;
Expand All @@ -22,7 +22,7 @@ export namespace Root {
export interface Actions {
test: (p1: {
title: string;
features: Type2048581c137c5b2130eb860e3ae37da196dfc25b;
features: Type1;
}) => void;
}
/** @example const socket: Root.Socket = io(Root.path) */
Expand Down
4 changes: 2 additions & 2 deletions src/__snapshots__/zts.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ exports[`zod-to-ts > Example > should produce the expected results 1`] = `
string: string;
}[];
boolean: boolean;
circular: Type118cb3b11b8a1f3b6b1e60a89f96a8be9da32a0f;
circular: SomeType;
union: {
number: number;
} | "hi";
Expand Down Expand Up @@ -60,7 +60,7 @@ exports[`zod-to-ts > Example > should produce the expected results 1`] = `
optDefaultString?: string | undefined;
refinedStringWithSomeBullshit: (string | number) & ((bigint | null) | undefined);
nativeEnum: "A" | "apple" | "banana" | "cantaloupe" | 5;
lazy: Type51497f7e879bae48c3fbad2fa68050d1e08bbf82;
lazy: SomeType;
discUnion: {
kind: "circle";
radius: number;
Expand Down
4 changes: 0 additions & 4 deletions src/integration-helpers.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { createHash } from "node:crypto";
import { range } from "ramda";
import ts from "typescript";
import { z } from "zod";

export const f = ts.factory;
export const exportModifier = [f.createModifier(ts.SyntaxKind.ExportKeyword)];

export const defaultSerializer = (schema: z.ZodTypeAny): string =>
createHash("sha1").update(JSON.stringify(schema), "utf8").digest("hex");

export const makeEventFnSchema = (
base: z.AnyZodTuple,
ack?: z.AnyZodTuple,
Expand Down
43 changes: 16 additions & 27 deletions src/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@ import { z } from "zod";
import { AbstractAction } from "./action";
import { makeCleanId } from "./common-helpers";
import { Config } from "./config";
import {
defaultSerializer,
exportModifier,
f,
makeEventFnSchema,
} from "./integration-helpers";
import { exportModifier, f, makeEventFnSchema } from "./integration-helpers";
import { Namespaces, normalizeNS } from "./namespace";
import { zodToTs } from "./zts";
import { addJsDocComment, createTypeAlias, printNode } from "./zts-helpers";
Expand All @@ -24,8 +19,8 @@ interface IntegrationProps {
*/
maxOverloads?: number;
/**
* @desc Used for comparing schemas wrapped into z.lazy() to limit the recursion
* @default JSON.stringify() + SHA1 hash as a hex digest
* @deprecated unused
* @todo remove in next major
* */
serializer?: (schema: z.ZodTypeAny) => string;
/**
Expand Down Expand Up @@ -53,7 +48,7 @@ export class Integration {
protected program: ts.Node[] = [];
protected aliases: Record<
string, // namespace
Record<string, ts.TypeAliasDeclaration>
Map<z.ZodTypeAny, ts.TypeAliasDeclaration>
> = {};
protected ids = {
path: f.createIdentifier("path"),
Expand All @@ -71,28 +66,24 @@ export class Integration {
>
> = {};

protected getAlias(
ns: string,
name: string,
): ts.TypeReferenceNode | undefined {
return name in this.aliases[ns]
? f.createTypeReferenceNode(name)
: undefined;
}

protected makeAlias(
ns: string,
name: string,
type: ts.TypeNode,
schema: z.ZodTypeAny,
produce: () => ts.TypeNode,
): ts.TypeReferenceNode {
this.aliases[ns][name] = createTypeAlias(type, name);
return this.getAlias(ns, name)!;
let name = this.aliases[ns].get(schema)?.name?.text;
if (!name) {
name = `Type${this.aliases[ns].size + 1}`;
const temp = f.createLiteralTypeNode(f.createNull());
this.aliases[ns].set(schema, createTypeAlias(temp, name));
this.aliases[ns].set(schema, createTypeAlias(produce(), name));
}
return f.createTypeReferenceNode(name);
}

constructor({
config: { namespaces },
actions,
serializer = defaultSerializer,
optionalPropStyle = { withQuestionMark: true, withUndefined: true },
maxOverloads = 3,
}: IntegrationProps) {
Expand All @@ -115,12 +106,10 @@ export class Integration {
);

for (const [ns, { emission }] of Object.entries(namespaces)) {
this.aliases[ns] = {};
this.aliases[ns] = new Map<z.ZodTypeAny, ts.TypeAliasDeclaration>();
this.registry[ns] = { emission: [], actions: [] };
const commons = {
getAlias: this.getAlias.bind(this, ns),
makeAlias: this.makeAlias.bind(this, ns),
serializer,
optionalPropStyle,
};
for (const [event, { schema, ack }] of Object.entries(emission)) {
Expand Down Expand Up @@ -197,7 +186,7 @@ export class Integration {
f.createIdentifier(publicName),
f.createModuleBlock([
nsNameNode,
...Object.values(this.aliases[ns]),
...this.aliases[ns].values(),
...interfaces,
socketNode,
]),
Expand Down
15 changes: 7 additions & 8 deletions src/zts-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ export type LiteralType = string | number | boolean;

export interface ZTSContext extends FlatObject {
direction: "in" | "out";
getAlias: (name: string) => ts.TypeReferenceNode | undefined;
makeAlias: (name: string, type: ts.TypeNode) => ts.TypeReferenceNode;
serializer: (schema: z.ZodTypeAny) => string;
makeAlias: (
schema: z.ZodTypeAny,
produce: () => ts.TypeNode,
) => ts.TypeReferenceNode;
optionalPropStyle: { withQuestionMark?: boolean; withUndefined?: boolean };
}

Expand All @@ -28,18 +29,16 @@ export const addJsDocComment = (node: ts.Node, text: string) => {

export const createTypeAlias = (
node: ts.TypeNode,
identifier: string,
name: string,
comment?: string,
) => {
const typeAlias = f.createTypeAliasDeclaration(
undefined,
f.createIdentifier(identifier),
f.createIdentifier(name),
undefined,
node,
);
if (comment) {
addJsDocComment(typeAlias, comment);
}
if (comment) addJsDocComment(typeAlias, comment);
return typeAlias;
};

Expand Down
6 changes: 2 additions & 4 deletions src/zts.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import assert from "node:assert/strict";
import ts from "typescript";
import { z } from "zod";
import { defaultSerializer, f } from "./integration-helpers";
import { f } from "./integration-helpers";
import { zodToTs } from "./zts";
import { ZTSContext, createTypeAlias, printNode } from "./zts-helpers";
import { describe, expect, test, vi } from "vitest";
Expand All @@ -11,9 +11,7 @@ describe("zod-to-ts", () => {
printNode(node, { newLine: ts.NewLineKind.LineFeed });
const defaultCtx: ZTSContext = {
direction: "in",
getAlias: vi.fn((name: string) => f.createTypeReferenceNode(name)),
makeAlias: vi.fn(),
serializer: defaultSerializer,
makeAlias: vi.fn(() => f.createTypeReferenceNode("SomeType")),
optionalPropStyle: { withQuestionMark: true, withUndefined: true },
};

Expand Down
15 changes: 2 additions & 13 deletions src/zts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,19 +196,8 @@ const onNull: Producer = () => f.createLiteralTypeNode(f.createNull());
const onDate: Producer = () =>
f.createTypeReferenceNode(f.createIdentifier("Date"));

const onLazy: Producer = (
lazy: z.ZodLazy<z.ZodTypeAny>,
{ getAlias, makeAlias, next, serializer: serialize },
) => {
const name = `Type${serialize(lazy.schema)}`;
return (
getAlias(name) ||
(() => {
makeAlias(name, f.createLiteralTypeNode(f.createNull())); // make empty type first
return makeAlias(name, next(lazy.schema)); // update
})()
);
};
const onLazy: Producer = (lazy: z.ZodLazy<z.ZodTypeAny>, { makeAlias, next }) =>
makeAlias(lazy, () => next(lazy.schema));

const onFunction: Producer = (
schema: z.ZodFunction<z.AnyZodTuple, z.ZodTypeAny>,
Expand Down
3 changes: 3 additions & 0 deletions tests/cjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "zod-sockets-cjs-test",
"private": true,
"version": "0.0.0",
"scripts": {
"preinstall": "rm -rf node_modules"
},
"dependencies": {
"zod-sockets": "link:../.."
}
Expand Down
10 changes: 3 additions & 7 deletions tests/compat/express-zod-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,15 @@ import { createConfig, createServer } from "express-zod-api";
import { Server } from "socket.io";
import { attachSockets, createSimpleConfig } from "zod-sockets";

const serverConfig = createConfig({
server: { listen: 8090 },
cors: false,
logger: { level: "debug", color: true },
});
const serverConfig = createConfig({ http: { listen: 8090 }, cors: false });

const { httpServer, logger } = await createServer(serverConfig, {});
const { servers, logger } = await createServer(serverConfig, {});

const socketsConfig = createSimpleConfig();

const io = new Server();
await attachSockets({
target: httpServer,
target: servers.pop()!,
config: socketsConfig,
actions: [],
io,
Expand Down
Loading

0 comments on commit ba2736e

Please sign in to comment.