Skip to content

Commit

Permalink
Switch to biome + fix build (#116)
Browse files Browse the repository at this point in the history
  • Loading branch information
kibertoad authored Sep 29, 2024
1 parent 6f7ebed commit de960ba
Show file tree
Hide file tree
Showing 12 changed files with 380 additions and 344 deletions.
27 changes: 27 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"extends": ["./node_modules/@kibertoad/biome-config/configs/biome-package.json"],
"overrides": [
{
"include": ["**/*.ts"],
"linter": {
"rules": {
"performance": {
"noBarrelFile": "off",
"noDelete": "off"
},
"correctness": {
"noUnusedVariables": "off"
},
"complexity": {
"noExcessiveCognitiveComplexity": "off",
"useOptionalChain": "off"
},
"suspicious": {
"noExplicitAny": "off"
}
}
}
}
]
}
5 changes: 3 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ export {
serializerCompiler,
validatorCompiler,
createSerializerCompiler,
} from './src/core';
} from './src/core'

export {
type ZodFastifySchemaValidationError,
ResponseSerializationError,
InvalidSchemaError,
hasZodFastifySchemaValidationErrors,
} from './src/errors';
isResponseSerializationError,
} from './src/errors'
24 changes: 6 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@
"description": "Zod Type Provider for Fastify@5",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"README.md",
"LICENSE",
"dist"
],
"files": ["README.md", "LICENSE", "dist"],
"scripts": {
"build": "tsc",
"test": "npm run build && npm run typescript && vitest",
"test:coverage": "vitest --coverage",
"lint": "eslint .",
"lint:fix": "eslint --fix . && prettier --write .",
"lint": "biome check . && tsc --project tsconfig.lint.json --noEmit",
"lint:fix": "biome check --write .",
"typescript": "tsd",
"prepublishOnly": "npm run build"
},
Expand All @@ -25,12 +21,7 @@
"repository": {
"url": "https://github.com/turkerdev/fastify-type-provider-zod"
},
"keywords": [
"fastify",
"zod",
"type",
"provider"
],
"keywords": ["fastify", "zod", "type", "provider"],
"author": "turkerd",
"license": "MIT",
"bugs": {
Expand All @@ -41,19 +32,16 @@
"zod-to-json-schema": "^3.23.3"
},
"devDependencies": {
"@biomejs/biome": "^1.9.2",
"@fastify/swagger": "^9.0.0",
"@fastify/swagger-ui": "^5.0.1",
"@kibertoad/biome-config": "^1.2.1",
"@types/node": "^20.12.12",
"@typescript-eslint/eslint-plugin": "^7.9.0",
"@typescript-eslint/parser": "^7.9.0",
"@vitest/coverage-v8": "^2.1.1",
"eslint": "^8.57.0",
"eslint-plugin-import": "^2.29.1",
"fastify": "^5.0.0",
"fastify-plugin": "^5.0.1",
"oas-validator": "^5.0.8",
"openapi-types": "^12.1.3",
"prettier": "^3.2.5",
"tsd": "^0.31.0",
"typescript": "^5.4.5",
"vitest": "^2.1.1",
Expand Down
104 changes: 52 additions & 52 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import type {
FastifyTypeProvider,
RawServerBase,
RawServerDefault,
} from 'fastify';
import type { FastifySerializerCompiler } from 'fastify/types/schema';
import type { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';
import type { z } from 'zod';
} from 'fastify'
import type { FastifySerializerCompiler } from 'fastify/types/schema'
import type { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types'
import type { z } from 'zod'

import { createValidationError, InvalidSchemaError, ResponseSerializationError } from './errors';
import { resolveRefs } from './ref';
import { convertZodToJsonSchema } from './zod-to-json';
import { InvalidSchemaError, ResponseSerializationError, createValidationError } from './errors'
import { resolveRefs } from './ref'
import { convertZodToJsonSchema } from './zod-to-json'

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type FreeformRecord = Record<string, any>;
type FreeformRecord = Record<string, any>

const defaultSkipList = [
'/documentation/',
Expand All @@ -27,15 +27,15 @@ const defaultSkipList = [
'/documentation/yaml',
'/documentation/*',
'/documentation/static/*',
];
]

export interface ZodTypeProvider extends FastifyTypeProvider {
validator: this['schema'] extends z.ZodTypeAny ? z.output<this['schema']> : unknown;
serializer: this['schema'] extends z.ZodTypeAny ? z.input<this['schema']> : unknown;
validator: this['schema'] extends z.ZodTypeAny ? z.output<this['schema']> : unknown
serializer: this['schema'] extends z.ZodTypeAny ? z.input<this['schema']> : unknown
}

interface Schema extends FastifySchema {
hide?: boolean;
hide?: boolean
}

export const createJsonSchemaTransform = ({ skipList }: { skipList: readonly string[] }) => {
Expand All @@ -44,54 +44,54 @@ export const createJsonSchemaTransform = ({ skipList }: { skipList: readonly str
return {
schema,
url,
};
}
}

const { response, headers, querystring, body, params, hide, ...rest } = schema;
const { response, headers, querystring, body, params, hide, ...rest } = schema

const transformed: FreeformRecord = {};
const transformed: FreeformRecord = {}

if (skipList.includes(url) || hide) {
transformed.hide = true;
return { schema: transformed, url };
transformed.hide = true
return { schema: transformed, url }
}

const zodSchemas: FreeformRecord = { headers, querystring, body, params };
const zodSchemas: FreeformRecord = { headers, querystring, body, params }

for (const prop in zodSchemas) {
const zodSchema = zodSchemas[prop];
const zodSchema = zodSchemas[prop]
if (zodSchema) {
transformed[prop] = convertZodToJsonSchema(zodSchema);
transformed[prop] = convertZodToJsonSchema(zodSchema)
}
}

if (response) {
transformed.response = {};
transformed.response = {}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
for (const prop in response as any) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const schema = resolveSchema((response as any)[prop]);
const schema = resolveSchema((response as any)[prop])

const transformedResponse = convertZodToJsonSchema(schema);
transformed.response[prop] = transformedResponse;
const transformedResponse = convertZodToJsonSchema(schema)
transformed.response[prop] = transformedResponse
}
}

for (const prop in rest) {
const meta = rest[prop as keyof typeof rest];
const meta = rest[prop as keyof typeof rest]
if (meta) {
transformed[prop] = meta;
transformed[prop] = meta
}
}

return { schema: transformed, url };
};
};
return { schema: transformed, url }
}
}

export const jsonSchemaTransform = createJsonSchemaTransform({
skipList: defaultSkipList,
});
})

export const createJsonSchemaTransformObject =
({ schemas }: { schemas: Record<string, z.ZodTypeAny> }) =>
Expand All @@ -101,58 +101,58 @@ export const createJsonSchemaTransformObject =
| { openapiObject: Partial<OpenAPIV3.Document | OpenAPIV3_1.Document> },
) => {
if ('swaggerObject' in input) {
console.warn('This package currently does not support component references for Swagger 2.0');
return input.swaggerObject;
console.warn('This package currently does not support component references for Swagger 2.0')
return input.swaggerObject
}

return resolveRefs(input.openapiObject, schemas);
};
return resolveRefs(input.openapiObject, schemas)
}

export const validatorCompiler: FastifySchemaCompiler<z.ZodTypeAny> =
({ schema }) =>
(data) => {
const result = schema.safeParse(data);
const result = schema.safeParse(data)
if (result.error) {
return { error: createValidationError(result.error) as unknown as Error };
return { error: createValidationError(result.error) as unknown as Error }
}

return { value: result.data };
};
return { value: result.data }
}

function resolveSchema(maybeSchema: z.ZodTypeAny | { properties: z.ZodTypeAny }): z.ZodTypeAny {
if ('safeParse' in maybeSchema) {
return maybeSchema;
return maybeSchema
}
if ('properties' in maybeSchema) {
return maybeSchema.properties;
return maybeSchema.properties
}
throw new InvalidSchemaError(JSON.stringify(maybeSchema));
throw new InvalidSchemaError(JSON.stringify(maybeSchema))
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type ReplacerFunction = (this: any, key: string, value: any) => any;
type ReplacerFunction = (this: any, key: string, value: any) => any

export type ZodSerializerCompilerOptions = {
replacer?: ReplacerFunction;
};
replacer?: ReplacerFunction
}

export const createSerializerCompiler =
(
options?: ZodSerializerCompilerOptions,
): FastifySerializerCompiler<z.ZodTypeAny | { properties: z.ZodTypeAny }> =>
({ schema: maybeSchema, method, url }) =>
(data) => {
const schema = resolveSchema(maybeSchema);
const schema = resolveSchema(maybeSchema)

const result = schema.safeParse(data);
const result = schema.safeParse(data)
if (result.error) {
throw new ResponseSerializationError(method, url, { cause: result.error });
throw new ResponseSerializationError(method, url, { cause: result.error })
}

return JSON.stringify(result.data, options?.replacer);
};
return JSON.stringify(result.data, options?.replacer)
}

export const serializerCompiler = createSerializerCompiler({});
export const serializerCompiler = createSerializerCompiler({})

/**
* FastifyPluginCallbackZod with Zod automatic type inference
Expand All @@ -169,7 +169,7 @@ export const serializerCompiler = createSerializerCompiler({});
export type FastifyPluginCallbackZod<
Options extends FastifyPluginOptions = Record<never, never>,
Server extends RawServerBase = RawServerDefault,
> = FastifyPluginCallback<Options, Server, ZodTypeProvider>;
> = FastifyPluginCallback<Options, Server, ZodTypeProvider>

/**
* FastifyPluginAsyncZod with Zod automatic type inference
Expand All @@ -185,4 +185,4 @@ export type FastifyPluginCallbackZod<
export type FastifyPluginAsyncZod<
Options extends FastifyPluginOptions = Record<never, never>,
Server extends RawServerBase = RawServerDefault,
> = FastifyPluginAsync<Options, Server, ZodTypeProvider>;
> = FastifyPluginAsync<Options, Server, ZodTypeProvider>
40 changes: 23 additions & 17 deletions src/errors.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,52 @@
import createError from '@fastify/error';
import type { FastifyError } from 'fastify';
import type { ZodError, ZodIssue, ZodIssueCode } from 'zod';
import createError from '@fastify/error'
import type { FastifyError } from 'fastify'
import type { ZodError, ZodIssue, ZodIssueCode } from 'zod'

export class ResponseSerializationError extends createError<[{ cause: ZodError }]>(
'FST_ERR_RESPONSE_SERIALIZATION',
"Response doesn't match the schema",
500,
) {
cause!: ZodError

constructor(
public method: string,
public url: string,
options: { cause: ZodError },
) {
super({ cause: options.cause });
super({ cause: options.cause })
}
}

export function isResponseSerializationError(value: unknown): value is ResponseSerializationError {
return 'method' in (value as ResponseSerializationError)
}

export const InvalidSchemaError = createError<[string]>(
'FST_ERR_INVALID_SCHEMA',
'Invalid schema passed: %s',
500,
);
)

export type ZodFastifySchemaValidationError = {
name: 'ZodFastifySchemaValidationError';
keyword: ZodIssueCode;
instancePath: string;
schemaPath: string;
name: 'ZodFastifySchemaValidationError'
keyword: ZodIssueCode
instancePath: string
schemaPath: string
params: {
issue: ZodIssue;
zodError: ZodError;
};
message: string;
};
issue: ZodIssue
zodError: ZodError
}
message: string
}

const isZodFastifySchemaValidationError = (
error: unknown,
): error is ZodFastifySchemaValidationError =>
typeof error === 'object' &&
error !== null &&
'name' in error &&
error.name === 'ZodFastifySchemaValidationError';
error.name === 'ZodFastifySchemaValidationError'

export const hasZodFastifySchemaValidationErrors = (
error: unknown,
Expand All @@ -50,7 +56,7 @@ export const hasZodFastifySchemaValidationErrors = (
'validation' in error &&
Array.isArray(error.validation) &&
error.validation.length > 0 &&
isZodFastifySchemaValidationError(error.validation[0]);
isZodFastifySchemaValidationError(error.validation[0])

export const createValidationError = (error: ZodError): ZodFastifySchemaValidationError[] =>
error.errors.map((issue) => ({
Expand All @@ -63,4 +69,4 @@ export const createValidationError = (error: ZodError): ZodFastifySchemaValidati
zodError: error,
},
message: issue.message,
}));
}))
Loading

0 comments on commit de960ba

Please sign in to comment.