graphql-data-generator 0.2.3 → 0.3.0-alpha.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/esm/codegen.js CHANGED
@@ -555,7 +555,9 @@ ${usedTypes.map(([name]) => ` ${name}: ${rename(name)};`).join("\n")}
555
555
  }
556
556
  else if (enums.startsWith("import:") &&
557
557
  usedReferences.some((r) => r.kind === Kind.ENUM_TYPE_DEFINITION)) {
558
- serializedTypes.unshift(`import { ${usedReferences.filter((r) => r.kind === Kind.ENUM_TYPE_DEFINITION).map((r) => r.name.value).join(", ")} } from "${enums.slice(7)}";`);
558
+ serializedTypes.unshift(`import {
559
+ ${usedReferences.filter((r) => r.kind === Kind.ENUM_TYPE_DEFINITION).map((r) => r.name.value).join(",\n ")},
560
+ } from "${enums.slice(7)}";`);
559
561
  }
560
562
  return serializedTypes.join("\n\n") + "\n";
561
563
  };
package/esm/init.js CHANGED
@@ -72,18 +72,62 @@ export const init = (schema, queries, mutations, subscriptions, types, inputs, s
72
72
  return `${kind}${operation[0].toUpperCase()}${operation.slice(1)}`;
73
73
  };
74
74
  const addOperationTransforms = (operation, obj) => {
75
- Object.defineProperty(obj, "patch", {
76
- value: (...patches) => {
77
- const prev = typeof obj === "function" ? obj() : obj;
78
- const builder = build[operation];
79
- const { result, request, error, ...rest } = prev;
80
- return builder({
81
- data: result.data,
82
- variables: request.variables,
83
- error: error,
84
- errors: result.errors,
85
- ...rest,
86
- }, ...patches);
75
+ Object.defineProperties(obj, {
76
+ patch: {
77
+ value: (...patches) => {
78
+ const prev = typeof obj === "function" ? obj() : obj;
79
+ const builder = build[operation];
80
+ const { result, request, error, ...rest } = prev;
81
+ return builder({
82
+ data: result.data,
83
+ variables: request.variables,
84
+ error: error,
85
+ errors: result.errors,
86
+ ...rest,
87
+ }, ...patches);
88
+ },
89
+ },
90
+ variables: {
91
+ value: (variables) => {
92
+ const prev = typeof obj === "function" ? obj() : obj;
93
+ const builder = build[operation];
94
+ const { result, request, error, ...rest } = prev;
95
+ const mock = builder({
96
+ data: result.data,
97
+ variables: request.variables,
98
+ error: error,
99
+ errors: result.errors,
100
+ ...rest,
101
+ }, {
102
+ variables: typeof variables === "function"
103
+ ? variables(result.data, request.variables)
104
+ : variables,
105
+ });
106
+ Error.captureStackTrace(mock, obj.variables);
107
+ mock.stack = mock.stack?.slice(6);
108
+ return mock;
109
+ },
110
+ },
111
+ data: {
112
+ value: (data) => {
113
+ const prev = typeof obj === "function" ? obj() : obj;
114
+ const builder = build[operation];
115
+ const { result, request, error, ...rest } = prev;
116
+ const mock = builder({
117
+ data: result.data,
118
+ variables: request.variables,
119
+ error: error,
120
+ errors: result.errors,
121
+ ...rest,
122
+ }, {
123
+ data: typeof data === "function"
124
+ ? data(request.variables, result.data)
125
+ : data,
126
+ });
127
+ Error.captureStackTrace(mock, obj.data);
128
+ mock.stack = mock.stack?.slice(6);
129
+ return mock;
130
+ },
87
131
  },
88
132
  });
89
133
  Object.defineProperties(obj, Object.fromEntries(Object.entries(transforms[operation] ?? {}).map(([name, fn]) => [name, {
@@ -100,26 +144,34 @@ export const init = (schema, queries, mutations, subscriptions, types, inputs, s
100
144
  ? operationFn(prevInput, ...args)
101
145
  : operationFn);
102
146
  const builder = build[operation];
103
- return builder(prevInput, patch);
147
+ const mock = builder(prevInput, patch);
148
+ Error.captureStackTrace(mock, obj[name]);
149
+ mock.stack = mock.stack?.slice(6);
150
+ return mock;
104
151
  },
105
152
  }])));
106
153
  return obj;
107
154
  };
108
- const operationBuilder = (name, path) => addOperationTransforms(name, (...patches) => {
109
- const query = getOperationContent(path, name);
110
- if (transforms[name] && "default" in transforms[name]) {
111
- patches = [transforms[name].default, ...patches];
112
- }
113
- const { request: { query: parsedQuery, ...request }, ...raw } = operation(doc.definitions, scalars, query, ...patches);
114
- const result = toObject({
115
- request: { ...request },
116
- ...raw,
117
- });
118
- result.request.query = parsedQuery;
119
- return addOperationTransforms(name, options?.finalizeOperation
120
- ? options.finalizeOperation(result)
121
- : result);
122
- });
155
+ const operationBuilder = (name, path) => {
156
+ const builder = (...patches) => {
157
+ const query = getOperationContent(path, name);
158
+ if (transforms[name] && "default" in transforms[name]) {
159
+ patches = [transforms[name].default, ...patches];
160
+ }
161
+ const { request: { query: parsedQuery, ...request }, ...raw } = operation(doc.definitions, scalars, query, ...patches);
162
+ const mock = toObject({
163
+ request: { ...request },
164
+ ...raw,
165
+ });
166
+ mock.request.query = parsedQuery;
167
+ Error.captureStackTrace(mock, builder);
168
+ mock.stack = mock.stack?.slice(6);
169
+ return addOperationTransforms(name, options?.finalizeOperation
170
+ ? options.finalizeOperation(mock)
171
+ : mock);
172
+ };
173
+ return addOperationTransforms(name, builder);
174
+ };
123
175
  {
124
176
  const nonQueryNames = [
125
177
  ...Object.keys(mutations),
package/esm/jest.js ADDED
@@ -0,0 +1,120 @@
1
+ import * as dntShim from "./_dnt.shims.js";
2
+ import "./deps/esm.sh/@types/jest@29.5.3/index";
3
+ import React, { useMemo } from "react";
4
+ import { ApolloLink } from "@apollo/client";
5
+ import { ErrorLink } from "@apollo/client/link/error/index.js";
6
+ import { MockedProvider, MockLink, } from "@apollo/client/testing/index.js";
7
+ import { waitFor } from "@testing-library/dom";
8
+ import { print } from "graphql";
9
+ import { diff as jestDiff } from "jest-diff";
10
+ let currentSpecResult;
11
+ jasmine.getEnv().addReporter({
12
+ specStarted: (result) => currentSpecResult = result,
13
+ });
14
+ const afterTest = [];
15
+ afterEach(async () => {
16
+ for (const hook of afterTest)
17
+ await hook();
18
+ afterTest.splice(0);
19
+ });
20
+ const diff = (a, b) => jestDiff(a, b, {
21
+ omitAnnotationLines: true,
22
+ // aColor: green,
23
+ // bColor: red,
24
+ // changeColor: inverse,
25
+ // commonColor: dim,
26
+ // patchColor: yellow,
27
+ })
28
+ ?.replace(/\w+ \{/g, "{") // Remove class names
29
+ .replace(/\w+ \[/g, "["); // Remove array class names
30
+ const getErrorMessage = (operation, mockLink) => {
31
+ const definition = operation.query.definitions[0];
32
+ const operationType = definition.kind === "OperationDefinition"
33
+ ? definition.operation
34
+ : "<unknown operation type>";
35
+ const key = JSON.stringify({
36
+ query: print(operation.query),
37
+ });
38
+ // Bypassing private variable
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ const alts = (mockLink
41
+ .mockedResponsesByKey[key] ?? []);
42
+ let errorMessage = `Expected GraphQL ${operationType} ${operation.operationName} to have been mocked`;
43
+ if (alts.length || Object.keys(operation.variables).length > 0) {
44
+ errorMessage += ` with variables ${dntShim.Deno.inspect(operation.variables, { depth: Infinity, colors: true })}`;
45
+ }
46
+ if (alts.length > 1) {
47
+ errorMessage +=
48
+ `, found ${alts.length} similar operations with differing variables:${alts
49
+ .slice(0, 9)
50
+ .map((o, i) => `\n${i + 1}.\n${diff(operation.variables, o.request.variables)}`)
51
+ .join("")}`;
52
+ if (alts.length > 9)
53
+ errorMessage += `\n... and ${alts.length - 9} more`;
54
+ }
55
+ else if (alts.length === 1) {
56
+ errorMessage += `, found similar operation with differing variables:\n${diff(operation.variables, alts[0].request.variables)}`;
57
+ }
58
+ return {
59
+ message: errorMessage,
60
+ stack: alts[0] && "stack" in alts[0] && typeof alts[0].stack === "string"
61
+ ? alts[0]?.stack
62
+ : undefined,
63
+ };
64
+ };
65
+ export const MockProvider = ({ mocks, stack, children }) => {
66
+ const observableMocks = useMemo(() => {
67
+ const observableMocks = mocks.map((m) => ({
68
+ ...m,
69
+ stack: m.stack,
70
+ result: Object.assign(jest.fn(() => m.result), m.result),
71
+ }));
72
+ afterTest.push(async () => {
73
+ if (currentSpecResult.failedExpectations.length)
74
+ return;
75
+ for (const mock of observableMocks) {
76
+ if ("optional" in mock && mock.optional || mock.error)
77
+ continue;
78
+ await waitFor(() => {
79
+ if (currentSpecResult.failedExpectations.length)
80
+ return;
81
+ if (mock.result.mock.calls.length === 0) {
82
+ const err = new Error(`Expected to have used mock ${mock.request.variables
83
+ ? ` with variables ${dntShim.Deno.inspect(mock.request.variables, {
84
+ depth: Infinity,
85
+ colors: true,
86
+ })}`
87
+ : ""}`);
88
+ err.stack = `${err.message}\n${mock.stack ?? stack ?? err.stack?.slice(6)}`;
89
+ throw err;
90
+ }
91
+ }, { onTimeout: (e) => e });
92
+ }
93
+ });
94
+ return observableMocks;
95
+ }, [mocks]);
96
+ const link = useMemo(() => {
97
+ const mockLink = new MockLink(observableMocks);
98
+ mockLink.showWarnings = false;
99
+ const errorLoggingLink = new ErrorLink(({ networkError, operation }) => {
100
+ if (!networkError?.message.includes("No more mocked responses"))
101
+ return;
102
+ const { message, stack: altStack } = getErrorMessage(operation, mockLink);
103
+ try {
104
+ networkError.message = message;
105
+ const finalStack = altStack ?? stack
106
+ ? `${message}\n${altStack ?? stack}`
107
+ : undefined;
108
+ if (finalStack)
109
+ networkError.stack = finalStack;
110
+ fail({ name: "Error", message, stack: finalStack });
111
+ }
112
+ catch {
113
+ // fail both throws and marks the test as failed in jest; we only need the latter
114
+ }
115
+ });
116
+ // @ts-ignore It's fine
117
+ return ApolloLink.from([errorLoggingLink, mockLink]);
118
+ }, [observableMocks, stack]);
119
+ return React.createElement(MockedProvider, { link: link }, children);
120
+ };
package/esm/plugin.cjs CHANGED
@@ -2,6 +2,7 @@
2
2
  module.exports = {
3
3
  async plugin(schema, documents, config) {
4
4
  const { codegen } = await import("./codegen.js");
5
- return (config.banner ?? "") + codegen(schema, documents.map((d) => ({ path: d.location, content: d.rawSDL })), { namingConvention: "change-case-all#pascalCase", ...config });
5
+ const { formatCode } = await import("./util.js");
6
+ return (config.banner ?? "") + await formatCode(codegen(schema, documents.map((d) => ({ path: d.location, content: d.rawSDL })), { namingConvention: "change-case-all#pascalCase", ...config }));
6
7
  },
7
8
  };
package/esm/util.js CHANGED
@@ -1,4 +1,4 @@
1
- import { exec } from "node:child_process";
1
+ import { spawn } from "node:child_process";
2
2
  export const raise = (error) => {
3
3
  if (typeof error === "string") {
4
4
  const err = new Error(error);
@@ -10,14 +10,28 @@ export const raise = (error) => {
10
10
  export const formatCode = async (input) => {
11
11
  try {
12
12
  return await new Promise((resolve, reject) => {
13
- const process = exec("deno fmt -", (error, stdout, stderr) => {
14
- if (error)
15
- return reject(error);
16
- if (stderr)
17
- return reject(new Error(stderr));
18
- resolve(stdout);
13
+ const process = spawn("deno", ["fmt", "-"], {
14
+ stdio: ["pipe", "pipe", "pipe"],
19
15
  });
20
- process.stdin?.write(input);
16
+ let output = "";
17
+ let errorOutput = "";
18
+ process.stdout.on("data", (data) => {
19
+ output += data.toString();
20
+ });
21
+ process.stderr.on("data", (data) => {
22
+ errorOutput += data.toString();
23
+ });
24
+ process.on("close", (code) => {
25
+ if (code !== 0 || errorOutput) {
26
+ reject(new Error(errorOutput || `Process exited with code ${code}`));
27
+ }
28
+ else
29
+ resolve(output);
30
+ });
31
+ process.on("error", (error) => {
32
+ reject(error);
33
+ });
34
+ process.stdin.write(input);
21
35
  process.stdin?.end();
22
36
  });
23
37
  }
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "graphql-data-generator",
3
- "version": "0.2.3",
3
+ "version": "0.3.0-alpha.0",
4
4
  "repository": {
5
5
  "type": "git",
6
- "url": "git+https://github.com/vocesgraphql-data-generator/.git"
6
+ "url": "git+https://github.com/voces/graphql-data-generator.git"
7
7
  },
8
8
  "license": "MIT",
9
9
  "bugs": {
@@ -24,6 +24,12 @@
24
24
  "require": "./esm/plugin.cjs",
25
25
  "types": "./types/plugin.cjs",
26
26
  "default": "./esm/plugin.cjs"
27
+ },
28
+ "./jest": {
29
+ "import": "./esm/jest.js",
30
+ "require": "./esm/jest.js",
31
+ "types": "./types/jest.d.ts",
32
+ "default": "./esm/jest.js"
27
33
  }
28
34
  },
29
35
  "bin": {
@@ -31,7 +37,9 @@
31
37
  },
32
38
  "dependencies": {
33
39
  "@graphql-codegen/visitor-plugin-common": "*",
40
+ "@testing-library/dom": "*",
34
41
  "fast-glob": "*",
42
+ "jest-diff": "*",
35
43
  "@deno/shim-deno": "~0.18.0"
36
44
  },
37
45
  "devDependencies": {
@@ -40,6 +48,20 @@
40
48
  "_generatedBy": "dnt@dev",
41
49
  "peerDependencies": {
42
50
  "graphql": "*",
43
- "@graphql-tools/graphql-tag-pluck": "*"
51
+ "@graphql-tools/graphql-tag-pluck": "*",
52
+ "react": "*",
53
+ "@types/react": "*",
54
+ "@apollo/client": "*"
55
+ },
56
+ "peerDependenciesMeta": {
57
+ "react": {
58
+ "optional": true
59
+ },
60
+ "@types/react": {
61
+ "optional": true
62
+ },
63
+ "@apollo/client": {
64
+ "optional": true
65
+ }
44
66
  }
45
67
  }
package/types/init.d.ts CHANGED
@@ -12,5 +12,5 @@ export declare const init: <Query extends Record<string, {
12
12
  }>, Types extends Record<string, Record<string, unknown>>, Inputs extends Record<string, Record<string, unknown>>, Extra = object>(schema: string, queries: { [operation in keyof Query]: string; }, mutations: { [operation in keyof Mutation]: string; }, subscriptions: { [operation in keyof Subscription]: string; }, types: readonly (keyof Types & string)[], inputs: readonly (keyof Inputs & string)[], scalars: {
13
13
  [name: string]: ((typeName: string, fieldName: string) => unknown) | string | number | boolean | null;
14
14
  }, options?: {
15
- finalizeOperation: <T extends OperationMock & Partial<Extra>>(operation: T) => T;
15
+ finalizeOperation?: <T extends OperationMock & Partial<Extra>>(operation: T) => T;
16
16
  }) => <Transforms extends MapObjectsToTransforms<Types & Inputs> & MapOperationsToTransforms<Query, Mutation, Subscription, Types, Inputs>>(fn: (b: Build<Query, Mutation, Subscription, Types, Inputs, ContravariantEmpty, Extra>) => Transforms) => Build<Query, Mutation, Subscription, Types, Inputs, Transforms, Extra>;
@@ -0,0 +1,8 @@
1
+ import "./deps/esm.sh/@types/jest@29.5.3/index";
2
+ import React from "react";
3
+ import type { OperationMock } from "./types.js";
4
+ export declare const MockProvider: ({ mocks, stack, children }: {
5
+ mocks: OperationMock[];
6
+ stack?: string;
7
+ children?: React.ReactNode;
8
+ }) => React.JSX.Element;
package/types/types.d.ts CHANGED
@@ -27,6 +27,7 @@ export type OperationMock<Data extends Record<string, unknown> = Record<string,
27
27
  errors?: GraphQLError[];
28
28
  };
29
29
  error?: Error;
30
+ stack?: string;
30
31
  };
31
32
  export type SimpleOperationMock<Data extends Record<string, unknown> = Record<string, unknown>, Variables = Record<string, unknown> | never> = {
32
33
  data: Data;