diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cbf4b3f5e7a..d55bd14a643 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -73,37 +73,40 @@ jobs: - name: End2End Test Examples run: | EXAMPLE_TYPE=normal yarn examples:test:end2end - dev-tests-swc: - name: Examples - SWC - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - - name: Setup env - uses: the-guild-org/shared-config/setup@main - - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1 - with: - toolchain: 1.65.0 - target: wasm32-wasi - override: true - - name: Build SWC plugin - working-directory: ./packages/presets/swc-plugin - run: | - npm run build-wasm - - name: Build - run: yarn build - env: - CI: true - - name: Generate and Diff Codegen Artifacts - run: | - EXAMPLE_TYPE=swc yarn examples:codegen - git diff --exit-code -- examples/ - - name: Build Examples - run: | - EXAMPLE_TYPE=swc yarn examples:build - - name: End2End Test Examples - run: | - EXAMPLE_TYPE=swc yarn examples:test:end2end + + # TODO: Remove all SWC test setup and references as that has been moved to https://github.com/swc-project/plugins/tree/main/contrib/graphql-codegen-client-preset + # dev-tests-swc: + # name: Examples - SWC + # runs-on: ubuntu-latest + # steps: + # - name: Checkout + # uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + # - name: Setup env + # uses: the-guild-org/shared-config/setup@main + # - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1 + # with: + # toolchain: 1.65.0 + # target: wasm32-wasi + # override: true + # - name: Build SWC plugin + # working-directory: ./packages/presets/swc-plugin + # run: | + # npm run build-wasm + # - name: Build + # run: yarn build + # env: + # CI: true + # - name: Generate and Diff Codegen Artifacts + # run: | + # EXAMPLE_TYPE=swc yarn examples:codegen + # git diff --exit-code -- examples/ + # - name: Build Examples + # run: | + # EXAMPLE_TYPE=swc yarn examples:build + # - name: End2End Test Examples + # run: | + # EXAMPLE_TYPE=swc yarn examples:test:end2end + esm: name: Testing exports integrity runs-on: ubuntu-latest diff --git a/examples/persisted-documents-string-mode/package.json b/examples/persisted-documents-string-mode/package.json index 345e00c4e90..32ea3668f40 100644 --- a/examples/persisted-documents-string-mode/package.json +++ b/examples/persisted-documents-string-mode/package.json @@ -8,7 +8,7 @@ }, "devDependencies": { "@graphql-typed-document-node/core": "3.2.0", - "@graphql-codegen/cli": "6.0.0", + "@graphql-codegen/cli": "6.0.1", "@babel/core": "7.25.2", "@babel/preset-env": "7.25.3", "@babel/preset-typescript": "7.27.1" diff --git a/examples/persisted-documents/package.json b/examples/persisted-documents/package.json index d8af54cd364..d04515225f4 100644 --- a/examples/persisted-documents/package.json +++ b/examples/persisted-documents/package.json @@ -8,7 +8,7 @@ }, "devDependencies": { "@graphql-typed-document-node/core": "3.2.0", - "@graphql-codegen/cli": "6.0.0", + "@graphql-codegen/cli": "6.0.1", "@babel/core": "7.25.2", "@babel/preset-env": "7.25.3", "@babel/preset-typescript": "7.27.1" diff --git a/examples/react/apollo-client-defer/package.json b/examples/react/apollo-client-defer/package.json index e44943f0016..f2340bd0cb5 100644 --- a/examples/react/apollo-client-defer/package.json +++ b/examples/react/apollo-client-defer/package.json @@ -11,7 +11,7 @@ "graphql-yoga": "5.7.0" }, "devDependencies": { - "@graphql-codegen/cli": "^6.0.0", + "@graphql-codegen/cli": "^6.0.1", "@types/node": "^22.0.0", "@types/react": "^18.0.15", "@types/react-dom": "^18.0.10", diff --git a/examples/react/apollo-client-swc-plugin/package.json b/examples/react/apollo-client-swc-plugin/package.json index f1828ae92ef..33e9e5ff445 100644 --- a/examples/react/apollo-client-swc-plugin/package.json +++ b/examples/react/apollo-client-swc-plugin/package.json @@ -9,7 +9,7 @@ }, "devDependencies": { "@graphql-codegen/client-preset-swc-plugin": "0.2.0", - "@graphql-codegen/cli": "^6.0.0", + "@graphql-codegen/cli": "^6.0.1", "@vitejs/plugin-react-swc": "^3.3.0", "@types/react": "18.3.3", "@types/react-dom": "18.3.0", diff --git a/examples/react/apollo-client/package.json b/examples/react/apollo-client/package.json index 5b0eefc1ff9..1ce0860ed38 100644 --- a/examples/react/apollo-client/package.json +++ b/examples/react/apollo-client/package.json @@ -9,7 +9,7 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@graphql-codegen/cli": "^6.0.0", + "@graphql-codegen/cli": "^6.0.1", "@vitejs/plugin-react": "^4.0.0", "@types/node": "^22.0.0", "@types/react": "^18.0.15", diff --git a/examples/react/http-executor/package.json b/examples/react/http-executor/package.json index 2b9ac10c15b..09f1f8ace7e 100644 --- a/examples/react/http-executor/package.json +++ b/examples/react/http-executor/package.json @@ -8,7 +8,7 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@graphql-codegen/cli": "^6.0.0", + "@graphql-codegen/cli": "^6.0.1", "@vitejs/plugin-react": "^4.0.0", "@types/node": "^22.0.0", "@types/react": "^18.0.17", diff --git a/examples/react/nextjs-swr/package.json b/examples/react/nextjs-swr/package.json index a39deda68cf..7ff5092e605 100644 --- a/examples/react/nextjs-swr/package.json +++ b/examples/react/nextjs-swr/package.json @@ -19,7 +19,7 @@ "swr": "^2.0.0" }, "devDependencies": { - "@graphql-codegen/cli": "^6.0.0", + "@graphql-codegen/cli": "^6.0.1", "@graphql-codegen/schema-ast": "5.0.0", "@graphql-codegen/client-preset-swc-plugin": "0.2.0", "@types/node": "^22.0.0", diff --git a/examples/react/tanstack-react-query/package.json b/examples/react/tanstack-react-query/package.json index 709d14f88f1..91d83fc1c34 100644 --- a/examples/react/tanstack-react-query/package.json +++ b/examples/react/tanstack-react-query/package.json @@ -8,7 +8,7 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@graphql-codegen/cli": "^6.0.0", + "@graphql-codegen/cli": "^6.0.1", "@vitejs/plugin-react": "^4.0.0", "@types/node": "^22.0.0", "@types/react": "^18.0.17", diff --git a/examples/react/urql/package.json b/examples/react/urql/package.json index f31e90f2a4c..0efe6316ddd 100644 --- a/examples/react/urql/package.json +++ b/examples/react/urql/package.json @@ -10,7 +10,7 @@ "devDependencies": { "@types/react": "^18.0.17", "@types/react-dom": "^18.0.10", - "@graphql-codegen/cli": "^6.0.0", + "@graphql-codegen/cli": "^6.0.1", "@vitejs/plugin-react": "^4.0.0", "typescript": "5.5.4", "serve": "14.2.3", diff --git a/examples/typescript-esm/package.json b/examples/typescript-esm/package.json index dc3d6e5373b..c6c2cf25860 100644 --- a/examples/typescript-esm/package.json +++ b/examples/typescript-esm/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "devDependencies": { - "@graphql-codegen/cli": "6.0.0" + "@graphql-codegen/cli": "6.0.1" }, "dependencies": { "@graphql-typed-document-node/core": "3.2.0", diff --git a/examples/typescript-graphql-request/package.json b/examples/typescript-graphql-request/package.json index eebbe1af9de..e637aaaa01c 100644 --- a/examples/typescript-graphql-request/package.json +++ b/examples/typescript-graphql-request/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "devDependencies": { - "@graphql-codegen/cli": "6.0.0" + "@graphql-codegen/cli": "6.0.1" }, "dependencies": { "graphql": "16.9.0", diff --git a/examples/typescript-resolvers/package.json b/examples/typescript-resolvers/package.json index eb551421cbb..dd9697db706 100644 --- a/examples/typescript-resolvers/package.json +++ b/examples/typescript-resolvers/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "devDependencies": { - "@graphql-codegen/cli": "6.0.0", + "@graphql-codegen/cli": "6.0.1", "@graphql-codegen/typescript": "5.0.2", "@graphql-codegen/typescript-resolvers": "5.1.0" }, diff --git a/examples/vite/vite-react-cts/package.json b/examples/vite/vite-react-cts/package.json index ebdf27bce77..5f1e5af08af 100644 --- a/examples/vite/vite-react-cts/package.json +++ b/examples/vite/vite-react-cts/package.json @@ -21,7 +21,7 @@ "vite": "^6.0.0" }, "devDependencies": { - "@graphql-codegen/cli": "6.0.0", + "@graphql-codegen/cli": "6.0.1", "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", "cypress": "14.0.0", diff --git a/examples/vite/vite-react-mts/package.json b/examples/vite/vite-react-mts/package.json index 0ce39afba5d..943e4d49aea 100644 --- a/examples/vite/vite-react-mts/package.json +++ b/examples/vite/vite-react-mts/package.json @@ -21,7 +21,7 @@ "vite": "^6.0.0" }, "devDependencies": { - "@graphql-codegen/cli": "6.0.0", + "@graphql-codegen/cli": "6.0.1", "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", "cypress": "14.0.0", diff --git a/examples/vite/vite-react-ts/package.json b/examples/vite/vite-react-ts/package.json index c3f534518ee..443e314799a 100644 --- a/examples/vite/vite-react-ts/package.json +++ b/examples/vite/vite-react-ts/package.json @@ -21,7 +21,7 @@ "vite": "^6.0.0" }, "devDependencies": { - "@graphql-codegen/cli": "6.0.0", + "@graphql-codegen/cli": "6.0.1", "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", "cypress": "14.0.0", diff --git a/examples/vue/apollo-composable/package.json b/examples/vue/apollo-composable/package.json index 7af05dc6337..0cdc77758c6 100644 --- a/examples/vue/apollo-composable/package.json +++ b/examples/vue/apollo-composable/package.json @@ -17,7 +17,7 @@ "vue": "^3.2.37" }, "devDependencies": { - "@graphql-codegen/cli": "^6.0.0", + "@graphql-codegen/cli": "^6.0.1", "@vitejs/plugin-vue": "^5.0.0", "typescript": "^5.0.0", "vite": "^6.0.0", diff --git a/examples/vue/urql/package.json b/examples/vue/urql/package.json index 19e81a03f3d..4b8c4f11c4d 100644 --- a/examples/vue/urql/package.json +++ b/examples/vue/urql/package.json @@ -16,7 +16,7 @@ "vue": "^3.2.45" }, "devDependencies": { - "@graphql-codegen/cli": "^6.0.0", + "@graphql-codegen/cli": "^6.0.1", "@vitejs/plugin-vue": "^5.0.0", "typescript": "^5.0.0", "vite": "^6.0.0", diff --git a/examples/vue/villus/package.json b/examples/vue/villus/package.json index df94f7a4907..2e75a502fef 100644 --- a/examples/vue/villus/package.json +++ b/examples/vue/villus/package.json @@ -16,7 +16,7 @@ "vue": "^3.2.37" }, "devDependencies": { - "@graphql-codegen/cli": "^6.0.0", + "@graphql-codegen/cli": "^6.0.1", "@vitejs/plugin-vue": "^5.0.0", "typescript": "^5.0.0", "vite": "^6.0.0", diff --git a/examples/yoga-tests/package.json b/examples/yoga-tests/package.json index d9636350529..142f6ad81e7 100644 --- a/examples/yoga-tests/package.json +++ b/examples/yoga-tests/package.json @@ -7,7 +7,7 @@ }, "devDependencies": { "@graphql-typed-document-node/core": "3.2.0", - "@graphql-codegen/cli": "6.0.0", + "@graphql-codegen/cli": "6.0.1", "@babel/core": "7.25.2", "@babel/preset-env": "7.25.3", "@babel/preset-typescript": "7.27.1" diff --git a/packages/graphql-codegen-cli/CHANGELOG.md b/packages/graphql-codegen-cli/CHANGELOG.md index e75d88ca220..ed4d0aa73ac 100644 --- a/packages/graphql-codegen-cli/CHANGELOG.md +++ b/packages/graphql-codegen-cli/CHANGELOG.md @@ -1,5 +1,17 @@ # @graphql-codegen/cli +## 6.0.1 + +### Patch Changes + +- [#10468](https://github.com/dotansimha/graphql-code-generator/pull/10468) [`cb1b9d9`](https://github.com/dotansimha/graphql-code-generator/commit/cb1b9d99c413a96fde6c9af0b2315b3ad721ee4e) Thanks [@eddeee888](https://github.com/eddeee888)! - In watch mode, do not write output on failure + + Previously, on partial or full failure, watch mode still write to output. However, since the output'd be an empty array, it will then call `removeStaleFiles` internally to remove all previously generated files. + + This patch puts a temporary fix to avoid writing output on any failure to fix the described behaviour. + + This also means the `config.allowPartialOutputs` does not work in watch mode for now. + ## 6.0.0 ### Major Changes diff --git a/packages/graphql-codegen-cli/package.json b/packages/graphql-codegen-cli/package.json index ee381b6b597..07b8f791fa1 100644 --- a/packages/graphql-codegen-cli/package.json +++ b/packages/graphql-codegen-cli/package.json @@ -1,6 +1,6 @@ { "name": "@graphql-codegen/cli", - "version": "6.0.0", + "version": "6.0.1", "license": "MIT", "bin": { "gql-gen": "dist/cjs/bin.js", diff --git a/packages/graphql-codegen-cli/src/generate-and-save.ts b/packages/graphql-codegen-cli/src/generate-and-save.ts index 384b84e3a4e..2d05e9f1b18 100644 --- a/packages/graphql-codegen-cli/src/generate-and-save.ts +++ b/packages/graphql-codegen-cli/src/generate-and-save.ts @@ -15,7 +15,14 @@ const hash = (content: string): string => createHash('sha1').update(content).dig export async function generate( input: CodegenContext | (Types.Config & { cwd?: string }), saveToFile = true -): Promise { +): Promise< + | Types.FileOutput[] + /** + * When this function runs in watch mode, it'd return an empty promise that doesn't resolve until the watcher exits + * FIXME: this effectively makes the result `any`, which loses type-hints + */ + | any +> { const context = ensureContext(input); const config = context.getConfig(); await context.profiler.run(() => lifecycleHooks(config.hooks).afterStart(), 'Lifecycle: afterStart'); @@ -43,7 +50,7 @@ export async function generate( const recentOutputHash = new Map(); - async function writeOutput(generationResult: Types.FileOutput[]) { + async function writeOutput(generationResult: Types.FileOutput[]): Promise { if (!saveToFile) { return generationResult; } diff --git a/packages/graphql-codegen-cli/src/utils/watcher.ts b/packages/graphql-codegen-cli/src/utils/watcher.ts index 72a8039998e..615e465552e 100644 --- a/packages/graphql-codegen-cli/src/utils/watcher.ts +++ b/packages/graphql-codegen-cli/src/utils/watcher.ts @@ -79,7 +79,21 @@ export const createWatcher = ( if (!isShutdown) { executeCodegen(initialContext) .then( - ({ result }) => onNext(result), + ({ result, error }) => { + // FIXME: this is a quick fix to stop `onNext` (writeOutput) from + // removing all files when there is an error. + // + // This is because `removeStaleFiles()` will remove files if the + // generated files are different between runs. And on error, it + // returns an empty array i.e. will remove all generated files from + // the previous run + // + // This also means we don't have config.allowPartialOutputs in watch mode + if (error) { + return; + } + onNext(result); + }, () => Promise.resolve() ) .then(() => emitWatching(watchDirectory)); @@ -202,7 +216,14 @@ export const createWatcher = ( stopWatching.runningWatcher = new Promise((resolve, reject) => { executeCodegen(initialContext) .then( - ({ result }) => onNext(result), + ({ result, error }) => { + // TODO: this is the initial run, the logic here mimics the above watcher logic. + // We need to check whether it's ok to deviate between these two. + if (error) { + return; + } + onNext(result); + }, () => Promise.resolve() ) .then(() => runWatcher(abortController.signal)) diff --git a/packages/graphql-codegen-cli/tests/watcher-test-helpers/assert-watcher-build-triggers.ts b/packages/graphql-codegen-cli/tests/watcher-test-helpers/assert-watcher-build-triggers.ts index 296371678f0..9933269580a 100644 --- a/packages/graphql-codegen-cli/tests/watcher-test-helpers/assert-watcher-build-triggers.ts +++ b/packages/graphql-codegen-cli/tests/watcher-test-helpers/assert-watcher-build-triggers.ts @@ -1,5 +1,5 @@ import { join, isAbsolute, relative, resolve, sep } from 'path'; -import { Options } from '@parcel/watcher'; +import type { Options } from '@parcel/watcher'; import isGlob from 'is-glob'; import type { Mock } from 'vitest'; @@ -22,7 +22,7 @@ interface MockWatcher { /** * Helper function for asserting that multiple paths did or did not trigger a build, - * and for asserting the values of paths and globs passed to {@link ParcelWatcher.Options}`["ignore"]` + * and for asserting the values of paths and globs passed to {@link Options}`["ignore"]` */ export const assertBuildTriggers = async ( mockWatcher: MockWatcher, @@ -224,7 +224,7 @@ const assertParcelWouldIgnoreGlob = ( }; /** - * Given a path, and the `ignore` option passed to the mocked {@link ParcelWatcher.Options}, + * Given a path, and the `ignore` option passed to the mocked {@link Options}, * assert that ParcelWatcher "would" ignore the path if given it as part of the ignore option. * * Note that ParcelWatcher expects paths relative from the watchDirectory, but diff --git a/packages/graphql-codegen-cli/tests/watcher.spec.ts b/packages/graphql-codegen-cli/tests/watcher.spec.ts index a89ca46e472..6a68211c980 100644 --- a/packages/graphql-codegen-cli/tests/watcher.spec.ts +++ b/packages/graphql-codegen-cli/tests/watcher.spec.ts @@ -10,6 +10,8 @@ const unsubscribeMock = vi.fn(); const subscribeMock = vi.fn(); let subscribeCallbackMock: Mock; +// FIXME: this mocks out the main functionality which is triggering the codegen +// This is not great because we cannot test the actual watch functionality vi.mock('@parcel/watcher', () => ({ subscribe: subscribeMock.mockImplementation((watchDirectory: string, subscribeCallback: SubscribeCallback) => { subscribeCallbackMock = vi.fn(subscribeCallback); @@ -19,13 +21,16 @@ vi.mock('@parcel/watcher', () => ({ }), })); -const setupMockWatcher = async (codegenContext: ConstructorParameters[0]) => { - const { stopWatching } = createWatcher(new CodegenContext(codegenContext), async () => Promise.resolve([])); +const setupMockWatcher = async ( + codegenContext: ConstructorParameters[0], + onNext: Mock = vi.fn().mockResolvedValue([]) +) => { + const { stopWatching } = createWatcher(new CodegenContext(codegenContext), onNext); const dispatchChange = async (path: string) => subscribeCallbackMock(undefined, [{ type: 'update', path }]); // createWatcher doesn't set up subscription immediately, so we wait for a tick before continuing - await new Promise(resolve => setTimeout(resolve, 10)); + await new Promise(resolve => setTimeout(resolve, 100)); return { stopWatching, dispatchChange }; }; @@ -771,4 +776,53 @@ describe('Watch targets', () => { } ); }); + + test('it does not call onNext on error', async () => { + vi.spyOn(fs, 'access').mockImplementation(() => Promise.resolve()); + const onNextMock = vi.fn(); + + const schema = /* GraphQL */ ` + type Query { + me: User + } + + type User { + id: ID + } + `; + const document = /* GraphQL */ ` + query { + me { + id + zzz # Error here + } + } + `; + + const { stopWatching } = await setupMockWatcher( + { + filepath: './foo/some-config.ts', + config: { + hooks: { onWatchTriggered: vi.fn() }, + schema, + documents: document, + generates: { + ['./foo/some-output.ts']: { + plugins: ['typescript'], + }, + }, + }, + }, + onNextMock + ); + + // Because document has error, onNext shouldn't be called + expect(onNextMock).not.toHaveBeenCalled(); + + // Wait a tick for stopWatch to be set up correctly, before calling it + await new Promise(resolve => setTimeout(resolve, 100)); + await stopWatching(); + }); + + test.todo('on watcher subsequent codegen run, it does not call onNext on error'); }); diff --git a/website/package.json b/website/package.json index 73e7936f835..395f644621c 100644 --- a/website/package.json +++ b/website/package.json @@ -26,7 +26,7 @@ "@graphql-codegen/add": "6.0.0", "@graphql-codegen/c-sharp": "4.3.1", "@graphql-codegen/c-sharp-operations": "2.3.1", - "@graphql-codegen/cli": "6.0.0", + "@graphql-codegen/cli": "6.0.1", "@graphql-codegen/client-preset": "5.1.0", "@graphql-codegen/core": "5.0.0", "@graphql-codegen/flow": "2.3.6",