@toptal/davinci-graphql-codegen 4.1.9-alpha-cp-rename-root-libs-in-codeowners-2872dfb9.15 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @toptal/davinci-graphql-codegen
2
2
 
3
+ ## 5.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#2474](https://github.com/toptal/davinci/pull/2474) [`d133536b`](https://github.com/toptal/davinci/commit/d133536be3c7c8c82020e17b58169cd2650f9e75) Thanks [@sashuk](https://github.com/sashuk)!
8
+ - breaking change: the configuration format for `generate-schema` and `generate-operations` is now restricted to the structure described in the README. This change is necessary to ensure that the tool can be used in a consistent manner across all packages. In case of any issues, please rework your configuration or extend the tool to support your use case.
9
+ - breaking change: the `preset` configuration key has been deleted from the `generate-operations` configuration (it is always set to `near-operation-file`). Please delete it to avoid the configuration validation error.
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies [[`74c9bb18`](https://github.com/toptal/davinci/commit/74c9bb1818fee5b314674e308ea3bef3f572c7fe)]:
14
+ - @toptal/davinci-monorepo@9.0.0
15
+
3
16
  ## 4.1.8
4
17
 
5
18
  ### Patch Changes
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # ⚛ GraphQL Codegen
2
2
 
3
- GraphQL Codegen is a library developed by Toptal with the idea in mind of improving DX when generating types for your application. Easy to configure (almost no-config) and extend, and easy to import and use. With this library you'd be able to generate types for all your schemas without worring much about implementation details, and if you need to customize or use a specific plugin to suit your needs, it would be piece of cake just by adding the plugin name to the config (package specific or global).
3
+ GraphQL Codegen is a library developed by Toptal with the idea in mind of improving DX when generating types for your application. Easy to configure (almost no-config) and extend, and easy to import and use. With this library you'd be able to generate types for all your schemas without worrying much about implementation details, and if you need to customize or use a specific plugin to suit your needs, it would be piece of cake just by adding the plugin name to the config (package specific or global).
4
4
 
5
5
  # 🛠 Generating Schema Types
6
6
 
7
- In order to generate schema types for your GraphQL Gateway the reccomended way is that you create a `lib/graphql` package in your monorepo and create a `codegen.json` file were you will store some configuration needed for later usage. This file will contain a structure like the following<sup>1</sup>:
7
+ In order to generate schema types for your GraphQL Gateway the recommended way is that you create a `lib/graphql` package in your monorepo and create a `codegen.json` file were you will store some configuration needed for later usage. This file will contain a structure like the following<sup>1</sup>:
8
8
 
9
9
  ```json
10
10
  [
@@ -26,16 +26,27 @@ In order to generate schema types for your GraphQL Gateway the reccomended way i
26
26
  ]
27
27
  ```
28
28
 
29
- The array contains many objects with the following shape:
29
+ The array contains configuration objects specified below (please note that any other configuration options are prohibited):
30
30
 
31
31
  ```ts
32
32
  {
33
33
  schema: string
34
34
  target: string
35
+ plugins?: Array<any>
36
+ config?: {
37
+ skipTypename?: boolean
38
+ scalars?: Record<string, string>
39
+ }
35
40
  }
36
41
  ```
37
42
 
38
- The `schema` property will point to a protocol (https:// or gs://) or a relative path where the schema will be fetched from. The `target` property will indicate where the schema is going to be stored.
43
+ The `schema` property specifies a protocol (https:// or gs://) or a relative path where the schema will be fetched from.
44
+
45
+ The `target` property indicates where the schema is going to be stored.
46
+
47
+ The `plugins` property is optional. The property contains array of [additional plugins](https://the-guild.dev/graphql/codegen/plugins).
48
+
49
+ The `config.skipTypename` and `config.scalars` properties are optional and affect schema generation [the same way as documented](https://the-guild.dev/graphql/codegen/plugins/typescript/typescript-operations).
39
50
 
40
51
  ![Captura de pantalla 2021-10-11 a las 11 03 00](https://user-images.githubusercontent.com/9496960/136763291-7ab3f50e-17e0-4fc8-a4b5-965cc15ac0fd.png)
41
52
 
@@ -60,9 +71,32 @@ In order to generate operation types for your GraphQL Gateway, you'd need to add
60
71
  Then create a `codegen.json` file at the root folder of your package that contains the following data/structure:
61
72
 
62
73
  ```json
63
- {
74
+ [{
64
75
  "schema": "@toptal/modularity-template-graphql/talent",
65
76
  "documents": "src/**/*.gql"
77
+ }]
78
+ ```
79
+
80
+ The array contains configuration objects specified below (please note that any other configuration options are prohibited):
81
+
82
+ ```ts
83
+ {
84
+ schema: string,
85
+ documents: string,
86
+ plugins?: Array<string | {
87
+ add: { content: string },
88
+ }>,
89
+ config?: {
90
+ documentMode?: string,
91
+ skipTypename?: boolean,
92
+ skipTypeNameForRoot?: boolean,
93
+ avoidOptionals?: boolean,
94
+ dedupeOperationSuffix?: boolean,
95
+ useTypeImports?: boolean,
96
+ inlineFragmentTypes?: string,
97
+ dedupeFragments?: boolean,
98
+ scalars: Record<string, string>,
99
+ },
66
100
  }
67
101
  ```
68
102
 
@@ -70,6 +104,12 @@ The `schema` property in the `codegen.json` file is where this utility is going
70
104
 
71
105
  The `documents` property is a `glob pattern` that tells this utility where your GraphQL operations are located. Please note that this `glob pattern` does not start with `./` as we use `process.env.INIT_CWD` to resolve where this utility was launched from and therefore, using `./src/**/*.gql` will break the implementation and won't be able to resolve your files.
72
106
 
107
+ The `plugins` property is optional. By default, configuration uses `typescript-operations` and `typed-document-node` plugins, and prepends every generated file with `/* eslint-disable */ /* ⚠️ THIS IS AN AUTOGENERATED FILE, DO NOT EDIT ⚠️ */` string (set via `{ add: { content: string } }` configuration).
108
+
109
+ The `config` property is also optional. See corresponding documentation of [typescript-operations](https://the-guild.dev/graphql/codegen/plugins/typescript/typescript-operations) and [typed-document-node](https://the-guild.dev/graphql/codegen/plugins/typescript/typed-document-node) plugins for more information about these options.
110
+
111
+ GraphQL Codegen uses `near-operation-file` preset.
112
+
73
113
  # ⚙️ Customizing GraphQL Codegen
74
114
 
75
115
  GraphQL Codegen is an extensible and configurable tool that gives you the ability to customize many different things to suit your project needs.
@@ -84,26 +124,6 @@ yarn davinci-graphql-codegen generate-schema --config=./graphql/codegen-schema.j
84
124
 
85
125
  The above script will search for `codegen-schema.json` within `./graphql`.
86
126
 
87
- ## Using custom config
88
-
89
- To override default configuration, `preset`, `presetConfig`, `plugins`, and `config` options can be added to `codegen.json`.
90
-
91
- ```json
92
- // codegen.json
93
- [
94
- {
95
- "schema": "@toptal/modularity-template-graphql/talent",
96
- "documents": "src/**/*.gql",
97
- "preset": "...",
98
- "presetConfig": { ... },
99
- "plugins": [ ... ],
100
- "config": { ... }
101
- }
102
- ]
103
- ```
104
-
105
- > Please see the https://the-guild.dev/graphql/codegen/docs/config-reference/codegen-config for more information about these options.
106
-
107
127
  ## Customizing the extension of generated files
108
128
 
109
129
  When generating operations, we have set a default setting that generates your operation types within a file named the same as where your query or mutation is and it will have the `.ts` extension. This is due to that the default extension for your queries or mutations should be `.graphql`. But you might have your query within a `.ts` file that comes with, for instance, a hook that makes use of this query, and if you'd run GraphQL Codegen Operations as is, you'll have that `.ts` file ovewriten. But you can avoid this conflict via CLI with the following command:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toptal/davinci-graphql-codegen",
3
- "version": "4.1.9-alpha-cp-rename-root-libs-in-codeowners-2872dfb9.15+2872dfb9",
3
+ "version": "5.0.0",
4
4
  "description": "Codegen",
5
5
  "author": "Toptal",
6
6
  "license": "SEE LICENSE IN LICENSE.MD",
@@ -35,9 +35,10 @@
35
35
  "@graphql-tools/load": "^8.0.2",
36
36
  "@graphql-tools/schema": "^9.0.19",
37
37
  "@graphql-typed-document-node/core": "^3.2.0",
38
- "@toptal/davinci-cli-shared": "2.5.1-alpha-cp-rename-root-libs-in-codeowners-2872dfb9.55+2872dfb9",
39
- "@toptal/davinci-graphql-codegen-extensions": "1.0.6-alpha-cp-rename-root-libs-in-codeowners-2872dfb9.21+2872dfb9",
40
- "@toptal/davinci-monorepo": "8.5.3-alpha-cp-rename-root-libs-in-codeowners-2872dfb9.1+2872dfb9",
38
+ "@toptal/davinci-cli-shared": "^2.5.0",
39
+ "@toptal/davinci-graphql-codegen-extensions": "1.0.5",
40
+ "@toptal/davinci-monorepo": "^9.0.0",
41
+ "ajv": "8.17.1",
41
42
  "babel-plugin-extract-export": "^0.1.0",
42
43
  "chalk": "^4.1.2",
43
44
  "deepmerge": "^4.2.2",
@@ -58,6 +59,5 @@
58
59
  "publishConfig": {
59
60
  "access": "public"
60
61
  },
61
- "sideEffects": false,
62
- "gitHead": "2872dfb937ff4735bc5ff853a55f44756ff65296"
62
+ "sideEffects": false
63
63
  }
@@ -4,6 +4,7 @@ import { createOption } from '@toptal/davinci-cli-shared'
4
4
  import { generateOperations } from '../generate/index.js'
5
5
  import readConfig from '../read-config/index.js'
6
6
  import { getConfigurationType } from '../services/get-configutation-type.js'
7
+ import { validateGenerateOperationsConfiguration } from '../utils/validate-configuration/index.js'
7
8
 
8
9
  const codegenGenerateOperations = async ({
9
10
  config,
@@ -18,11 +19,11 @@ const codegenGenerateOperations = async ({
18
19
 
19
20
  for (const codegenConfiguration of codegenConfigurations) {
20
21
  if (getConfigurationType(codegenConfiguration) === 'operations') {
22
+ validateGenerateOperationsConfiguration(codegenConfiguration)
23
+
21
24
  const {
22
25
  schema,
23
26
  documents,
24
- preset,
25
- presetConfig,
26
27
  plugins,
27
28
  config: customConfig = {},
28
29
  } = codegenConfiguration
@@ -30,8 +31,6 @@ const codegenGenerateOperations = async ({
30
31
  await generateOperations({
31
32
  schema,
32
33
  documents,
33
- preset,
34
- presetConfig,
35
34
  plugins,
36
35
  extension,
37
36
  experiments,
@@ -3,6 +3,7 @@ import chalk from 'chalk'
3
3
  import { generateSchema } from '../generate/index.js'
4
4
  import readConfig from '../read-config/index.js'
5
5
  import { getConfigurationType } from '../services/get-configutation-type.js'
6
+ import { validateGenerateSchemaConfiguration } from '../utils/validate-configuration/index.js'
6
7
 
7
8
  const codegenGenerateSchema = async ({ projectId, config, verbose }) => {
8
9
  process.env.VERBOSE = verbose
@@ -11,6 +12,8 @@ const codegenGenerateSchema = async ({ projectId, config, verbose }) => {
11
12
 
12
13
  for (const codegenConfiguration of codegenConfigurations) {
13
14
  if (getConfigurationType(codegenConfiguration) === 'schema') {
15
+ validateGenerateSchemaConfiguration(codegenConfiguration)
16
+
14
17
  const {
15
18
  schema,
16
19
  documents,
@@ -19,8 +19,6 @@ const { readFileSync, writeFileSync } = fsExtra
19
19
  const generateOperations = async ({
20
20
  schema,
21
21
  documents,
22
- preset,
23
- presetConfig,
24
22
  plugins,
25
23
  extension,
26
24
  experiments,
@@ -64,8 +62,8 @@ const generateOperations = async ({
64
62
  generates: {
65
63
  [schemaPath]: {
66
64
  schema: schemasPathResoltuions,
67
- preset: preset || 'near-operation-file',
68
- presetConfig: presetConfig || {
65
+ preset: 'near-operation-file',
66
+ presetConfig: {
69
67
  extension,
70
68
  baseTypesPath: `~${primarySchema}/${schemaName}`,
71
69
  },
@@ -55,7 +55,7 @@ const generateSchema = async ({
55
55
  },
56
56
  ...additionalPlugins,
57
57
  ],
58
- config
58
+ config,
59
59
  },
60
60
  },
61
61
  hooks: {
@@ -0,0 +1,7 @@
1
+ import validateGenerateSchemaConfiguration from './validate-generate-schema-configuration.js'
2
+ import validateGenerateOperationsConfiguration from './validate-generate-operations-configuration.js'
3
+
4
+ export {
5
+ validateGenerateSchemaConfiguration,
6
+ validateGenerateOperationsConfiguration,
7
+ }
@@ -0,0 +1,17 @@
1
+ import Ajv from 'ajv'
2
+
3
+ const validateAgainstSchema = (schema, validatedObject) => {
4
+ const ajv = new Ajv({
5
+ allowUnionTypes: true,
6
+ })
7
+
8
+ const validate = ajv.compile(schema)
9
+ const valid = validate(validatedObject)
10
+
11
+ return {
12
+ valid,
13
+ errorsText: ajv.errorsText(validate.errors),
14
+ }
15
+ }
16
+
17
+ export default validateAgainstSchema
@@ -0,0 +1,61 @@
1
+ import validateAgainstSchema from './validate-against-schema.js'
2
+
3
+ const schema = {
4
+ type: 'object',
5
+ properties: {
6
+ schema: { type: ['string', 'array'] },
7
+ documents: { type: ['string', 'array'] },
8
+ plugins: {
9
+ type: 'array',
10
+ items: {
11
+ oneOf: [
12
+ {
13
+ type: 'string',
14
+ },
15
+ {
16
+ type: 'object',
17
+ properties: {
18
+ add: {
19
+ type: 'object',
20
+ properties: {
21
+ content: { type: 'string' },
22
+ },
23
+ required: ['content'],
24
+ },
25
+ },
26
+ required: ['add'],
27
+ },
28
+ ],
29
+ },
30
+ },
31
+ config: {
32
+ type: 'object',
33
+ properties: {
34
+ documentMode: { type: 'string' },
35
+ skipTypename: { type: 'boolean' },
36
+ skipTypeNameForRoot: { type: 'boolean' },
37
+ avoidOptionals: { type: 'boolean' },
38
+ dedupeOperationSuffix: { type: 'boolean' },
39
+ useTypeImports: { type: 'boolean' },
40
+ inlineFragmentTypes: { type: 'string' },
41
+ dedupeFragments: { type: 'boolean' },
42
+ scalars: { type: 'object' },
43
+ },
44
+ additionalProperties: false,
45
+ },
46
+ },
47
+ required: ['schema', 'documents'],
48
+ additionalProperties: false,
49
+ }
50
+
51
+ const validateConfiguration = config => {
52
+ const { valid, errorsText } = validateAgainstSchema(schema, config)
53
+
54
+ if (!valid) {
55
+ throw new Error(
56
+ `Invalid configuration for generate-operations: ${errorsText}`
57
+ )
58
+ }
59
+ }
60
+
61
+ export default validateConfiguration
@@ -0,0 +1,74 @@
1
+ import validateConfiguration from './validate-generate-operations-configuration.js'
2
+
3
+ describe('validate generate-operations configuration', () => {
4
+ describe('when configuration contains unexpected top-level key', () => {
5
+ it('throws an error', () => {
6
+ const config = {
7
+ schema: 'schema.graphql',
8
+ documents: 'documents.graphql',
9
+ config: {},
10
+ unexpectedKey: 'unexpected value',
11
+ }
12
+
13
+ expect(() => {
14
+ validateConfiguration(config)
15
+ }).toThrow(
16
+ 'Invalid configuration for generate-operations: data must NOT have additional properties'
17
+ )
18
+ })
19
+ })
20
+
21
+ describe('when configuration contains unexpected format of plugins object', () => {
22
+ describe('when plugins is not an array', () => {
23
+ it('throws an error', () => {
24
+ const config = {
25
+ schema: 'schema.graphql',
26
+ documents: 'documents.graphql',
27
+ plugins: 'unexpected value',
28
+ }
29
+
30
+ expect(() => {
31
+ validateConfiguration(config)
32
+ }).toThrow(
33
+ 'Invalid configuration for generate-operations: data/plugins must be array'
34
+ )
35
+ })
36
+ })
37
+
38
+ describe('when plugins is an array with unexpected format', () => {
39
+ it('throws an error', () => {
40
+ const config = {
41
+ schema: 'schema.graphql',
42
+ documents: 'documents.graphql',
43
+ config: {},
44
+ plugins: [{ test: 'abc123 ' }],
45
+ }
46
+
47
+ expect(() => {
48
+ validateConfiguration(config)
49
+ }).toThrow(
50
+ "Invalid configuration for generate-operations: data/plugins/0 must be string, data/plugins/0 must have required property 'add', data/plugins/0 must match exactly one schema in oneOf"
51
+ )
52
+ })
53
+ })
54
+ })
55
+
56
+ describe('when configuration contains unexpected config object key', () => {
57
+ it('throws an error', () => {
58
+ const config = {
59
+ schema: 'schema.graphql',
60
+ documents: 'documents.graphql',
61
+ config: {
62
+ skipTypename: true,
63
+ unexpectedKey: 'unexpected value',
64
+ },
65
+ }
66
+
67
+ expect(() => {
68
+ validateConfiguration(config)
69
+ }).toThrow(
70
+ 'Invalid configuration for generate-operations: data/config must NOT have additional properties'
71
+ )
72
+ })
73
+ })
74
+ })
@@ -0,0 +1,44 @@
1
+ import validateAgainstSchema from './validate-against-schema.js'
2
+
3
+ const schema = {
4
+ type: 'object',
5
+ properties: {
6
+ schema: {
7
+ type: 'string',
8
+ },
9
+ target: {
10
+ type: 'string',
11
+ },
12
+ plugins: {
13
+ type: 'array',
14
+ items: {},
15
+ },
16
+ config: {
17
+ type: 'object',
18
+ properties: {
19
+ skipTypename: {
20
+ type: 'boolean',
21
+ },
22
+ scalars: {
23
+ type: 'object',
24
+ additionalProperties: {
25
+ type: 'string',
26
+ },
27
+ },
28
+ },
29
+ additionalProperties: false,
30
+ },
31
+ },
32
+ required: ['schema', 'target'],
33
+ additionalProperties: false,
34
+ }
35
+
36
+ const validateConfiguration = config => {
37
+ const { valid, errorsText } = validateAgainstSchema(schema, config)
38
+
39
+ if (!valid) {
40
+ throw new Error(`Invalid configuration for generate-schema: ${errorsText}`)
41
+ }
42
+ }
43
+
44
+ export default validateConfiguration
@@ -0,0 +1,39 @@
1
+ import validateConfiguration from './validate-generate-schema-configuration.js'
2
+
3
+ describe('validate generate-schema configuration', () => {
4
+ describe('when configuration contains unexpected top-level key', () => {
5
+ it('throws an error', () => {
6
+ const config = {
7
+ schema: 'schema.graphql',
8
+ target: 'typescript',
9
+ config: {},
10
+ unexpectedKey: 'unexpected value',
11
+ }
12
+
13
+ expect(() => {
14
+ validateConfiguration(config)
15
+ }).toThrow(
16
+ 'Invalid configuration for generate-schema: data must NOT have additional properties'
17
+ )
18
+ })
19
+ })
20
+
21
+ describe('when configuration contains unexpected config object key', () => {
22
+ it('throws an error', () => {
23
+ const config = {
24
+ schema: 'schema.graphql',
25
+ target: 'typescript',
26
+ config: {
27
+ skipTypename: true,
28
+ unexpectedKey: 'unexpected value',
29
+ },
30
+ }
31
+
32
+ expect(() => {
33
+ validateConfiguration(config)
34
+ }).toThrow(
35
+ 'Invalid configuration for generate-schema: data/config must NOT have additional properties'
36
+ )
37
+ })
38
+ })
39
+ })