@graphcommerce/graphql-codegen-markdown-docs 6.0.0-canary.20

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.
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MarkdownVisitor = void 0;
4
+ /* eslint-disable @typescript-eslint/no-use-before-define */
5
+ /* eslint-disable prefer-template */
6
+ const typescript_1 = require("@graphql-codegen/typescript");
7
+ const visitor_plugin_common_1 = require("@graphql-codegen/visitor-plugin-common");
8
+ const graphql_1 = require("./graphql");
9
+ const importZod = `import { z } from 'zod'`;
10
+ const anySchema = `definedNonNullAnySchema`;
11
+ const MarkdownVisitor = (schema, config) => {
12
+ const tsVisitor = new typescript_1.TsVisitor(schema, config);
13
+ const importTypes = [];
14
+ return {
15
+ buildImports: () =>
16
+ // if (config.importFrom && importTypes.length > 0) {
17
+ // return [importZod, `import { ${importTypes.join(', ')} } from '${config.importFrom}'`]
18
+ // }
19
+ [importZod],
20
+ initialEmit: () => '\n' +
21
+ [
22
+ new visitor_plugin_common_1.DeclarationBlock({})
23
+ .asKind('type')
24
+ .withName('Properties<T>')
25
+ .withContent(['Required<{', ' [K in keyof T]: z.ZodType<T[K], any, T[K]>;', '}>'].join('\n')).string,
26
+ // Unfortunately, zod doesn’t provide non-null defined any schema.
27
+ // This is a temporary hack until it is fixed.
28
+ // see: https://github.com/colinhacks/zod/issues/884
29
+ new visitor_plugin_common_1.DeclarationBlock({}).asKind('type').withName('definedNonNullAny').withContent('{}')
30
+ .string,
31
+ new visitor_plugin_common_1.DeclarationBlock({})
32
+ .export()
33
+ .asKind('const')
34
+ .withName(`isDefinedNonNullAny`)
35
+ .withContent(`(v: any): v is definedNonNullAny => v !== undefined && v !== null`).string,
36
+ new visitor_plugin_common_1.DeclarationBlock({})
37
+ .export()
38
+ .asKind('const')
39
+ .withName(`${anySchema}`)
40
+ .withContent(`z.any().refine((v) => isDefinedNonNullAny(v))`).string,
41
+ ].join('\n'),
42
+ InputObjectTypeDefinition: (node) => {
43
+ const name = tsVisitor.convertName(node.name.value);
44
+ importTypes.push(name);
45
+ const shape = node.fields
46
+ ?.map((field) => generateFieldZodSchema(config, tsVisitor, schema, field, 2))
47
+ .join(',\n');
48
+ return new visitor_plugin_common_1.DeclarationBlock({})
49
+ .export()
50
+ .asKind('function')
51
+ .withName(`${name}Schema(): z.ZodObject<Properties<${name}>>`)
52
+ .withBlock([(0, visitor_plugin_common_1.indent)(`return z.object<Properties<${name}>>({`), shape, (0, visitor_plugin_common_1.indent)('})')].join('\n')).string;
53
+ },
54
+ ObjectTypeDefinition: ObjectTypeDefinitionBuilder(true, (node) => {
55
+ const name = tsVisitor.convertName(node.name.value);
56
+ importTypes.push(name);
57
+ const shape = node.fields
58
+ ?.map((field) => generateFieldZodSchema(config, tsVisitor, schema, field, 2))
59
+ .join(',\n');
60
+ return new visitor_plugin_common_1.DeclarationBlock({})
61
+ .export()
62
+ .asKind('function')
63
+ .withName(`${name}Schema(): z.ZodObject<Properties<${name}>>`)
64
+ .withBlock([
65
+ (0, visitor_plugin_common_1.indent)(`return z.object<Properties<${name}>>({`),
66
+ (0, visitor_plugin_common_1.indent)(`__typename: z.literal('${node.name.value}').optional(),`, 2),
67
+ shape,
68
+ (0, visitor_plugin_common_1.indent)('})'),
69
+ ].join('\n')).string;
70
+ }),
71
+ EnumTypeDefinition: (node) => {
72
+ const enumname = tsVisitor.convertName(node.name.value);
73
+ importTypes.push(enumname);
74
+ if (config.enumsAsTypes) {
75
+ return new visitor_plugin_common_1.DeclarationBlock({})
76
+ .export()
77
+ .asKind('const')
78
+ .withName(`${enumname}Schema`)
79
+ .withContent(`z.enum([${node.values
80
+ ?.map((enumOption) => `'${enumOption.name.value}'`)
81
+ .join(', ')}])`).string;
82
+ }
83
+ return new visitor_plugin_common_1.DeclarationBlock({})
84
+ .export()
85
+ .asKind('const')
86
+ .withName(`${enumname}Schema`)
87
+ .withContent(`z.nativeEnum(${enumname})`).string;
88
+ },
89
+ UnionTypeDefinition: (node) => {
90
+ if (!node.types)
91
+ return undefined;
92
+ const unionName = tsVisitor.convertName(node.name.value);
93
+ const unionElements = node.types
94
+ .map((t) => `${tsVisitor.convertName(t.name.value)}Schema()`)
95
+ .join(', ');
96
+ const unionElementsCount = node.types.length ?? 0;
97
+ const union = unionElementsCount > 1
98
+ ? (0, visitor_plugin_common_1.indent)(`return z.union([${unionElements}])`)
99
+ : (0, visitor_plugin_common_1.indent)(`return ${unionElements}`);
100
+ return new visitor_plugin_common_1.DeclarationBlock({})
101
+ .export()
102
+ .asKind('function')
103
+ .withName(`${unionName}Schema()`)
104
+ .withBlock(union).string;
105
+ },
106
+ };
107
+ };
108
+ exports.MarkdownVisitor = MarkdownVisitor;
109
+ const generateFieldZodSchema = (config, tsVisitor, schema, field, indentCount) => {
110
+ const gen = generateFieldTypeZodSchema(config, tsVisitor, schema, field, field.type);
111
+ return (0, visitor_plugin_common_1.indent)(`${field.name.value}: ${maybeLazy(field.type, gen)}`, indentCount);
112
+ };
113
+ const generateFieldTypeZodSchema = (config, tsVisitor, schema, field, type, parentType) => {
114
+ if ((0, graphql_1.isListType)(type)) {
115
+ const gen = generateFieldTypeZodSchema(config, tsVisitor, schema, field, type.type, type);
116
+ if (!(0, graphql_1.isNonNullType)(parentType)) {
117
+ const arrayGen = `z.array(${maybeLazy(type.type, gen)})`;
118
+ const maybeLazyGen = applyDirectives(config, field, arrayGen);
119
+ return `${maybeLazyGen}.nullish()`;
120
+ }
121
+ return `z.array(${maybeLazy(type.type, gen)})`;
122
+ }
123
+ if ((0, graphql_1.isNonNullType)(type)) {
124
+ const gen = generateFieldTypeZodSchema(config, tsVisitor, schema, field, type.type, type);
125
+ return maybeLazy(type.type, gen);
126
+ }
127
+ if ((0, graphql_1.isNamedType)(type)) {
128
+ const gen = generateNameNodeZodSchema(config, tsVisitor, schema, type.name);
129
+ if ((0, graphql_1.isListType)(parentType)) {
130
+ return `${gen}.nullable()`;
131
+ }
132
+ const appliedDirectivesGen = applyDirectives(config, field, gen);
133
+ if ((0, graphql_1.isNonNullType)(parentType)) {
134
+ // if (config.notAllowEmptyString === true) {
135
+ // const tsType = tsVisitor.scalars[type.name.value]
136
+ // if (tsType === 'string') return `${appliedDirectivesGen}.min(1)`
137
+ // }
138
+ return appliedDirectivesGen;
139
+ }
140
+ if ((0, graphql_1.isListType)(parentType)) {
141
+ return `${appliedDirectivesGen}.nullable()`;
142
+ }
143
+ return `${appliedDirectivesGen}.nullish()`;
144
+ }
145
+ console.warn('unhandled type:', type);
146
+ return '';
147
+ };
148
+ const applyDirectives = (config, field, gen) =>
149
+ // if (config.directives && field.directives) {
150
+ // const formatted = formatDirectiveConfig(config.directives)
151
+ // return gen + buildApi(formatted, field.directives)
152
+ // }
153
+ gen;
154
+ const generateNameNodeZodSchema = (config, tsVisitor, schema, node) => {
155
+ const typ = schema.getType(node.value);
156
+ if (typ?.astNode?.kind === 'InputObjectTypeDefinition') {
157
+ const enumName = tsVisitor.convertName(typ.astNode.name.value);
158
+ return `${enumName}Schema()`;
159
+ }
160
+ if (typ?.astNode?.kind === 'ObjectTypeDefinition') {
161
+ const enumName = tsVisitor.convertName(typ.astNode.name.value);
162
+ return `${enumName}Schema()`;
163
+ }
164
+ if (typ?.astNode?.kind === 'EnumTypeDefinition') {
165
+ const enumName = tsVisitor.convertName(typ.astNode.name.value);
166
+ return `${enumName}Schema`;
167
+ }
168
+ if (typ?.astNode?.kind === 'UnionTypeDefinition') {
169
+ const enumName = tsVisitor.convertName(typ.astNode.name.value);
170
+ return `${enumName}Schema()`;
171
+ }
172
+ return zod4Scalar(config, tsVisitor, node.value);
173
+ };
174
+ const maybeLazy = (type, schema) => {
175
+ if ((0, graphql_1.isNamedType)(type) && (0, graphql_1.isInput)(type.name.value)) {
176
+ return `z.lazy(() => ${schema})`;
177
+ }
178
+ return schema;
179
+ };
180
+ const zod4Scalar = (config, tsVisitor, scalarName) => {
181
+ const tsType = tsVisitor.scalars[scalarName];
182
+ switch (tsType) {
183
+ case 'string':
184
+ return `z.string()`;
185
+ case 'number':
186
+ return `z.number()`;
187
+ case 'boolean':
188
+ return `z.boolean()`;
189
+ }
190
+ console.warn('unhandled scalar name:', scalarName);
191
+ return anySchema;
192
+ };
package/dist/config.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ObjectTypeDefinitionBuilder = exports.isInput = exports.isNamedType = exports.isNonNullType = exports.isListType = void 0;
4
+ const isListType = (typ) => typ?.kind === 'ListType';
5
+ exports.isListType = isListType;
6
+ const isNonNullType = (typ) => typ?.kind === 'NonNullType';
7
+ exports.isNonNullType = isNonNullType;
8
+ const isNamedType = (typ) => typ?.kind === 'NamedType';
9
+ exports.isNamedType = isNamedType;
10
+ const isInput = (kind) => kind.includes('Input');
11
+ exports.isInput = isInput;
12
+ const ObjectTypeDefinitionBuilder = (useObjectTypes, callback) => {
13
+ if (!useObjectTypes)
14
+ return undefined;
15
+ return (node) => {
16
+ if (/^(Query|Mutation|Subscription)$/.test(node.name.value)) {
17
+ return undefined;
18
+ }
19
+ return callback(node);
20
+ };
21
+ };
22
+ exports.ObjectTypeDefinitionBuilder = ObjectTypeDefinitionBuilder;
package/dist/index.js ADDED
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.plugin = void 0;
4
+ const plugin_helpers_1 = require("@graphql-codegen/plugin-helpers");
5
+ const graphql_1 = require("graphql");
6
+ /** Converts input type to markdown document. */
7
+ const plugin = (schema, _documents, config) => {
8
+ const astNode = (0, plugin_helpers_1.getCachedDocumentNodeFromSchema)(schema);
9
+ const enumStings = new Map();
10
+ const descriptionText = (node) => {
11
+ if (!node.description) {
12
+ console.warn(`Missing description for ${node.name}`);
13
+ }
14
+ return node.description ? `\n\n${node.description}` : '';
15
+ };
16
+ const res = (0, graphql_1.visit)(astNode, {
17
+ Document: {
18
+ leave: (node) => `<!-- auto generated -->${node.definitions.filter(Boolean).join('\n')}`,
19
+ },
20
+ Name: { leave: (node) => node.value },
21
+ NamedType: { leave: (node) => node.name },
22
+ StringValue: { leave: (node) => node.value },
23
+ ListType: { leave: (node) => `[${node.type}]` },
24
+ NonNullType: { leave: (node) => `${node.type}!` },
25
+ InputValueDefinition: {
26
+ leave: (node) => {
27
+ const { type } = node;
28
+ return `\`${node.name}: ${type}\`${descriptionText(node)}`;
29
+ },
30
+ },
31
+ InputObjectTypeDefinition: {
32
+ enter: (node) => ({
33
+ ...node,
34
+ // Move required fields to the top.
35
+ fields: [...(node.fields ?? [])].sort((a, b) => a.type.kind === 'NonNullType' && b.type.kind !== 'NonNullType' ? -1 : 1),
36
+ }),
37
+ leave: (node) => `\n## ${node.name}${descriptionText(node)}
38
+ ${node.fields?.map((f) => `\n### ${f}`).join('\n')}`,
39
+ },
40
+ EnumValueDefinition: {
41
+ leave: (node) => `${node.name} # ${node.description}`,
42
+ },
43
+ EnumTypeDefinition: {
44
+ leave: (node) => {
45
+ enumStings.set(node.name, node.values?.join('\n') || '');
46
+ return '';
47
+ },
48
+ },
49
+ });
50
+ return {
51
+ // prepend: buildImports(),
52
+ content: [res].join('\n'),
53
+ };
54
+ };
55
+ exports.plugin = plugin;
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@graphcommerce/graphql-codegen-markdown-docs",
3
+ "homepage": "https://www.graphcommerce.org/",
4
+ "repository": "github:graphcommerce-org/graphcommerce",
5
+ "version": "6.0.0-canary.20",
6
+ "sideEffects": false,
7
+ "type": "commonjs",
8
+ "main": "dist/index.js",
9
+ "types": "src/index.ts",
10
+ "scripts": {
11
+ "test": "jest",
12
+ "dev": "tsc -W --preserveWatchOutput",
13
+ "build": "tsc",
14
+ "prepack": "tsc"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "src"
19
+ ],
20
+ "prettier": "@graphcommerce/prettier-config-pwa",
21
+ "eslintConfig": {
22
+ "extends": "@graphcommerce/eslint-config-pwa",
23
+ "parserOptions": {
24
+ "project": "./tsconfig.json"
25
+ }
26
+ },
27
+ "devDependencies": {
28
+ "@graphcommerce/eslint-config-pwa": "6.0.0-canary.20",
29
+ "@graphcommerce/prettier-config-pwa": "6.0.0-canary.20",
30
+ "@graphcommerce/typescript-config-pwa": "6.0.0-canary.20"
31
+ },
32
+ "dependencies": {
33
+ "@graphql-codegen/add": "4.0.0",
34
+ "@graphql-codegen/plugin-helpers": "4.0.0",
35
+ "@graphql-codegen/visitor-plugin-common": "3.0.0",
36
+ "@graphql-tools/utils": "^9.2.1",
37
+ "@types/parse-filepath": "^1.0.0",
38
+ "graphql": "16.6.0",
39
+ "parse-filepath": "^1.0.2"
40
+ }
41
+ }
package/src/config.ts ADDED
@@ -0,0 +1,15 @@
1
+ import type { TypeScriptPluginConfig } from '@graphql-codegen/typescript'
2
+
3
+ export interface DirectiveConfig {
4
+ [directive: string]: {
5
+ [argument: string]: string | string[] | DirectiveObjectArguments
6
+ }
7
+ }
8
+
9
+ export interface DirectiveObjectArguments {
10
+ [matched: string]: string | string[]
11
+ }
12
+
13
+ export interface MarkdownDocsPluginConfig extends TypeScriptPluginConfig {
14
+ markdown: boolean
15
+ }
package/src/graphql.ts ADDED
@@ -0,0 +1,28 @@
1
+ import {
2
+ ListTypeNode,
3
+ NonNullTypeNode,
4
+ NamedTypeNode,
5
+ TypeNode,
6
+ ObjectTypeDefinitionNode,
7
+ } from 'graphql'
8
+
9
+ export const isListType = (typ?: TypeNode): typ is ListTypeNode => typ?.kind === 'ListType'
10
+ export const isNonNullType = (typ?: TypeNode): typ is NonNullTypeNode => typ?.kind === 'NonNullType'
11
+ export const isNamedType = (typ?: TypeNode): typ is NamedTypeNode => typ?.kind === 'NamedType'
12
+
13
+ export const isInput = (kind: string) => kind.includes('Input')
14
+
15
+ type ObjectTypeDefinitionFn = (node: ObjectTypeDefinitionNode) => any
16
+
17
+ export const ObjectTypeDefinitionBuilder = (
18
+ useObjectTypes: boolean | undefined,
19
+ callback: ObjectTypeDefinitionFn,
20
+ ): ObjectTypeDefinitionFn | undefined => {
21
+ if (!useObjectTypes) return undefined
22
+ return (node) => {
23
+ if (/^(Query|Mutation|Subscription)$/.test(node.name.value)) {
24
+ return undefined
25
+ }
26
+ return callback(node)
27
+ }
28
+ }
package/src/index.ts ADDED
@@ -0,0 +1,64 @@
1
+ import { PluginFunction, Types } from '@graphql-codegen/plugin-helpers'
2
+ import { getCachedDocumentNodeFromSchema } from '@graphql-codegen/plugin-helpers'
3
+ import { GraphQLSchema, visit } from 'graphql'
4
+ import { MarkdownDocsPluginConfig } from './config'
5
+
6
+ /** Converts input type to markdown document. */
7
+ export const plugin: PluginFunction<MarkdownDocsPluginConfig, Types.ComplexPluginOutput> = (
8
+ schema: GraphQLSchema,
9
+ _documents: Types.DocumentFile[],
10
+ config: MarkdownDocsPluginConfig,
11
+ ): Types.ComplexPluginOutput => {
12
+ const astNode = getCachedDocumentNodeFromSchema(schema)
13
+
14
+ const enumStings = new Map<string, string>()
15
+
16
+ const descriptionText = (node: { description?: string; name: string }) => {
17
+ if (!node.description) {
18
+ console.warn(`Missing description for ${node.name}`)
19
+ }
20
+ return node.description ? `\n\n${node.description}` : ''
21
+ }
22
+
23
+ const res = visit<string>(astNode, {
24
+ Document: {
25
+ leave: (node) => `<!-- auto generated -->${node.definitions.filter(Boolean).join('\n')}`,
26
+ },
27
+ Name: { leave: (node) => node.value },
28
+ NamedType: { leave: (node) => node.name }, // String, Boolean, GraphCommerceDebugConfig, etc.
29
+ StringValue: { leave: (node) => node.value },
30
+ ListType: { leave: (node) => `[${node.type}]` },
31
+ NonNullType: { leave: (node) => `${node.type}!` },
32
+ InputValueDefinition: {
33
+ leave: (node) => {
34
+ const { type } = node
35
+ return `\`${node.name}: ${type}\`${descriptionText(node)}`
36
+ },
37
+ },
38
+ InputObjectTypeDefinition: {
39
+ enter: (node) => ({
40
+ ...node,
41
+ // Move required fields to the top.
42
+ fields: [...(node.fields ?? [])].sort((a, b) =>
43
+ a.type.kind === 'NonNullType' && b.type.kind !== 'NonNullType' ? -1 : 1,
44
+ ),
45
+ }),
46
+ leave: (node) => `\n## ${node.name}${descriptionText(node)}
47
+ ${node.fields?.map((f) => `\n### ${f}`).join('\n')}`,
48
+ },
49
+ EnumValueDefinition: {
50
+ leave: (node) => `${node.name} # ${node.description}`,
51
+ },
52
+ EnumTypeDefinition: {
53
+ leave: (node) => {
54
+ enumStings.set(node.name, node.values?.join('\n') || '')
55
+ return ''
56
+ },
57
+ },
58
+ })
59
+
60
+ return {
61
+ // prepend: buildImports(),
62
+ content: [res].join('\n'),
63
+ }
64
+ }