@toptal/davinci-graphql-codegen 0.1.1-alpha-feature-comm-620-graphql-codegen.1420 → 0.1.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ # @toptal/davinci-graphql-codegen
2
+
3
+ ## 0.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1153](https://github.com/toptal/davinci/pull/1153) [`b51f6179`](https://github.com/toptal/davinci/commit/b51f61791640b552b3d861cfe14fcb3e6ebedb56) Thanks [@alexvcasillas](https://github.com/alexvcasillas)! - Release for GraphQL Codegen
package/README.md CHANGED
@@ -1,73 +1,68 @@
1
- # 🛠 Generating Operation Types
1
+ # GraphQL Codegen
2
2
 
3
- In order to generate operation types for your GraphQL Gateway, you'd need to add this library as a dependency on your app/host/lib and the GraphQL schemas lib dependency too:
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).
4
4
 
5
- ```
6
- yarn workspace @toptal/modularity-template-my-lib add @toptal/modularity-template-codegen@0.0.1 @toptal/modularity-template-graphql@0.0.1 @graphql-typed-document-node/core
7
- ```
5
+ # 🛠 Generating Schema Types
8
6
 
9
- _PS: Note that we specify the package version, otherwise, yarn will throw you an error saying that it cannot find the module._
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>:
10
8
 
11
- Then add this `script` to your `package.json`.
12
-
13
- `libs/my-lib/package.json`
14
- ```
15
- "codegen:operations": "codegen generate:operations"
9
+ ```json
10
+ [
11
+ {
12
+ "schema": "gs://gqlgw-introspection/staging_talent_schema.graphql",
13
+ "target": "talent"
14
+ },
15
+ {
16
+ "schema": "gs://gqlgw-introspection/staging_staff_schema.graphql",
17
+ "target": "staff"
18
+ },
19
+ {
20
+ "schema": "gs://gqlgw-introspection/staging_lens_schema.graphql",
21
+ "target": "lens"
22
+ }
23
+ ]
16
24
  ```
17
25
 
18
- Then create a `codegen.json` file at the root folder of your package that contains the following data/structure:
26
+ The array contains many objects with the following shape:
19
27
 
20
- ```json
28
+ ```ts
21
29
  {
22
- "schema": "@toptal/modularity-template-graphql/talent",
23
- "documents": "src/**/*.gql"
30
+ schema: string
31
+ target: string
24
32
  }
25
33
  ```
26
34
 
27
- This `schema` property in the `codegen.json` file is where this utility is going to go fetch your schema to download it, parse it and then generate the appropriate typescript types for all your GraphQL operations. In this example we're telling the utility to fetch the schema from `@toptal/modularity-tempalte-graphql` which is the dependency that we have just installed and also telling it that the `schema` we would like to use is the `talent` schema. This is because we store our schemas within `lib/graphl` like so:
35
+ 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.
28
36
 
29
37
  ![Captura de pantalla 2021-10-11 a las 11 03 00](https://user-images.githubusercontent.com/9496960/136763291-7ab3f50e-17e0-4fc8-a4b5-965cc15ac0fd.png)
30
38
 
31
- `@toptal/modularity-template-graphql` will internally resolve to `lib/graphql`, this is a more convenient and comfortable way of working with the `lib/graphql` package and won't break implementations.
39
+ _<sup>1</sup> *This structure might be subject to change in a future iteration of this project*_
32
40
 
33
- **ℹ️ Heads-up:** 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.
41
+ After creating the package and applying the default configurations you should add Davinci as a dependency of `@toptal/modularity-template-graphql` (it's how we name this package within our monorepo to resolve to `libs/graphql`) and add this `script` to your `package.json`:
34
42
 
35
- # 🛠 Generating Schema Types
43
+ ```
44
+ "generate-schema": "davinci graphql-codegen generate-schema"
45
+ ```
36
46
 
37
- In order to generate schema types for your GraphQL Gateway, you'd have to go to `lib/graphql` and modify the `codegen.json`. This file contains a structure like the following<sup>1</sup>:
47
+ When you run the above command, it will iterate over the `schemas` you have configured in your `codegen.json` and then create those schemas locally for you to commit to your repo, and then make use of them for generating operation types.
48
+
49
+ # 🛠 Generating Operation Types
50
+
51
+ In order to generate operation types for your GraphQL Gateway, you'd need to add this `script` to your `package.json`.
38
52
 
39
- ```json
40
- [
41
- {
42
- "schema": "https://staging.toptal.net/gateway/graphql/talent/graphql",
43
- "target": "talent"
44
- },
45
- {
46
- "schema": "https://staging.toptal.net/gateway/graphql/gateway/graphql",
47
- "target": "gateway"
48
- },
49
- {
50
- "schema": "https://staging.toptal.net/gateway/graphql/lens/graphql",
51
- "target": "lens"
52
- },
53
- {
54
- "schema": "https://staging.toptal.net/gateway/graphql/chronicles/graphql",
55
- "target": "chronicles"
56
- },
57
- {
58
- "schema": "https://staging.toptal.net/gateway/graphql/staff/graphql",
59
- "target": "staff"
60
- }
61
- ]
53
+ ```
54
+ "generate-operations": "davinci graphql-codegen generate-operations"
62
55
  ```
63
56
 
64
- The array contains many objects with the following shape:
57
+ Then create a `codegen.json` file at the root folder of your package that contains the following data/structure:
65
58
 
66
- ```ts
67
- schema: string;
68
- target: string;
59
+ ```json
60
+ {
61
+ "schema": "@toptal/modularity-template-graphql/talent",
62
+ "documents": "src/**/*.gql"
63
+ }
69
64
  ```
70
65
 
71
- The `schema` property will point to the URL where the schema will be fetched from. The `target` property will indicate where the schema is going to be store. As per the example above, your should name it the same way as your gateway, for instance: the talent gateway would have a target of "talent". Later on, as you have already read on the "Generate Operation Types" section, you'd use this target to retrieve the schemas from like so: `@toptal/modularity-template-graphql/talent`.
66
+ The `schema` property in the `codegen.json` file is where this utility is going to go search for your schema, parse it and then generate the appropriate typescript types for all your GraphQL operations. In this example we're telling the utility to use the schema located at `@toptal/modularity-tempalte-graphql`, which is the package were we will store our schemas. In this example, `@toptal/modularity-template-graphql/talent` will resolve to `libs/graphql/talent`, but it can be any package were you'd like to store your schemas at.
72
67
 
73
- _<sup>1</sup> *This structure might be subject to change in a future iteration of this project*_
68
+ 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.
@@ -9,26 +9,3 @@ cliEngine.loadCommands([
9
9
  codegenGenerateSchemaCreator,
10
10
  codegenGenerateOperationsCreator
11
11
  ])
12
-
13
- cliEngine.help(
14
- () => `
15
- Commands:
16
-
17
- help [command...] Provides help for a given command
18
- exit Exits application
19
- generate:operations generate graphql operation types based off generated schemas
20
- generate:schema generate graphql schemas
21
- `
22
- )
23
-
24
- const args = cliEngine.bootstrap({ use: 'minimist' })
25
-
26
- // eslint-disable-next-line @typescript-eslint/no-shadow
27
- cliEngine.catchErrorCommand((args, cb) => {
28
- cliEngine.execCommand(`${args.commands.join(' ')}`)
29
- cb()
30
- })
31
-
32
- if (args._ && args._.length) {
33
- cliEngine.execCommand(`${args._.join(' ')}`)
34
- }
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@toptal/davinci-graphql-codegen",
3
+ "version": "0.1.1",
4
+ "description": "Codegen",
5
+ "author": "Toptal",
6
+ "license": "ISC",
7
+ "homepage": "https://github.com/toptal/davinci/tree/master/packages/graphql-codegen#readme",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "bin": {
12
+ "davinci-graphql-codegen": "./bin/davinci-graphql-codegen.js"
13
+ },
14
+ "main": "./src/index.js",
15
+ "scripts": {
16
+ "build:package": "../../bin/build-package.js",
17
+ "prepublishOnly": "../../bin/prepublish.js",
18
+ "test": "echo \"Error: no test specified\" && exit 1"
19
+ },
20
+ "sideEffects": false,
21
+ "dependencies": {
22
+ "@google-cloud/storage": "^5.16.1",
23
+ "@toptal/davinci-cli-shared": "^1.5.0",
24
+ "chalk": "^4.1.2",
25
+ "graphql": "^15.7.1",
26
+ "@graphql-codegen/add": "^3.1.0",
27
+ "@graphql-codegen/cli": "^2.2.0",
28
+ "@graphql-codegen/introspection": "^2.1.0",
29
+ "@graphql-codegen/typed-document-node": "^2.1.4",
30
+ "@graphql-codegen/typescript": "^2.2.2",
31
+ "@graphql-codegen/typescript-operations": "^2.1.4",
32
+ "@graphql-codegen/typescript-resolvers": "^2.2.1",
33
+ "@graphql-typed-document-node/core": "^3.1.0"
34
+ }
35
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toptal/davinci-graphql-codegen",
3
- "version": "0.1.1-alpha-feature-comm-620-graphql-codegen.1420+772235c2",
3
+ "version": "0.1.1",
4
4
  "description": "Codegen",
5
5
  "author": "Toptal",
6
6
  "license": "ISC",
@@ -20,6 +20,9 @@
20
20
  "sideEffects": false,
21
21
  "dependencies": {
22
22
  "@google-cloud/storage": "^5.16.1",
23
+ "@toptal/davinci-cli-shared": "^1.5.0",
24
+ "chalk": "^4.1.2",
25
+ "graphql": "^15.7.1",
23
26
  "@graphql-codegen/add": "^3.1.0",
24
27
  "@graphql-codegen/cli": "^2.2.0",
25
28
  "@graphql-codegen/introspection": "^2.1.0",
@@ -27,10 +30,6 @@
27
30
  "@graphql-codegen/typescript": "^2.2.2",
28
31
  "@graphql-codegen/typescript-operations": "^2.1.4",
29
32
  "@graphql-codegen/typescript-resolvers": "^2.2.1",
30
- "@graphql-typed-document-node/core": "^3.1.0",
31
- "@toptal/davinci-cli-shared": "1.5.1-alpha-feature-comm-620-graphql-codegen.83+772235c2",
32
- "chalk": "^4.1.2",
33
- "graphql": "^15.7.1"
34
- },
35
- "gitHead": "772235c2a3e93c6d06cd233dc7c77a532831c83e"
33
+ "@graphql-typed-document-node/core": "^3.1.0"
34
+ }
36
35
  }
@@ -1,16 +1,15 @@
1
1
  const { generateOperations } = require('../generate')
2
2
  const readConfig = require('../read-config')
3
- const processArgs = require('../services/process-args')
3
+ const processArgs = require('../utils/process-args')
4
4
 
5
5
  const args = processArgs(process.argv.slice(2))
6
6
  const operation = args.operation
7
7
 
8
- // eslint-disable-next-line func-style
9
- async function codegenGenerateOperations() {
8
+ const codegenGenerateOperations = async () => {
10
9
  const codegen = await readConfig()
11
10
 
12
11
  switch (operation) {
13
- case 'generate:operations':
12
+ case 'generate-operations':
14
13
  for await (const { schema, documents } of codegen) {
15
14
  await generateOperations({
16
15
  schema,
@@ -24,7 +23,7 @@ async function codegenGenerateOperations() {
24
23
  }
25
24
 
26
25
  const codegenGenerateOperationsCreator = {
27
- command: 'generate:operations',
26
+ command: 'generate-operations',
28
27
  description: 'generate graphql operation types based off generated schemas',
29
28
  action: () => {
30
29
  codegenGenerateOperations()
@@ -1,17 +1,16 @@
1
1
  const { generateSchema } = require('../generate')
2
2
  const readConfig = require('../read-config')
3
- const processArgs = require('../services/process-args')
3
+ const processArgs = require('../utils/process-args')
4
4
 
5
5
  const args = processArgs(process.argv.slice(2))
6
6
  const operation = args.operation
7
7
  const projectId = args.projectId || 'toptal-hub'
8
8
 
9
- // eslint-disable-next-line func-style
10
- async function codegenGenerateSchema() {
9
+ const codegenGenerateSchema = async () => {
11
10
  const codegen = await readConfig()
12
11
 
13
12
  switch (operation) {
14
- case 'generate:schema': {
13
+ case 'generate-schema': {
15
14
  for await (const { schema, documents, target } of codegen) {
16
15
  await generateSchema({
17
16
  schema,
@@ -28,7 +27,7 @@ async function codegenGenerateSchema() {
28
27
  }
29
28
 
30
29
  const codegenGenerateSchemaCreator = {
31
- command: 'generate:schema',
30
+ command: 'generate-schema',
32
31
  description: 'generate graphql schemas',
33
32
  action: () => {
34
33
  codegenGenerateSchema()
@@ -0,0 +1,3 @@
1
+ const config = require('./config')
2
+
3
+ module.exports = config
@@ -3,8 +3,8 @@ const { generate } = require('@graphql-codegen/cli')
3
3
  const {
4
4
  commonOperationTypesConfig,
5
5
  autoGenerationComments
6
- } = require('../shared-config/shared-config')
7
- const getRelativeFilePath = require('../services/get-relative-file-path')
6
+ } = require('../config/config')
7
+ const getRelativeFilePath = require('../utils/get-relative-file-path')
8
8
 
9
9
  const generateOperations = async ({ schema, documents }) => {
10
10
  const docsPath = getRelativeFilePath(documents)
@@ -12,7 +12,10 @@ const generateOperations = async ({ schema, documents }) => {
12
12
  // @toptal/modularity-template-graphql/talent -> talent
13
13
  const target = schema.split('/').pop()
14
14
  // @toptal/modularity-template-graphql/talent -> @toptal/modularity-template-graphql/talent
15
- const schemaPath = schema.split('/').slice(0, 2).join('/')
15
+ const schemaPath = schema
16
+ .split('/')
17
+ .slice(0, 2)
18
+ .join('/')
16
19
 
17
20
  await generate(
18
21
  {
@@ -4,8 +4,9 @@ const chalk = require('chalk')
4
4
  const {
5
5
  commonSchemaTypesConfig,
6
6
  autoGenerationComments
7
- } = require('../shared-config/shared-config')
7
+ } = require('../config/config')
8
8
  const schemaLoader = require('../services/schema-loader')
9
+ const { isSchemaFromHttp } = require('../utils/detect-schema-source')
9
10
 
10
11
  const generateSchema = async ({ schema, target, projectId }) => {
11
12
  const {
@@ -23,7 +24,7 @@ const generateSchema = async ({ schema, target, projectId }) => {
23
24
  // plugins: ['introspection']
24
25
  // },
25
26
  [destinationPathTs]: {
26
- schema: schema.startsWith('https://')
27
+ schema: isSchemaFromHttp(schema)
27
28
  ? schema
28
29
  : require.resolve(schemaPath),
29
30
  plugins: [
@@ -1,7 +1,7 @@
1
1
  const chalk = require('chalk')
2
2
 
3
- const getRelativeFilePath = require('../services/get-relative-file-path')
4
- const toArray = require('../services/to-array')
3
+ const getRelativeFilePath = require('../utils/get-relative-file-path')
4
+ const toArray = require('../utils/to-array')
5
5
 
6
6
  const readConfig = async () => {
7
7
  console.log(`🔍 Searching for ${chalk.bold('codegen.json')} file`)
@@ -1,7 +1,7 @@
1
1
  const { Storage } = require('@google-cloud/storage')
2
2
 
3
- const getRelativeFilePath = require('../services/get-relative-file-path')
4
- const parseGSURI = require('./parse-gs-uri')
3
+ const getRelativeFilePath = require('../utils/get-relative-file-path')
4
+ const parseGSURI = require('../utils/parse-gs-uri')
5
5
 
6
6
  const gsSchemaLoader = async (projectId, source, destination) => {
7
7
  // Creates a Google Storage Client
@@ -1,12 +1,12 @@
1
1
  const { existsSync, copyFileSync } = require('fs')
2
2
 
3
3
  const gsSchemaLoader = require('./gs-schema-loader')
4
- const getRelativeFilePath = require('./get-relative-file-path')
4
+ const getRelativeFilePath = require('../utils/get-relative-file-path')
5
5
  const {
6
6
  isSchemaFromBucket,
7
7
  isLocalSchema,
8
8
  isSchemaFromHttp
9
- } = require('./detect-schema-source')
9
+ } = require('../utils/detect-schema-source')
10
10
 
11
11
  module.exports = async (schema, target, projectId) => {
12
12
  const schemaPath = isSchemaFromHttp(schema)
File without changes
@@ -0,0 +1,29 @@
1
+ const {
2
+ isSchemaFromBucket,
3
+ isSchemaFromHttp,
4
+ isLocalSchema
5
+ } = require('./detect-schema-source')
6
+
7
+ const gsBucketSchema = 'gs://toptal.net/gateway/graphql/talent'
8
+ const httpSchema = 'https://toptal.net/gateway/graphql/talent'
9
+ const localSchema = '../../graphql/talent'
10
+
11
+ describe('Detect Schema Sources', () => {
12
+ it('detects that schema is from GS Bucket', () => {
13
+ expect(isSchemaFromBucket(gsBucketSchema)).toBe(true)
14
+ expect(isSchemaFromHttp(gsBucketSchema)).toBe(false)
15
+ expect(isLocalSchema(gsBucketSchema)).toBe(false)
16
+ })
17
+
18
+ it('detects that schema is from http', () => {
19
+ expect(isSchemaFromBucket(httpSchema)).toBe(false)
20
+ expect(isSchemaFromHttp(httpSchema)).toBe(true)
21
+ expect(isLocalSchema(httpSchema)).toBe(false)
22
+ })
23
+
24
+ it('detects that schema is from local folder', () => {
25
+ expect(isSchemaFromBucket(localSchema)).toBe(false)
26
+ expect(isSchemaFromHttp(localSchema)).toBe(false)
27
+ expect(isLocalSchema(localSchema)).toBe(true)
28
+ })
29
+ })
File without changes
@@ -0,0 +1,12 @@
1
+ const parseGSURI = require('./parse-gs-uri')
2
+
3
+ const bucketURI = 'gs://gqlgw-introspection/staging_talent_schema.graphql'
4
+
5
+ describe('Parse Google Storage Bucket URI', () => {
6
+ it('parses a Google Storage Bucket URI correctly', () => {
7
+ const { bucketName, fileName } = parseGSURI(bucketURI)
8
+
9
+ expect(bucketName).toBe('gqlgw-introspection')
10
+ expect(fileName).toBe('staging_talent_schema.graphql')
11
+ })
12
+ })
@@ -2,20 +2,17 @@ const processArgs = args => {
2
2
  const obj = {}
3
3
 
4
4
  args.forEach(arg => {
5
- if (arg.includes('generate:')) {
5
+ if (arg.includes('generate-')) {
6
6
  obj.operation = arg
7
7
 
8
8
  return
9
9
  }
10
10
 
11
11
  // Eg: Parts -> ['projectId', 'toptal-hub']
12
- const parts = arg
12
+ const [key, value] = arg
13
13
  .split(/(?:--)([a-zA-Z]*)(?:=)([a-zA-Z-]*)/i)
14
14
  .filter(Boolean)
15
15
 
16
- const key = parts[0]
17
- const value = parts[1]
18
-
19
16
  obj[key] = value
20
17
  })
21
18
 
@@ -0,0 +1,10 @@
1
+ const processArgs = require('./process-args')
2
+
3
+ describe('Argument processor', () => {
4
+ it('process arguments correctly', () => {
5
+ const args = processArgs(['generate-operations', '--projectId=toptal'])
6
+
7
+ expect(args.operation).toBe('generate-operations')
8
+ expect(args.projectId).toBe('toptal')
9
+ })
10
+ })
File without changes
@@ -0,0 +1,15 @@
1
+ const toArray = require('./to-array')
2
+
3
+ describe('toArray', () => {
4
+ it("converts a value into an array if it's not one", () => {
5
+ const asArray = toArray('hello')
6
+
7
+ expect(Array.isArray(asArray)).toBe(true)
8
+ })
9
+
10
+ it("returns the array as is if it's an array", () => {
11
+ const asArray = toArray(['hello', 'there'])
12
+
13
+ expect(Array.isArray(asArray)).toBe(true)
14
+ })
15
+ })
@@ -1,3 +0,0 @@
1
- const sharedConfig = require('./shared-config')
2
-
3
- module.exports = sharedConfig