@graphcommerce/graphql-codegen-near-operation-file 2.102.2 → 2.103.2

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,173 @@
1
+ /* eslint-disable import/no-cycle */
2
+ import { resolve } from 'path'
3
+ import { isUsingTypes, Types, DetailedError } from '@graphql-codegen/plugin-helpers'
4
+ import {
5
+ generateImportStatement,
6
+ ImportSource,
7
+ resolveImportSource,
8
+ FragmentImport,
9
+ ImportDeclaration,
10
+ LoadedFragment,
11
+ } from '@graphql-codegen/visitor-plugin-common'
12
+ import { Source } from '@graphql-tools/utils'
13
+ import { FragmentDefinitionNode, GraphQLSchema, visit } from 'graphql'
14
+ import buildFragmentResolver, { buildFragmentRegistry } from './fragment-resolver'
15
+ import { extractExternalFragmentsInUse } from './utils'
16
+
17
+ export type FragmentRegistry = {
18
+ [fragmentName: string]: {
19
+ location: string
20
+ importNames: string[]
21
+ onType: string
22
+ node: FragmentDefinitionNode
23
+ }
24
+ }
25
+
26
+ export type DocumentImportResolverOptions = {
27
+ baseDir: string
28
+ /** Generates a target file path from the source `document.location` */
29
+ generateFilePath: (location: string) => string
30
+ /** Schema base types source */
31
+ schemaTypesSource: string | ImportSource
32
+ /** Should `import type` be used */
33
+ typesImport: boolean
34
+ }
35
+
36
+ interface ResolveDocumentImportResult {
37
+ filename: string
38
+ documents: Source[]
39
+ importStatements: string[]
40
+ fragmentImports: ImportDeclaration<FragmentImport>[]
41
+ externalFragments: LoadedFragment<{
42
+ level: number
43
+ }>[]
44
+ }
45
+
46
+ function getFragmentName(documentFile: Types.DocumentFile) {
47
+ let name: string | undefined
48
+ visit(documentFile.document!, {
49
+ enter: {
50
+ FragmentDefinition: (node: FragmentDefinitionNode) => {
51
+ name = node.name.value
52
+ },
53
+ },
54
+ })
55
+ return name
56
+ }
57
+
58
+ /**
59
+ * Transform the preset's provided documents into single-file generator sources, while resolving
60
+ * fragment and user-defined imports
61
+ *
62
+ * Resolves user provided imports and fragment imports using the `DocumentImportResolverOptions`.
63
+ * Does not define specific plugins, but rather returns a string[] of `importStatements` for the
64
+ * calling plugin to make use of
65
+ */
66
+ export function resolveDocumentImports<T>(
67
+ presetOptions: Types.PresetFnArgs<T>,
68
+ schemaObject: GraphQLSchema,
69
+ importResolverOptions: DocumentImportResolverOptions,
70
+ ): Array<ResolveDocumentImportResult> {
71
+ const { baseOutputDir, documents, pluginMap } = presetOptions
72
+ const { generateFilePath, schemaTypesSource, baseDir, typesImport } = importResolverOptions
73
+
74
+ const resolveFragments = buildFragmentResolver(importResolverOptions, presetOptions, schemaObject)
75
+ const fragmentRegistry = buildFragmentRegistry(importResolverOptions, presetOptions, schemaObject)
76
+
77
+ const isRelayOptimizer = !!Object.keys(pluginMap).find((plugin) =>
78
+ plugin.includes('relay-optimizer-plugin'),
79
+ )
80
+
81
+ const resDocuments = documents.map((documentFile) => {
82
+ try {
83
+ const isFragment = typeof getFragmentName(documentFile) !== 'undefined'
84
+
85
+ if (!isFragment && isRelayOptimizer) {
86
+ const generatedFilePath = generateFilePath(documentFile.location!)
87
+
88
+ let externalFragments = extractExternalFragmentsInUse(
89
+ documentFile.document!,
90
+ fragmentRegistry,
91
+ )
92
+ // Sort the entries in the right order so fragments are defined when using
93
+ externalFragments = Object.fromEntries(
94
+ Object.entries(externalFragments).sort(([, levelA], [, levelB]) => levelB - levelA),
95
+ )
96
+
97
+ const fragments = documents.filter(
98
+ (d) => typeof externalFragments[getFragmentName(d) ?? ''] !== 'undefined',
99
+ )
100
+
101
+ const importStatements: string[] = []
102
+
103
+ if (isUsingTypes(documentFile.document!, [], schemaObject)) {
104
+ const schemaTypesImportStatement = generateImportStatement({
105
+ baseDir,
106
+ importSource: resolveImportSource(schemaTypesSource),
107
+ baseOutputDir,
108
+ outputPath: generatedFilePath,
109
+ typesImport,
110
+ })
111
+ importStatements.unshift(schemaTypesImportStatement)
112
+ }
113
+
114
+ // const newDocument = [...fragments.map((f) => f.rawSDL), documentFile.rawSDL].join('\n')
115
+
116
+ return {
117
+ filename: generatedFilePath,
118
+ documents: [...fragments, documentFile],
119
+ importStatements,
120
+ fragmentImports: [],
121
+ externalFragments: [],
122
+ } as ResolveDocumentImportResult
123
+ }
124
+
125
+ const generatedFilePath = generateFilePath(documentFile.location!)
126
+ const importStatements: string[] = []
127
+ const { externalFragments, fragmentImports } = resolveFragments(
128
+ generatedFilePath,
129
+ documentFile.document!,
130
+ )
131
+
132
+ if (
133
+ isRelayOptimizer ||
134
+ isUsingTypes(
135
+ documentFile.document!,
136
+ externalFragments.map((m) => m.name),
137
+ schemaObject,
138
+ )
139
+ ) {
140
+ const schemaTypesImportStatement = generateImportStatement({
141
+ baseDir,
142
+ importSource: resolveImportSource(schemaTypesSource),
143
+ baseOutputDir,
144
+ outputPath: generatedFilePath,
145
+ typesImport,
146
+ })
147
+ importStatements.unshift(schemaTypesImportStatement)
148
+ }
149
+
150
+ return {
151
+ filename: generatedFilePath,
152
+ documents: [documentFile],
153
+ importStatements,
154
+ fragmentImports,
155
+ externalFragments,
156
+ }
157
+ } catch (e) {
158
+ if (e instanceof Error) {
159
+ throw new DetailedError(
160
+ `Unable to validate GraphQL document!`,
161
+ `File ${documentFile.location} caused error: ${e.message || e.toString()}`,
162
+ documentFile.location,
163
+ )
164
+ } else {
165
+ throw e
166
+ }
167
+ }
168
+ })
169
+
170
+ return resDocuments.filter((result) =>
171
+ result.filename.startsWith(resolve(baseDir, baseOutputDir)),
172
+ )
173
+ }
@@ -0,0 +1,3 @@
1
+ fragment InjectableFragment on StoreConfig @injectable {
2
+ store_code
3
+ }
@@ -0,0 +1,3 @@
1
+ fragment InjectingFragment on StoreConfig @inject(into: ["InjectableFragment"]) {
2
+ base_url
3
+ }
@@ -0,0 +1,5 @@
1
+ query QueryWitInjectable {
2
+ storeConfig {
3
+ ...InjectableFragment
4
+ }
5
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,61 @@
1
+ /* eslint-disable import/no-cycle */
2
+ import { join } from 'path'
3
+ import { DocumentNode, visit, FragmentSpreadNode, FragmentDefinitionNode } from 'graphql'
4
+ import parsePath from 'parse-filepath'
5
+ import { FragmentRegistry } from './fragment-resolver'
6
+
7
+ export function defineFilepathSubfolder(baseFilePath: string, folder: string) {
8
+ const parsedPath = parsePath(baseFilePath)
9
+ return join(parsedPath.dir, folder, parsedPath.base).replace(/\\/g, '/')
10
+ }
11
+
12
+ export function appendExtensionToFilePath(baseFilePath: string, extension: string) {
13
+ const parsedPath = parsePath(baseFilePath)
14
+
15
+ return join(parsedPath.dir, parsedPath.name + extension).replace(/\\/g, '/')
16
+ }
17
+
18
+ export function extractExternalFragmentsInUse(
19
+ documentNode: DocumentNode | FragmentDefinitionNode,
20
+ fragmentNameToFile: FragmentRegistry,
21
+ result: { [fragmentName: string]: number } = {},
22
+ level = 0,
23
+ ): { [fragmentName: string]: number } {
24
+ const ignoreList: Set<string> = new Set()
25
+
26
+ // First, take all fragments definition from the current file, and mark them as ignored
27
+ visit(documentNode, {
28
+ enter: {
29
+ FragmentDefinition: (node: FragmentDefinitionNode) => {
30
+ ignoreList.add(node.name.value)
31
+ },
32
+ },
33
+ })
34
+
35
+ // Then, look for all used fragments in this document
36
+ visit(documentNode, {
37
+ enter: {
38
+ FragmentSpread: (node: FragmentSpreadNode) => {
39
+ if (!ignoreList.has(node.name.value)) {
40
+ if (
41
+ result[node.name.value] === undefined ||
42
+ (result[node.name.value] !== undefined && level < result[node.name.value])
43
+ ) {
44
+ result[node.name.value] = level
45
+
46
+ if (fragmentNameToFile[node.name.value]) {
47
+ extractExternalFragmentsInUse(
48
+ fragmentNameToFile[node.name.value].node,
49
+ fragmentNameToFile,
50
+ result,
51
+ level + 1,
52
+ )
53
+ }
54
+ }
55
+ }
56
+ },
57
+ },
58
+ })
59
+
60
+ return result
61
+ }