Skip to content

Commit

Permalink
feature: add zod plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
hayes committed Apr 12, 2021
1 parent eed4785 commit 5a77982
Show file tree
Hide file tree
Showing 13 changed files with 782 additions and 25 deletions.
2 changes: 2 additions & 0 deletions configs/eslint.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module.exports = {
plugins: ['prettier'],
rules: {
'class-methods-use-this': 'off',
'no-restricted-syntax': 'off',
Expand All @@ -16,6 +17,7 @@ module.exports = {
ignores: [],
},
],
'prettier/prettier': 'error',
},
overrides: [
{
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@types/node": "^14.14.35",
"@types/node-fetch": "^2.5.8",
"conventional-changelog-beemo": "^2.1.0",
"eslint-plugin-prettier": "^3.3.1",
"graphql": "^15.5.0",
"husky": "^5.1.3",
"lerna": "^4.0.0",
Expand Down
17 changes: 15 additions & 2 deletions packages/core/src/build-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,21 +303,34 @@ export default class BuildCache<Types extends SchemaTypes> {
fields: Record<string, GiraphQLOutputFieldConfig<Types>>,
): GraphQLFieldConfigMap<unknown, object> {
const built: GraphQLFieldConfigMap<unknown, object> = {};

Object.keys(fields).forEach((fieldName) => {
const originalConfig = fields[fieldName];

if (!this.outputFieldConfigs.has(originalConfig)) {
this.outputFieldConfigs.set(
originalConfig,
this.plugin.onOutputFieldConfig(originalConfig),
);
}

const config = this.outputFieldConfigs.get(originalConfig)!;
const config = {
...this.outputFieldConfigs.get(originalConfig)!,
};

const args = this.buildInputFields(config.args);
const argConfigs: { [name: string]: GiraphQLInputFieldConfig<Types> } = {};

Object.keys(config.args).forEach((argName) => {
argConfigs[argName] = this.inputFieldConfigs.get(config.args[argName])!;
});

config.args = argConfigs;

built[fieldName] = {
...config,
type: this.buildOutputTypeParam(config.type),
args: this.buildInputFields(config.args),
args,
extensions: {
...config.extensions,
giraphqlOptions: config.giraphqlOptions,
Expand Down
25 changes: 14 additions & 11 deletions packages/core/src/utils/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import {
SchemaTypes,
} from '..';

interface InputTypeFieldsMapping<Types extends SchemaTypes, T> {
export interface InputTypeFieldsMapping<Types extends SchemaTypes, T> {
configs: Record<string, GiraphQLInputFieldConfig<Types>>;
map: InputFieldsMap<Types, T> | null;
map: InputFieldsMapping<Types, T> | null;
}

type InputFieldMapping<Types extends SchemaTypes, T> =
export type InputFieldMapping<Types extends SchemaTypes, T> =
| {
kind: 'Enum';
isList: boolean;
Expand All @@ -32,7 +32,10 @@ type InputFieldMapping<Types extends SchemaTypes, T> =
value: T;
};

type InputFieldsMap<Types extends SchemaTypes, T> = Map<string, InputFieldMapping<Types, T>>;
export type InputFieldsMapping<Types extends SchemaTypes, T> = Map<
string,
InputFieldMapping<Types, T>
>;

export function resolveInputTypeConfig<Types extends SchemaTypes>(
type: GiraphQLInputFieldType<Types>,
Expand All @@ -55,12 +58,12 @@ export function mapInputFields<Types extends SchemaTypes, T>(
inputs: { [name: string]: GiraphQLInputFieldConfig<Types> },
buildCache: BuildCache<Types>,
mapper: (config: GiraphQLInputFieldConfig<Types>) => T | null,
): InputFieldsMap<Types, T> | null {
const filterMappings = new Map<InputFieldsMap<Types, T>, InputFieldsMap<Types, T>>();
): InputFieldsMapping<Types, T> | null {
const filterMappings = new Map<InputFieldsMapping<Types, T>, InputFieldsMapping<Types, T>>();

return filterMapped(internalMapInputFields(inputs, buildCache, mapper, new Map()));

function filterMapped(map: InputFieldsMap<Types, T>) {
function filterMapped(map: InputFieldsMapping<Types, T>) {
if (filterMappings.has(map)) {
return filterMappings.get(map)!;
}
Expand Down Expand Up @@ -96,8 +99,8 @@ export function mapInputFields<Types extends SchemaTypes, T>(
}

function checkForMappings(
map: InputFieldsMap<Types, T>,
hasMappings = new Map<InputFieldsMap<Types, T>, boolean>(),
map: InputFieldsMapping<Types, T>,
hasMappings = new Map<InputFieldsMapping<Types, T>, boolean>(),
): boolean {
if (hasMappings.has(map)) {
return hasMappings.get(map)!;
Expand Down Expand Up @@ -179,10 +182,10 @@ function internalMapInputFields<Types extends SchemaTypes, T>(
}

export function createInputValueMapper<Types extends SchemaTypes, T>(
argMap: InputFieldsMap<Types, T>,
argMap: InputFieldsMapping<Types, T>,
mapValue: (val: unknown, mapping: InputFieldMapping<Types, T>) => unknown,
) {
return function mapObject(obj: object, map: InputFieldsMap<Types, T> = argMap) {
return function mapObject(obj: object, map: InputFieldsMapping<Types, T> = argMap) {
const mapped: Record<string, unknown> = { ...obj };

map.forEach((field, fieldName) => {
Expand Down
33 changes: 33 additions & 0 deletions packages/plugin-validation/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "@giraphql/plugin-validation",
"version": "1.0.0",
"description": "A GiraphQL plugin for adding argument validation",
"main": "lib/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Michael Hayes",
"license": "ISC",
"keywords": [
"giraphql",
"graphql",
"schema",
"typescript",
"zod",
"validation",
"validate"
],
"publishConfig": {
"access": "public"
},
"peerDependencies": {
"@giraphql/core": "^0.20.3",
"graphql": ">=15.1.0",
"zod": "^1.11.11"
},
"devDependencies": {
"apollo-server": "^2.21.2",
"graphql-tag": "^2.11.0",
"zod": "^1.11.11"
}
}
41 changes: 41 additions & 0 deletions packages/plugin-validation/src/global-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import {
FieldNullability,
FieldRequiredness,
InputFieldMap,
InputShapeFromFields,
InputShapeFromTypeParam,
InputType,
SchemaTypes,
TypeParam,
} from '@giraphql/core';
import { ValidationOptions } from './types';
import { GiraphQLValidationPlugin } from '.';

declare global {
export namespace GiraphQLSchemaTypes {
export interface Plugins<Types extends SchemaTypes> {
validation: GiraphQLValidationPlugin<Types>;
}

export interface FieldOptions<
Types extends SchemaTypes,
ParentShape,
Type extends TypeParam<Types>,
Nullable extends FieldNullability<Type>,
Args extends InputFieldMap,
ResolveShape,
ResolveReturnShape
> {
validate?: ValidationOptions<InputShapeFromFields<Args>>;
}

export interface InputFieldOptions<
Types extends SchemaTypes = SchemaTypes,
Type extends InputType<Types> | [InputType<Types>] = InputType<Types> | [InputType<Types>],
Req extends FieldRequiredness<Type> = FieldRequiredness<Type>
> {
validate?: ValidationOptions<InputShapeFromTypeParam<Types, Type, true>>;
}
}
}

0 comments on commit 5a77982

Please sign in to comment.