Skip to content

Commit

Permalink
Showing 7 changed files with 99 additions and 53 deletions.
5 changes: 5 additions & 0 deletions .changeset/friendly-rivers-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'graphql-no-alias': major
---

Change function signature, make it use a single config object
7 changes: 6 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -5,7 +5,11 @@ module.exports = {
node: true,
jest: true
},
plugins: ['@typescript-eslint/eslint-plugin', 'prettier'],
plugins: [
'eslint-plugin-tsdoc',
'@typescript-eslint/eslint-plugin',
'prettier'
],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
@@ -17,6 +21,7 @@ module.exports = {
sourceType: 'module'
},
rules: {
'tsdoc/syntax': 'warn',
'@typescript-eslint/no-unused-vars': ['off', { argsIgnorePattern: '^_' }],
'generator-star-spacing': ['error', { before: false, after: true }],
'space-before-function-paren': 'off',
23 changes: 9 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -162,18 +162,13 @@ The declaration can be customized to have a different name, different default `a
In the next example, `validation` will allow `3` calls to the same field by default, the directive name will be changed to `NoBatchCalls`, and there will be a custom error message.

```ts
const { typeDefs, validation } = createValidation(3,'NoBatchCalls',(
typeName: string,
fieldName: string,
maxAllowed: number,
node: FieldNode,
ctx: ValidationContext
): GraphQLError {
return new GraphQLError(
`Hey! allowed number of calls for ${typeName}->${fieldName} has been exceeded (max: ${maxAllowed})`
)
}
)
const defaultAllow = 3
const directiveName = 'NoBatchCalls'
const { typeDefs, validation } = createValidation({
defaultAllow,
directiveName
})
```

Usage:
@@ -192,7 +187,7 @@ const schema = buildSchema(`
Continuing from the previous example, the `error` message that is reported when the validation fails can also be customized. You can return a complete `GrahphQLError` or just a `string` that will be used as a message.

```ts
const { typeDefs, validation } = createValidation(3,'NoBatchCalls',(
const { typeDefs, validation } = createValidation({errorFn:(
typeName: string, //type name Query or Mutation
fieldName: string,
maxAllowed: number,
@@ -205,7 +200,7 @@ const { typeDefs, validation } = createValidation(3,'NoBatchCalls',(
//or
return 'just the message'
}
)
})
```

### License
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -62,6 +62,7 @@
"eslint-plugin-jest": "^25.3.4",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-tsdoc": "^0.2.14",
"graphql": "^16.2.0",
"husky": "^7.0.4",
"jest": "^27.4.5",
33 changes: 33 additions & 0 deletions pnpm-lock.yaml

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

36 changes: 17 additions & 19 deletions src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -106,8 +106,8 @@ describe('Directive on type field', () => {
})

test('Set default custom maximum allowed when creating the validation', () => {
const allow = 3
const { validation, typeDefs } = createValidation(allow)
const defaultAllow = 3
const { validation, typeDefs } = createValidation({ defaultAllow })

const schema = buildSchema(/* GraphQL */ `
${typeDefs}
@@ -142,15 +142,18 @@ describe('Directive on type field', () => {

expect(errors).toHaveLength(1)
expect(errors[0].message).toMatch(
new RegExp(`Allowed number of calls.+${allow}`, 'i')
new RegExp(`Allowed number of calls.+${defaultAllow}`, 'i')
)
})

test('Set custom directive name', () => {
const allow = 3
const defaultAllow = 3
const directiveName = 'customDirectiveName'

const { validation, typeDefs } = createValidation(allow, directiveName)
const { validation, typeDefs } = createValidation({
defaultAllow,
directiveName
})

const schema = buildSchema(/* GraphQL */ `
${typeDefs}
@@ -185,15 +188,18 @@ describe('Directive on type field', () => {

expect(errors).toHaveLength(1)
expect(errors[0].message).toMatch(
new RegExp(`Allowed number of calls.+${allow}`, 'i')
new RegExp(`Allowed number of calls.+${defaultAllow}`, 'i')
)
})

test('Report one error per field', () => {
const allow = 3
const defaultAllow = 3
const directiveName = 'customDirectiveName'

const { validation, typeDefs } = createValidation(allow, directiveName)
const { validation, typeDefs } = createValidation({
defaultAllow,
directiveName
})

const schema = buildSchema(/* GraphQL */ `
${typeDefs}
@@ -236,7 +242,7 @@ describe('Directive on type field', () => {

expect(errors).toHaveLength(1)
expect(errors[0].message).toMatch(
new RegExp(`Allowed number of calls.+${allow}`, 'i')
new RegExp(`Allowed number of calls.+${defaultAllow}`, 'i')
)
})

@@ -247,11 +253,7 @@ describe('Directive on type field', () => {

const errorFn = jest.fn().mockReturnValue(new GraphQLError(errorMessage))

const { validation, typeDefs } = createValidation(
undefined,
undefined,
errorFn
)
const { validation, typeDefs } = createValidation({ errorFn })

const schema = buildSchema(/* GraphQL */ `
${typeDefs}
@@ -287,11 +289,7 @@ describe('Directive on type field', () => {

const errorFn = jest.fn().mockReturnValue(errorMessage)

const { validation, typeDefs } = createValidation(
undefined,
undefined,
errorFn
)
const { validation, typeDefs } = createValidation({ errorFn })

const schema = buildSchema(/* GraphQL */ `
${typeDefs}
47 changes: 28 additions & 19 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -12,19 +12,34 @@ import {
export type ErrorFn = typeof createErrorMsg

/**
* Creates validation object with needed type declarations and validation function
* @param [defaultAllow] - how many aliases to allow by default
* @param [directiveName] - direactive name to use
* @param [errorFn] - function that will return GraphQLError when the validation fails
* Configuration object for the createValidation function
*/
export default function createValidation(
defaultAllow = 1,
directiveName = 'noAlias',
errorFn?: typeof createErrorMsg
): {
export type Config = {
/** How many aliases (calls) to allow by default */
defaultAllow?: number
/** directive name to use*/
directiveName?: string
/** function that should return a graphql erorr or string when the validation fails*/
errorFn?: ErrorFn
}
/**
* Creates validation
* @param config - {@link Config}
* @returns validation
*/
export default function createValidation(config?: Config): {
typeDefs: string
validation: (context: ValidationContext) => ASTVisitor
} {
const { directiveName, defaultAllow, errorFn } = {
...{
defaultAllow: 1,
directiveName: 'noAlias',
errorFn: createErrorMsg
},
...(config || {})
}

return {
typeDefs: `directive @${directiveName}(allow: Int = ${defaultAllow}) on OBJECT | FIELD_DEFINITION`,
validation(context: ValidationContext): ASTVisitor {
@@ -34,7 +49,7 @@ export default function createValidation(
context,
directiveName,
defaultAllow,
errorFn ? errorFn : createErrorMsg
errorFn
)
}
}
@@ -71,12 +86,6 @@ function createFieldValidation(

/**
* Checks if allowed alias count has been exceeded
* @param ctx
* @param node
* @param maxAllowedData
* @param currentCountData
* @param errorFn
* @param errorMap
*/
function checkCount(
ctx: ValidationContext,
@@ -176,9 +185,9 @@ function processDirective(

/**
* Creates custom GraphQLError instance
* @param typeName Object type name
* @param fieldName Object field name
* @param maxAllowed max allowed count that has been reached
* @param typeName - Object type name
* @param fieldName - Object field name
* @param maxAllowed - max allowed count that has been reached
*/
function createErrorMsg(
typeName: string,

0 comments on commit fccb773

Please sign in to comment.