diff --git a/.changeset/friendly-rivers-walk.md b/.changeset/friendly-rivers-walk.md new file mode 100644 index 0000000..3fd8a79 --- /dev/null +++ b/.changeset/friendly-rivers-walk.md @@ -0,0 +1,5 @@ +--- +'graphql-no-alias': major +--- + +Change function signature, make it use a single config object diff --git a/.eslintrc.js b/.eslintrc.js index 18fe29d..6094d53 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -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', diff --git a/README.md b/README.md index c6912a5..607c4a2 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/package.json b/package.json index 7fd32d2..99ead70 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7641980..2a80bea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,6 +13,7 @@ specifiers: 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 @@ -36,6 +37,7 @@ devDependencies: eslint-plugin-jest: 25.3.4_cac5dc51ed5a5c1ae220309c27c6e099 eslint-plugin-prettier: 4.0.0_1c588f61426b1faf18812943f1678311 eslint-plugin-promise: 6.0.0_eslint@8.6.0 + eslint-plugin-tsdoc: 0.2.14 graphql: 16.2.0 husky: 7.0.4 jest: 27.4.5 @@ -1778,6 +1780,19 @@ packages: read-yaml-file: 1.1.0 dev: true + /@microsoft/tsdoc-config/0.15.2: + resolution: {integrity: sha512-mK19b2wJHSdNf8znXSMYVShAHktVr/ib0Ck2FA3lsVBSEhSI/TfXT7DJQkAYgcztTuwazGcg58ZjYdk0hTCVrA==} + dependencies: + '@microsoft/tsdoc': 0.13.2 + ajv: 6.12.6 + jju: 1.4.0 + resolve: 1.19.0 + dev: true + + /@microsoft/tsdoc/0.13.2: + resolution: {integrity: sha512-WrHvO8PDL8wd8T2+zBGKrMwVL5IyzR3ryWUsl0PXgEV0QHup4mTLi0QcATefGI6Gx9Anu7vthPyyyLpY0EpiQg==} + dev: true + /@nodelib/fs.scandir/2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -3290,6 +3305,13 @@ packages: eslint: 8.6.0 dev: true + /eslint-plugin-tsdoc/0.2.14: + resolution: {integrity: sha512-fJ3fnZRsdIoBZgzkQjv8vAj6NeeOoFkTfgosj6mKsFjX70QV256sA/wq+y/R2+OL4L8E79VVaVWrPeZnKNe8Ng==} + dependencies: + '@microsoft/tsdoc': 0.13.2 + '@microsoft/tsdoc-config': 0.15.2 + dev: true + /eslint-scope/5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} @@ -4727,6 +4749,10 @@ packages: - utf-8-validate dev: true + /jju/1.4.0: + resolution: {integrity: sha1-o6vicYryQaKykE+EpiWXDzia4yo=} + dev: true + /js-tokens/4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: true @@ -6098,6 +6124,13 @@ packages: path-parse: 1.0.7 dev: true + /resolve/1.19.0: + resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} + dependencies: + is-core-module: 2.8.0 + path-parse: 1.0.7 + dev: true + /resolve/1.20.0: resolution: {integrity: sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==} dependencies: diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index 38ad3b9..13dc2d9 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -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} diff --git a/src/index.ts b/src/index.ts index 3cea1da..92dc2be 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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,