├── gql-codegen-cover.png ├── .prettierrc ├── .vscodeignore ├── .vscode ├── extensions.json ├── settings.json ├── tasks.json └── launch.json ├── .eslintrc ├── .github └── workflows │ └── main.yml ├── tsconfig.json ├── LICENSE ├── .gitignore ├── vsc-extension-quickstart.md ├── README.md ├── package.json └── src └── extension.ts /gql-codegen-cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capaj/graphql-codegen-vscode/HEAD/gql-codegen-cover.png -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "singleQuote": true, 4 | "semi": false, 5 | "trailingComma": "none" 6 | } 7 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/** 4 | src/** 5 | .gitignore 6 | .yarnrc 7 | vsc-extension-quickstart.md 8 | **/tsconfig.json 9 | **/.eslintrc.json 10 | **/*.map 11 | **/*.ts 12 | node_modules/** -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": ["dbaeumer.vscode-eslint", "eamodio.tsl-problem-matcher"] 5 | } 6 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": ["@typescript-eslint"], 5 | "extends": [ 6 | "eslint:recommended", 7 | "plugin:@typescript-eslint/eslint-recommended", 8 | "plugin:@typescript-eslint/recommended" 9 | ], 10 | "rules": { 11 | "@typescript-eslint/ban-ts-comment": "off" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | workflow_dispatch: 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - uses: actions/setup-node@v2 18 | with: 19 | node-version: '18' 20 | cache: 'npm' 21 | - run: npm ci 22 | - run: npm run tsc 23 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off", 11 | "cSpell.words": ["Codegen", "clonedeep", "codegens", "multimatch"], 12 | "typescript.tsdk": "node_modules/typescript/lib" 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "dist", 6 | "lib": ["es6"], 7 | "sourceMap": true, 8 | "rootDir": "src", 9 | "esModuleInterop": true, 10 | "strict": true /* enable all strict type-checking options */, 11 | "useUnknownInCatchVariables": false 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | }, 17 | "exclude": ["node_modules", ".vscode-test"] 18 | } 19 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": ["$ts-webpack-watch", "$tslint-webpack-watch"], 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | }, 19 | { 20 | "type": "npm", 21 | "script": "test-watch", 22 | "problemMatcher": "$tsc-watch", 23 | "isBackground": true, 24 | "presentation": { 25 | "reveal": "never" 26 | }, 27 | "group": "build" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": ["--extensionDevelopmentPath=${workspaceFolder}"], 13 | "outFiles": ["${workspaceFolder}/dist/**/*.js"], 14 | "preLaunchTask": "npm: build" 15 | }, 16 | { 17 | "name": "Extension Tests", 18 | "type": "extensionHost", 19 | "request": "launch", 20 | "args": [ 21 | "--verbose", 22 | "--extensionDevelopmentPath=${workspaceFolder}", 23 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 24 | ], 25 | "outFiles": ["${workspaceFolder}/out/test/**/*.js"], 26 | "preLaunchTask": "npm: test-watch" 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jiri Spac 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | out 106 | dist 107 | node_modules 108 | .vscode-test/ 109 | *.vsix 110 | -------------------------------------------------------------------------------- /vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | - This folder contains all of the files necessary for your extension. 6 | - `package.json` - this is the manifest file in which you declare your extension and command. 7 | - The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 8 | - `src/extension.ts` - this is the main file where you will provide the implementation of your command. 9 | - The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 10 | - We pass the function containing the implementation of the command as the second parameter to `registerCommand`. 11 | 12 | ## Get up and running straight away 13 | 14 | - Press `F5` to open a new window with your extension loaded. 15 | - Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. 16 | - Set breakpoints in your code inside `src/extension.ts` to debug your extension. 17 | - Find output from your extension in the debug console. 18 | 19 | ## Make changes 20 | 21 | - You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`. 22 | - You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 23 | 24 | ## Explore the API 25 | 26 | - You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. 27 | 28 | ## Run tests 29 | 30 | - Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`. 31 | - Press `F5` to run the tests in a new window with your extension loaded. 32 | - See the output of the test result in the debug console. 33 | - Make changes to `src/test/suite/extension.test.ts` or create new test files inside the `test/suite` folder. 34 | - The provided test runner will only consider files matching the name pattern `**.test.ts`. 35 | - You can create folders inside the `test` folder to structure your tests any way you want. 36 | 37 | ## Go further 38 | 39 | - Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension). 40 | - [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace. 41 | - Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration). 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Created by The guild 4 | 5 | 6 | 7 | # graphql-codegen-vscode 8 | 9 | Runs [@graphql-codegen](https://github.com/dotansimha/graphql-code-generator) generation as soon as you hit save on any `gql` or `graphql` file. 10 | Keep in mind it will only run when your node_modules contains `@graphql-codegen/cli` package. 11 | 12 | ## Extension config 13 | 14 | - `"graphql-codegen.fileExtensionsDeclaringGraphQLDocuments"`: change which file extensions are watched for saves. Defaults to `graphql` and `gql`. If you just use these files to define your mutations you don't need to configure anything. 15 | - `"graphql-codegen.filePathToWatch"`: allow users to specify a multimatch patters that file paths should match before running codegen. This is important as users could specify a more broad file (eg `ts`) that could exist in both paths relevant to graphql generation and paths that are not. Defaults to `null`, so watches everything. 16 | - `"graphql-codegen.configFilePath"`: allow users to specify a path to the codegen configuration file. Defaults to `codegen.yml`. 17 | 18 | ### How is it different than VilvaAthibanPB.graphql-codegen 19 | 20 | This extension uses codegen from your node_modules inside the folder you are working on, so you will never get a mismatching output to what your CLI would give you. Also it is faster-especially on large projects. VilvaAthibanPB's always executes all of the codegens. 21 | This extensions only executes codegens that match the last saved file. 22 | 23 | ### OS support 24 | 25 | Should support all major OSes. 26 | 27 | ### Contributing 28 | 29 | Testing is done manually until some basic specs are added. 30 | 31 | ## CLI Version support 32 | 33 | Extension was initially tested with @graphql-codegen/cli version 1.21.x. Last version is tested with version 5.0.0 34 | Other versions might not work as expected. If you hit any problems with other versions, please report them. The aim is to support as broad range of CLI versions as possible. 35 | 36 | ## FAQ 37 | 38 | ### Command output 39 | 40 | Since this runs the codegen behind the scenes you cannot see the output. You get notified of success/error with a vscode information message like this: 41 | 42 | ![image](https://user-images.githubusercontent.com/1305378/127301219-830602e3-b77b-4723-a69a-45e73121c334.png) 43 | 44 | ### Multiple workspaces support 45 | 46 | You can have multiple workspaces in your editor, but keep in mind that we always iterate from the first to last and we run codegen inside the first workspace which has `/node_modules/@graphql-codegen/cli` module available. 47 | If you have multiple VSCode workspaces with this module, it might not work correctly. 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphql-codegen-vscode", 3 | "displayName": "graphql-codegen", 4 | "publisher": "capaj", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/capaj/graphql-codegen-vscode.git" 8 | }, 9 | "description": "integrates graphql-codegen into vscode, running it every time your query/mutation is saved", 10 | "icon": "gql-codegen-cover.png", 11 | "version": "1.1.4", 12 | "engines": { 13 | "vscode": "^1.94.0" 14 | }, 15 | "categories": [ 16 | "Other" 17 | ], 18 | "main": "./dist/graphql-codegen-vscode.js", 19 | "activationEvents": [ 20 | "onLanguage:graphql", 21 | "onLanguage:GraphQL", 22 | "workspaceContains:package.json" 23 | ], 24 | "contributes": { 25 | "commands": [ 26 | { 27 | "command": "graphql-codegen.generateGqlCodegen", 28 | "title": "Generate GQL codegen" 29 | } 30 | ], 31 | "configuration": { 32 | "title": "GraphQL Codegen", 33 | "properties": { 34 | "graphql-codegen.fileExtensionsDeclaringGraphQLDocuments": { 35 | "type": "array", 36 | "items": { 37 | "type": "string" 38 | }, 39 | "default": [ 40 | "graphql", 41 | "gql" 42 | ], 43 | "description": "GraphQL Codegen will automatically re-run codegen when files matching these file extensions are saved." 44 | }, 45 | "graphql-codegen.filePathToWatch": { 46 | "type": [ 47 | "string", 48 | "null" 49 | ], 50 | "default": null, 51 | "markdownDescription": "If specified, GraphQL Codegen will only re-run codegen if the files match the specified glob path. Uses [minimatch](https://github.com/isaacs/minimatch) glob syntax." 52 | }, 53 | "graphql-codegen.configFilePath": { 54 | "type": [ 55 | "string", 56 | "null" 57 | ], 58 | "default": null, 59 | "markdownDescription": "Path to the codegen configuration file" 60 | } 61 | } 62 | } 63 | }, 64 | "scripts": { 65 | "vscode:prepublish": "npm run build", 66 | "pub": "vsce publish", 67 | "build": "esbuild src/extension.ts --bundle --outfile=dist/graphql-codegen-vscode.js --sourcemap --external:vscode --platform=node", 68 | "compile": "tsc -p ./", 69 | "tsc": "tsc --noEmit", 70 | "watch": "tsc -watch -p ./", 71 | "test-compile": "tsc -p ./", 72 | "test-watch": "tsc -watch -p ./", 73 | "pretest": "npm run test-compile && npm run lint", 74 | "lint": "eslint src --ext ts", 75 | "test": "npm run pretest" 76 | }, 77 | "devDependencies": { 78 | "@types/glob": "^8.1.0", 79 | "@types/lodash.clonedeep": "^4.5.9", 80 | "@types/mocha": "^10.0.9", 81 | "@types/node": "^22.7.5", 82 | "@types/vscode": "^1.94.0", 83 | "@typescript-eslint/eslint-plugin": "^8.8.1", 84 | "@typescript-eslint/parser": "^8.8.1", 85 | "esbuild": "^0.24.0", 86 | "eslint": "^9", 87 | "glob": "^11.0.0", 88 | "husky": "^9.1.6", 89 | "mocha": "^10.7.3", 90 | "prettier": "^3.3.3", 91 | "pretty-quick": "^4.0.0", 92 | "ts-loader": "^9.5.1", 93 | "typescript": "^5.6.3", 94 | "vscode-test": "^1.6.1" 95 | }, 96 | "husky": { 97 | "hooks": { 98 | "pre-commit": "pretty-quick --staged" 99 | } 100 | }, 101 | "dependencies": { 102 | "@graphql-codegen/cli": "^5.0.3", 103 | "globby": "^14.0.2", 104 | "graphql": "^16.9.0", 105 | "graphql-config": "^5.1.3", 106 | "lodash.clonedeep": "^4.5.0", 107 | "multimatch": "^7.0.0" 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import * as vscode from 'vscode' 3 | import * as graphqlCodegenCli from '@graphql-codegen/cli' 4 | 5 | import * as path from 'path' 6 | import multimatch from 'multimatch' 7 | import cloneDeep from 'lodash.clonedeep' 8 | import { YamlCliFlags } from '@graphql-codegen/cli' 9 | 10 | import { globby } from 'globby' 11 | 12 | let workspaceWithGraphqlCodegenCli: string | null = null 13 | 14 | const makePathAbsolute = (fsPath: string): string => { 15 | if (path.isAbsolute(fsPath) || fsPath.startsWith('http')) { 16 | return fsPath 17 | } 18 | if (!workspaceWithGraphqlCodegenCli) { 19 | throw new Error( 20 | 'workspaceWithGraphqlCodegenCli is not set. This should not happen, please report this as a bug.' 21 | ) 22 | } 23 | return path.join(workspaceWithGraphqlCodegenCli, fsPath) 24 | } 25 | 26 | const makePathOrPathArrayAbsolute = ( 27 | fsPath: string | string[] 28 | ): string | string[] => { 29 | if (Array.isArray(fsPath)) { 30 | return fsPath.map(makePathOrPathArrayAbsolute) as string[] 31 | } 32 | return makePathAbsolute(fsPath) 33 | } 34 | 35 | const makePathAbsoluteInSchema = ( 36 | schema: string | Record | (string | Record)[] 37 | ): string | Record | (string | Record)[] => { 38 | if (Array.isArray(schema)) { 39 | return schema.map(makePathAbsoluteInSchema) 40 | } 41 | 42 | if (typeof schema === 'string') { 43 | return makePathAbsolute(schema) 44 | } 45 | 46 | const [path, configuration] = Object.entries(schema)[0] 47 | return { [makePathAbsolute(path)]: configuration } 48 | } 49 | 50 | const PLUGIN_SETTINGS_ID = 'graphql-codegen' 51 | const FILE_EXTENSIONS_WITH_DOCUMENTS_KEY = 52 | 'fileExtensionsDeclaringGraphQLDocuments' 53 | const FILE_PATH_TO_WATCH_KEY = 'filePathToWatch' 54 | const CONFIG_FILE_PATH = 'configFilePath' 55 | 56 | function shouldRunGQLCodegenOnFile(filePath: string): boolean { 57 | const configuration = vscode.workspace.getConfiguration(PLUGIN_SETTINGS_ID) 58 | 59 | const fileExtensionsContainingGraphQLDocuments = configuration.get( 60 | FILE_EXTENSIONS_WITH_DOCUMENTS_KEY, 61 | ['graphql', 'gql'] 62 | ) 63 | const filePathToWatch = configuration.get( 64 | FILE_PATH_TO_WATCH_KEY, 65 | null 66 | ) 67 | 68 | const fileMatchesExtensions = fileExtensionsContainingGraphQLDocuments.some( 69 | (ext) => filePath.endsWith(ext) 70 | ) 71 | const fileInPathToWatch = 72 | filePathToWatch == null || multimatch(filePath, filePathToWatch).length > 0 73 | 74 | return fileMatchesExtensions && fileInPathToWatch 75 | } 76 | 77 | let cli: typeof graphqlCodegenCli | null = null 78 | 79 | function requireGQLCodegenCli() { 80 | if (cli) { 81 | return cli 82 | } 83 | if (vscode.workspace.workspaceFolders === undefined) { 84 | return 85 | } 86 | for (const dir of vscode.workspace.workspaceFolders) { 87 | try { 88 | cli = require( 89 | path.join(dir.uri.fsPath, '/node_modules/@graphql-codegen/cli') 90 | ) 91 | workspaceWithGraphqlCodegenCli = dir.uri.fsPath 92 | return cli 93 | } catch (err) { 94 | // ignore-we only want to run if @graphql-codegen/cli is installed in node modules 95 | } 96 | } 97 | } 98 | 99 | const getConfigPath = async () => { 100 | const configuration = vscode.workspace.getConfiguration(PLUGIN_SETTINGS_ID) 101 | const userConfigPath = configuration.get( 102 | CONFIG_FILE_PATH, 103 | undefined 104 | ) 105 | 106 | if (userConfigPath) { 107 | return makePathAbsolute(userConfigPath) 108 | } 109 | 110 | if (cli == null || !workspaceWithGraphqlCodegenCli) { 111 | throw new Error( 112 | 'cli is not set. This should not happen, please report this as a bug.' 113 | ) 114 | } 115 | 116 | const foundConfigs = await globby(cli.generateSearchPlaces('codegen'), { 117 | cwd: workspaceWithGraphqlCodegenCli 118 | }) 119 | 120 | return path.join(workspaceWithGraphqlCodegenCli, foundConfigs[0]) 121 | } 122 | 123 | // TODO figure out why we're getting Activating extension 'GraphQL.vscode-graphql-execution' failed: Cannot find module 'graphql-config' 124 | // Require stack: 125 | // - /home/capaj/.vscode/extensions/graphql.vscode-graphql-execution-0.1.7/dist/providers/exec-content.js 126 | // - /home/capaj/.vscode/extensions/graphql.vscode-graphql-execution-0.1.7/dist/extension.js 127 | // it does not seem to affect anything, just annoying spam in the console, generation works fine 128 | export function activate(context: vscode.ExtensionContext) { 129 | let cachedCtx: graphqlCodegenCli.CodegenContext | null = null 130 | let originalGenerates: Record | null = null 131 | 132 | const getCodegenContextForVSCode = async () => { 133 | if (cachedCtx) { 134 | return cachedCtx 135 | } 136 | 137 | if (!cli) { 138 | vscode.window.showWarningMessage( 139 | `could not find '/node_modules/@graphql-codegen/cli'` 140 | ) 141 | return 142 | } 143 | 144 | if (!workspaceWithGraphqlCodegenCli) { 145 | vscode.window.showWarningMessage( 146 | `could not find workspace with graphql-codegen-cli` 147 | ) 148 | return 149 | } 150 | 151 | try { 152 | const configFilePath = await getConfigPath() 153 | 154 | const flags: Partial = { 155 | config: configFilePath 156 | } 157 | cachedCtx = await cli.createContext(flags as YamlCliFlags) 158 | 159 | cachedCtx.cwd = workspaceWithGraphqlCodegenCli 160 | 161 | const config = cachedCtx.getConfig() 162 | if (!config) { 163 | return 164 | } 165 | 166 | if (config.schema) { 167 | // typically on a config for a single codegen artefact0 168 | config.schema = makePathAbsoluteInSchema(config.schema) 169 | } 170 | 171 | const generates = config.generates 172 | if (generates) { 173 | originalGenerates = cloneDeep(generates) 174 | const generatesWithAllAbsolutePaths: Record = {} 175 | // typically on a config for a codegen with multiple artifacts 176 | for (const codegenGenerateOutput of Object.keys(generates)) { 177 | const codegenGenerate = generates[codegenGenerateOutput] as any // as Types.ConfiguredOutput 178 | 179 | if (codegenGenerate.schema) { 180 | codegenGenerate.schema = makePathAbsoluteInSchema( 181 | codegenGenerate.schema 182 | ) 183 | } 184 | if ( 185 | codegenGenerate.preset && 186 | typeof codegenGenerate.preset === 'string' && 187 | codegenGenerate.preset.includes('near-operation-file') && 188 | !codegenGenerate.presetConfig?.cwd 189 | ) { 190 | if (!codegenGenerate.presetConfig) { 191 | codegenGenerate.presetConfig = {} 192 | } 193 | codegenGenerate.presetConfig.cwd = workspaceWithGraphqlCodegenCli 194 | } 195 | 196 | codegenGenerate.originalOutputPath = codegenGenerateOutput 197 | generatesWithAllAbsolutePaths[ 198 | makePathAbsolute(codegenGenerateOutput) // this is only needed for windows. Not sure why, but it works fine on linux even when these paths are relative 199 | ] = codegenGenerate 200 | } 201 | config.generates = generatesWithAllAbsolutePaths 202 | } 203 | 204 | cachedCtx.updateConfig(config) 205 | 206 | // console.log('cached ctx', cachedCtx) 207 | 208 | return cachedCtx 209 | } catch (err) { 210 | console.error(err) 211 | throw err 212 | } 213 | } 214 | 215 | vscode.workspace.onDidSaveTextDocument( 216 | async (document: vscode.TextDocument) => { 217 | if (shouldRunGQLCodegenOnFile(document.fileName)) { 218 | requireGQLCodegenCli() // require the package lazily as late as possible-makes it possible to install the deps and get the generation working right away 219 | 220 | const ctx = await getCodegenContextForVSCode() 221 | if (!ctx) { 222 | return 223 | } 224 | 225 | const config = ctx.getConfig() 226 | if (!config) { 227 | return 228 | } 229 | if (config.schema) { 230 | config.documents = document.fileName 231 | } else { 232 | const { generates } = config 233 | 234 | for (const codegenGenerateOutput of Object.keys(generates)) { 235 | const codegenGenerate = generates[codegenGenerateOutput] as any // as Types.ConfiguredOutput 236 | 237 | const matches = multimatch( 238 | document.fileName.replace( 239 | `${workspaceWithGraphqlCodegenCli}/`, 240 | '' 241 | ), 242 | // @ts-expect-error 243 | originalGenerates[codegenGenerate.originalOutputPath].documents 244 | ) 245 | 246 | if (matches.length === 0) { 247 | // this file does not match the glob. This will not generate so we can omit this 248 | codegenGenerate.documents = [] 249 | } else { 250 | codegenGenerate.documents = document.fileName 251 | } 252 | } 253 | } 254 | 255 | ctx.updateConfig(config) 256 | 257 | await runCliGenerateWithUINotifications(ctx, document.fileName) 258 | } 259 | // const customConfig = customExtensionConfig() 260 | } 261 | ) 262 | 263 | const disposable = vscode.commands.registerCommand( 264 | 'graphql-codegen.generateGqlCodegen', 265 | async () => { 266 | requireGQLCodegenCli() 267 | 268 | const ctx = await getCodegenContextForVSCode() 269 | if (!ctx) { 270 | return 271 | } 272 | 273 | const config = ctx.getConfig() 274 | if (!config) { 275 | vscode.window.showWarningMessage( 276 | `could not find @graphql-codegen/cli config` 277 | ) 278 | return 279 | } 280 | 281 | config.documents = makePathOrPathArrayAbsolute( 282 | config.documents as string[] 283 | ) 284 | 285 | ctx.updateConfig(config) 286 | 287 | await runCliGenerateWithUINotifications(ctx) 288 | } 289 | ) 290 | context.subscriptions.push(disposable) 291 | } 292 | 293 | async function runCliGenerateWithUINotifications( 294 | ctx: graphqlCodegenCli.CodegenContext, 295 | file?: string 296 | ) { 297 | if (!cli) { 298 | vscode.window.showWarningMessage( 299 | `could not find '/node_modules/@graphql-codegen/cli'` 300 | ) 301 | return 302 | } 303 | 304 | try { 305 | await cli.generate(ctx) 306 | 307 | vscode.window.showInformationMessage( 308 | `graphql codegen ${file ?? ''} successful!` 309 | ) 310 | } catch (err) { 311 | if (err.errors?.length) { 312 | vscode.window.showErrorMessage( 313 | `Codegen threw ${err.errors.length} ${ 314 | err.errors.length === 1 ? 'error' : 'errors' 315 | }, first one: ${err.errors[0].message}` 316 | ) 317 | } else { 318 | vscode.window.showErrorMessage(`Codegen threw error: ${err.message}`) 319 | } 320 | } 321 | } 322 | 323 | export function deactivate() { 324 | cli = null 325 | } 326 | --------------------------------------------------------------------------------