@stepzen/transpiler 0.0.33 → 0.0.36
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/LICENSE +1 -1
- package/lib/actions/configure.js +15 -14
- package/lib/actions/configure.js.map +1 -0
- package/lib/actions/lint.js +6 -5
- package/lib/actions/lint.js.map +1 -0
- package/lib/actions/merge.d.ts +2 -0
- package/lib/actions/merge.js +80 -70
- package/lib/actions/merge.js.map +1 -0
- package/lib/actions/print.d.ts +1 -1
- package/lib/actions/print.js +2 -1
- package/lib/actions/print.js.map +1 -0
- package/lib/actions/stitch.js +14 -13
- package/lib/actions/stitch.js.map +1 -0
- package/lib/actions/transpile.js +7 -6
- package/lib/actions/transpile.js.map +1 -0
- package/lib/actions/validate.js +4 -3
- package/lib/actions/validate.js.map +1 -0
- package/lib/index.d.ts +7 -1
- package/lib/index.js +16 -16
- package/lib/index.js.map +1 -0
- package/lib/mutations/config/envvars.js +3 -2
- package/lib/mutations/config/envvars.js.map +1 -0
- package/lib/mutations/config/index.js +1 -0
- package/lib/mutations/config/index.js.map +1 -0
- package/lib/utils/constants.js +2 -1
- package/lib/utils/constants.js.map +1 -0
- package/lib/utils/dedupe-query-and-mutation-types.js +7 -6
- package/lib/utils/dedupe-query-and-mutation-types.js.map +1 -0
- package/lib/utils/ensure-query-and-mutation-types.d.ts +1 -1
- package/lib/utils/ensure-query-and-mutation-types.js +7 -6
- package/lib/utils/ensure-query-and-mutation-types.js.map +1 -0
- package/lib/utils/graphql-helpers.js +1 -0
- package/lib/utils/graphql-helpers.js.map +1 -0
- package/lib/utils/merge-helpers.d.ts +2 -1
- package/lib/utils/merge-helpers.js +16 -5
- package/lib/utils/merge-helpers.js.map +1 -0
- package/lib/utils/set-files-in-sdl.js +9 -8
- package/lib/utils/set-files-in-sdl.js.map +1 -0
- package/lib/utils/strip-empty-queries-and-mutations.d.ts +1 -1
- package/lib/utils/strip-empty-queries-and-mutations.js +7 -6
- package/lib/utils/strip-empty-queries-and-mutations.js.map +1 -0
- package/lib/validators/config-exists/index.d.ts +1 -1
- package/lib/validators/config-exists/index.js +11 -10
- package/lib/validators/config-exists/index.js.map +1 -0
- package/lib/validators/index.js +1 -0
- package/lib/validators/index.js.map +1 -0
- package/package.json +24 -16
- package/src/actions/configure.ts +120 -0
- package/src/actions/lint.ts +45 -0
- package/src/actions/merge.ts +202 -0
- package/src/actions/print.ts +8 -0
- package/src/actions/stitch.ts +105 -0
- package/src/actions/transpile.ts +70 -0
- package/src/actions/validate.ts +54 -0
- package/src/index.ts +7 -0
- package/src/mutations/config/envvars.ts +17 -0
- package/src/mutations/config/index.ts +3 -0
- package/src/utils/constants.ts +16 -0
- package/src/utils/dedupe-query-and-mutation-types.ts +74 -0
- package/src/utils/ensure-query-and-mutation-types.ts +52 -0
- package/src/utils/graphql-helpers.ts +3 -0
- package/src/utils/merge-helpers.ts +187 -0
- package/src/utils/set-files-in-sdl.ts +40 -0
- package/src/utils/strip-empty-queries-and-mutations.ts +43 -0
- package/src/validators/config-exists/index.ts +54 -0
- package/src/validators/index.ts +3 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import * as fs from 'fs-extra'
|
|
2
|
+
import * as glob from 'glob'
|
|
3
|
+
import {mergeTypeDefs} from '@graphql-tools/merge'
|
|
4
|
+
import {parse, visit} from 'graphql'
|
|
5
|
+
import * as os from 'os'
|
|
6
|
+
import * as path from 'path'
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
dedupeTempFolder,
|
|
10
|
+
findQueryMutationInSchema,
|
|
11
|
+
findTypeInSchema,
|
|
12
|
+
getSchema,
|
|
13
|
+
mergeQueryMutationIntoSchema,
|
|
14
|
+
removeQueryMutationFromSchema,
|
|
15
|
+
mergeTypeIntoSchema,
|
|
16
|
+
removeTypeFromSchema,
|
|
17
|
+
getConfiguration,
|
|
18
|
+
findNextAvailableSubfolder,
|
|
19
|
+
} from '../utils/merge-helpers'
|
|
20
|
+
import print from './print'
|
|
21
|
+
import setFilesInSDL from '../utils/set-files-in-sdl'
|
|
22
|
+
import stripEmptyQueriesAndMutations from '../utils/strip-empty-queries-and-mutations'
|
|
23
|
+
|
|
24
|
+
const BLANK_INDEX_TEMPLATE = `
|
|
25
|
+
schema @sdl(files: []) {
|
|
26
|
+
query: Query
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type Query {
|
|
30
|
+
__query: String
|
|
31
|
+
}
|
|
32
|
+
`.trim()
|
|
33
|
+
|
|
34
|
+
export default async (
|
|
35
|
+
original: string,
|
|
36
|
+
imported: {
|
|
37
|
+
name: string
|
|
38
|
+
source: string
|
|
39
|
+
},
|
|
40
|
+
options: {
|
|
41
|
+
answers: any
|
|
42
|
+
output: string | null
|
|
43
|
+
silent: boolean
|
|
44
|
+
/** when `false` merge only covers config files and updates @sdl directrive */
|
|
45
|
+
mergeTypes?: boolean
|
|
46
|
+
} = {
|
|
47
|
+
answers: {},
|
|
48
|
+
output: null,
|
|
49
|
+
silent: false,
|
|
50
|
+
mergeTypes: true,
|
|
51
|
+
},
|
|
52
|
+
) => {
|
|
53
|
+
// Make sure there is an output directory
|
|
54
|
+
if (!options.answers) options.answers = {}
|
|
55
|
+
if (!options.output)
|
|
56
|
+
options.output = path.join(os.tmpdir(), `stepzen-tmp-${Date.now()}`)
|
|
57
|
+
if (!options.silent) options.silent = false
|
|
58
|
+
if (options.mergeTypes === undefined) options.mergeTypes = true
|
|
59
|
+
|
|
60
|
+
// To stop things like
|
|
61
|
+
// C:\Users\Darren\AppData\Local\Temp\stepzen-tmp-config-1638293497187\C:\Users\Darren\AppData\Local\Temp\stepzen-tmp-1638293496286
|
|
62
|
+
options.output = dedupeTempFolder(options.output)
|
|
63
|
+
|
|
64
|
+
// Ensure original, importing and output directories exist
|
|
65
|
+
if (!fs.existsSync(original))
|
|
66
|
+
throw new Error(`Cannot find original directory ${original}`)
|
|
67
|
+
if (!fs.existsSync(imported.source))
|
|
68
|
+
throw new Error(`Cannot find imported source directory ${imported.source}`)
|
|
69
|
+
fs.ensureDirSync(options.output)
|
|
70
|
+
|
|
71
|
+
// Copy the original into the output.
|
|
72
|
+
fs.copySync(original, options.output)
|
|
73
|
+
|
|
74
|
+
// Ensure an index.graphql exists
|
|
75
|
+
const outputIndex = path.join(options.output, 'index.graphql')
|
|
76
|
+
if (!fs.existsSync(outputIndex)) {
|
|
77
|
+
fs.writeFileSync(outputIndex, BLANK_INDEX_TEMPLATE)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const targetSubfolder = findNextAvailableSubfolder(original, imported.name)
|
|
81
|
+
|
|
82
|
+
if (options.mergeTypes) {
|
|
83
|
+
const merged = mergeTypeDefs([
|
|
84
|
+
await getSchema(options.output),
|
|
85
|
+
await getSchema(imported.source),
|
|
86
|
+
])
|
|
87
|
+
|
|
88
|
+
let queries: any[] = []
|
|
89
|
+
let mutations: any[] = []
|
|
90
|
+
let types: any[] = []
|
|
91
|
+
|
|
92
|
+
visit(merged, {
|
|
93
|
+
ObjectTypeDefinition(node) {
|
|
94
|
+
if (node.name.value === 'Query') queries = queries.concat(node.fields)
|
|
95
|
+
else if (node.name.value === 'Mutation')
|
|
96
|
+
mutations = mutations.concat(node.fields)
|
|
97
|
+
else types = types.concat(node)
|
|
98
|
+
},
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
const details = {
|
|
102
|
+
original: glob.sync('**/*.graphql', {cwd: options.output}).map(file => {
|
|
103
|
+
const content = fs.readFileSync(`${options.output}/${file}`, 'utf8')
|
|
104
|
+
return {ast: parse(content), file}
|
|
105
|
+
}),
|
|
106
|
+
imported: glob.sync('**/*.graphql', {cwd: imported.source}).map(file => {
|
|
107
|
+
const content = fs.readFileSync(`${imported.source}/${file}`, 'utf8')
|
|
108
|
+
return {ast: parse(content), file}
|
|
109
|
+
}),
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Merge Queries and Mutations
|
|
113
|
+
for (const type of [...queries, ...mutations]) {
|
|
114
|
+
const isInOriginal = findQueryMutationInSchema(
|
|
115
|
+
type.name.value,
|
|
116
|
+
details.original,
|
|
117
|
+
)
|
|
118
|
+
const isInImported = findQueryMutationInSchema(
|
|
119
|
+
type.name.value,
|
|
120
|
+
details.imported,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
if (isInOriginal && isInImported) {
|
|
124
|
+
details.original = mergeQueryMutationIntoSchema(type, details.original)
|
|
125
|
+
details.imported = removeQueryMutationFromSchema(
|
|
126
|
+
type.name.value,
|
|
127
|
+
details.imported,
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Merge Types
|
|
133
|
+
for (const type of types) {
|
|
134
|
+
const isInOriginal = findTypeInSchema(type.name.value, details.original)
|
|
135
|
+
const isInImported = findTypeInSchema(type.name.value, details.imported)
|
|
136
|
+
|
|
137
|
+
if (isInOriginal && isInImported) {
|
|
138
|
+
details.original = mergeTypeIntoSchema(type, details.original)
|
|
139
|
+
details.imported = removeTypeFromSchema(
|
|
140
|
+
type.name.value,
|
|
141
|
+
details.imported,
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Clean up the files. Remove empty Query / Mutation types, filter out now-empty files
|
|
147
|
+
const cleaned = {
|
|
148
|
+
original: details.original
|
|
149
|
+
.map(item => ({
|
|
150
|
+
...item,
|
|
151
|
+
ast: stripEmptyQueriesAndMutations(item.ast),
|
|
152
|
+
}))
|
|
153
|
+
.filter(item => item.ast.definitions.length > 0),
|
|
154
|
+
imported: details.imported
|
|
155
|
+
.map(item => ({
|
|
156
|
+
...item,
|
|
157
|
+
ast: stripEmptyQueriesAndMutations(item.ast),
|
|
158
|
+
}))
|
|
159
|
+
.filter(item => item.ast.definitions.length > 0),
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Write the files to the output directory
|
|
163
|
+
cleaned.original.forEach((a: any) => {
|
|
164
|
+
// eslint-disable-next-line
|
|
165
|
+
const file = path.join(options.output as any, a.file)
|
|
166
|
+
const deduped = dedupeTempFolder(file)
|
|
167
|
+
|
|
168
|
+
fs.ensureFileSync(deduped)
|
|
169
|
+
fs.writeFileSync(deduped, print(a.ast))
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
cleaned.imported.forEach(a => {
|
|
173
|
+
// eslint-disable-next-line
|
|
174
|
+
const file = path.join(options.output as any, targetSubfolder, a.file)
|
|
175
|
+
const deduped = dedupeTempFolder(file)
|
|
176
|
+
|
|
177
|
+
fs.ensureFileSync(deduped)
|
|
178
|
+
fs.writeFileSync(deduped, print(a.ast))
|
|
179
|
+
})
|
|
180
|
+
} else {
|
|
181
|
+
// Write the files to the output directory
|
|
182
|
+
fs.copySync(original, options.output)
|
|
183
|
+
fs.copySync(imported.source, path.join(options.output, targetSubfolder))
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Make sure all files are referenced in @sdl
|
|
187
|
+
setFilesInSDL(options.output)
|
|
188
|
+
|
|
189
|
+
// Generate configuration
|
|
190
|
+
const config = await getConfiguration(
|
|
191
|
+
[options.output, imported.source],
|
|
192
|
+
options.silent,
|
|
193
|
+
options.answers,
|
|
194
|
+
)
|
|
195
|
+
if (config) {
|
|
196
|
+
const configFile = path.join(options.output, 'config.yaml')
|
|
197
|
+
fs.writeFileSync(configFile, config as string)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Return a merged schema!
|
|
201
|
+
return options.output
|
|
202
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {clone, cloneDeep} from 'lodash'
|
|
2
|
+
import {parse, print, visit} from 'graphql'
|
|
3
|
+
import * as fs from 'fs-extra'
|
|
4
|
+
import * as glob from 'glob'
|
|
5
|
+
import * as os from 'os'
|
|
6
|
+
import * as path from 'path'
|
|
7
|
+
import * as prettier from 'prettier'
|
|
8
|
+
|
|
9
|
+
import dedupeQueryAndMutationTypes from '../utils/dedupe-query-and-mutation-types'
|
|
10
|
+
|
|
11
|
+
export default (
|
|
12
|
+
source: string,
|
|
13
|
+
output: string = path.join(os.tmpdir(), `stepzen-tmp-${Date.now()}`),
|
|
14
|
+
) => {
|
|
15
|
+
// Ensure source and output directories exist
|
|
16
|
+
if (!fs.existsSync(source))
|
|
17
|
+
throw new Error(`Cannot find source directory ${source}`)
|
|
18
|
+
fs.ensureDirSync(output)
|
|
19
|
+
|
|
20
|
+
// Get a list of files.
|
|
21
|
+
let ast: any
|
|
22
|
+
let files: string[] = []
|
|
23
|
+
|
|
24
|
+
// If there's an index.graphQL - get files argument in @sdl directive
|
|
25
|
+
const sourceIndex = path.join(source, 'index.graphql')
|
|
26
|
+
|
|
27
|
+
if (fs.existsSync(sourceIndex)) {
|
|
28
|
+
const index = fs.readFileSync(sourceIndex, 'utf8')
|
|
29
|
+
ast = parse(index)
|
|
30
|
+
ast = visit(ast, {
|
|
31
|
+
Directive(node) {
|
|
32
|
+
if (node.name.value === 'sdl') {
|
|
33
|
+
const list = node.arguments?.find(
|
|
34
|
+
(arg: any) => arg.name.value === 'files',
|
|
35
|
+
)
|
|
36
|
+
// If we find a 'files' argument, we copy the list, and remove the argument
|
|
37
|
+
if (list) {
|
|
38
|
+
const copy: any = clone(list.value)
|
|
39
|
+
for (const file of copy.values) {
|
|
40
|
+
files = files.concat(file.value)
|
|
41
|
+
}
|
|
42
|
+
const mutated: any = cloneDeep(node)
|
|
43
|
+
mutated.arguments = mutated.arguments.filter(
|
|
44
|
+
(arg: any) => arg.name.value !== 'files',
|
|
45
|
+
)
|
|
46
|
+
return mutated
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
} else {
|
|
52
|
+
const content = glob
|
|
53
|
+
.sync('**/*.graphql', {cwd: source})
|
|
54
|
+
.map((file: string) => {
|
|
55
|
+
const graphql = fs.readFileSync(`${source}/${file}`, 'utf8')
|
|
56
|
+
return graphql
|
|
57
|
+
})
|
|
58
|
+
ast = parse(content.join(os.EOL))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Strip @sdl directive
|
|
62
|
+
ast = visit(ast, {
|
|
63
|
+
Directive(node) {
|
|
64
|
+
if (node.name.value === 'sdl') return null
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// Check all the files exist
|
|
69
|
+
for (const file of files) {
|
|
70
|
+
const find = path.join(source, file)
|
|
71
|
+
if (!fs.existsSync(find)) {
|
|
72
|
+
throw new Error(`Cannot find file ${find}`)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Get all the files and stitch
|
|
77
|
+
const printed = print(ast)
|
|
78
|
+
let stitched = `${printed}${os.EOL}`
|
|
79
|
+
for (const file of files) {
|
|
80
|
+
const find = path.join(source, file)
|
|
81
|
+
const content = fs.readFileSync(find, 'utf8')
|
|
82
|
+
stitched += `${content}${os.EOL}`
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Dedupe Query and Mutation types
|
|
86
|
+
stitched = dedupeQueryAndMutationTypes(stitched)
|
|
87
|
+
|
|
88
|
+
// Format
|
|
89
|
+
stitched = prettier.format(stitched, {parser: 'graphql'})
|
|
90
|
+
|
|
91
|
+
// Write to output folder
|
|
92
|
+
const outputIndex = path.join(output, 'index.graphql')
|
|
93
|
+
fs.writeFileSync(outputIndex, stitched)
|
|
94
|
+
|
|
95
|
+
// Copy config if exists, too
|
|
96
|
+
const sourceConfig = path.join(source, 'config.yaml')
|
|
97
|
+
const outputConfig = path.join(output, 'config.yaml')
|
|
98
|
+
|
|
99
|
+
if (fs.existsSync(sourceConfig)) {
|
|
100
|
+
fs.copyFileSync(sourceConfig, outputConfig)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Return output folder
|
|
104
|
+
return output
|
|
105
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {DocumentNode, parse} from 'graphql'
|
|
2
|
+
import * as dotenv from 'dotenv'
|
|
3
|
+
import * as fs from 'fs'
|
|
4
|
+
import * as glob from 'glob'
|
|
5
|
+
import * as path from 'path'
|
|
6
|
+
|
|
7
|
+
import print from '../actions/print'
|
|
8
|
+
import stitch from '../actions/stitch'
|
|
9
|
+
import configure from './configure'
|
|
10
|
+
|
|
11
|
+
import configMutations from '../mutations/config'
|
|
12
|
+
|
|
13
|
+
export default async (source: string) => {
|
|
14
|
+
// Ensure source and output directories exist
|
|
15
|
+
if (!fs.existsSync(source)) {
|
|
16
|
+
throw new Error(`Cannot find source directory ${source}`)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Load env vars, from working and source directories
|
|
20
|
+
dotenv.config()
|
|
21
|
+
dotenv.config({path: path.resolve(source, '.env')})
|
|
22
|
+
|
|
23
|
+
// State of whether we've transpiled or not
|
|
24
|
+
let transpiledConfig = false
|
|
25
|
+
let transpiledGraphQL = false
|
|
26
|
+
|
|
27
|
+
// See whether to transpile config
|
|
28
|
+
let config: any = await configure(source, true)
|
|
29
|
+
const configCopy = config
|
|
30
|
+
|
|
31
|
+
if (config) {
|
|
32
|
+
for await (const mutation of configMutations) {
|
|
33
|
+
config = await mutation(config)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (configCopy !== config) {
|
|
38
|
+
transpiledConfig = true
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// See whether to transpile GraphQL
|
|
42
|
+
const graphqlFiles = glob.sync('**/*.graphql', {cwd: source})
|
|
43
|
+
let original: any = ''
|
|
44
|
+
let mutated: any = ''
|
|
45
|
+
|
|
46
|
+
if (graphqlFiles.length > 0) {
|
|
47
|
+
const stitched = await stitch(source)
|
|
48
|
+
|
|
49
|
+
const index = path.join(stitched, 'index.graphql')
|
|
50
|
+
|
|
51
|
+
const graphql = fs.readFileSync(index, 'utf8')
|
|
52
|
+
|
|
53
|
+
let ast: DocumentNode = parse(graphql)
|
|
54
|
+
original = parse(graphql)
|
|
55
|
+
|
|
56
|
+
// you can transpile schema ast here
|
|
57
|
+
|
|
58
|
+
mutated = print(ast)
|
|
59
|
+
|
|
60
|
+
if (print(original) !== mutated) {
|
|
61
|
+
transpiledGraphQL = true
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
config,
|
|
67
|
+
schema: mutated,
|
|
68
|
+
transpiled: transpiledConfig || transpiledGraphQL,
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {buildASTSchema, DocumentNode, parse, print} from 'graphql'
|
|
2
|
+
import * as fs from 'fs-extra'
|
|
3
|
+
import * as os from 'os'
|
|
4
|
+
import * as path from 'path'
|
|
5
|
+
|
|
6
|
+
import ensureQueryAndMutationTypes from '../utils/ensure-query-and-mutation-types'
|
|
7
|
+
import {EXPERIMENTAL_EXTENSIONS} from '../utils/constants'
|
|
8
|
+
import validators from '../validators'
|
|
9
|
+
|
|
10
|
+
export default (
|
|
11
|
+
source: string,
|
|
12
|
+
options: {
|
|
13
|
+
extensions: string
|
|
14
|
+
} = {
|
|
15
|
+
extensions: '',
|
|
16
|
+
},
|
|
17
|
+
) => {
|
|
18
|
+
// Ensure source and output directories exist
|
|
19
|
+
if (!fs.existsSync(source)) {
|
|
20
|
+
throw new Error(`Cannot find source directory ${source}`)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Ensure index.graphql exists
|
|
24
|
+
if (!fs.existsSync(`${source}/index.graphql`)) {
|
|
25
|
+
throw new Error(`Cannot find index.graphql in ${source}`)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Get the index.graphql file
|
|
29
|
+
const file = path.join(source, 'index.graphql')
|
|
30
|
+
const index = fs.readFileSync(file, 'utf8')
|
|
31
|
+
|
|
32
|
+
// Parse
|
|
33
|
+
let ast: DocumentNode = parse(
|
|
34
|
+
`${EXPERIMENTAL_EXTENSIONS}${os.EOL}${options.extensions}${os.EOL}${index}`,
|
|
35
|
+
{
|
|
36
|
+
noLocation: true,
|
|
37
|
+
},
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
// We make an exception for 'no type Query' or 'no type Mutation'
|
|
41
|
+
ast = ensureQueryAndMutationTypes(ast)
|
|
42
|
+
|
|
43
|
+
// Build and print, to validate
|
|
44
|
+
buildASTSchema(ast)
|
|
45
|
+
print(ast)
|
|
46
|
+
|
|
47
|
+
// Custom validators
|
|
48
|
+
for (const validator of validators) {
|
|
49
|
+
validator(ast, source)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Return true
|
|
53
|
+
return true
|
|
54
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export {default as configure} from './actions/configure'
|
|
2
|
+
export {default as lint} from './actions/lint'
|
|
3
|
+
export {default as merge} from './actions/merge'
|
|
4
|
+
export {default as print} from './actions/print'
|
|
5
|
+
export {default as stitch} from './actions/stitch'
|
|
6
|
+
export {default as transpile} from './actions/transpile'
|
|
7
|
+
export {default as validate} from './actions/validate'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export default async (config: string): Promise<string> => {
|
|
2
|
+
const envvars = Object.keys(process.env)
|
|
3
|
+
.filter(key => {
|
|
4
|
+
return key.startsWith(`STEPZEN_`)
|
|
5
|
+
})
|
|
6
|
+
.reduce((obj: any, key) => {
|
|
7
|
+
obj[key] = process.env[key]
|
|
8
|
+
return obj
|
|
9
|
+
}, {})
|
|
10
|
+
|
|
11
|
+
for (const [key, value] of Object.entries(envvars)) {
|
|
12
|
+
const regex = new RegExp(key, 'g')
|
|
13
|
+
config = config.replace(regex, `${value}`)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return config
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as dotenv from 'dotenv'
|
|
2
|
+
|
|
3
|
+
dotenv.config()
|
|
4
|
+
|
|
5
|
+
const {STEPZEN_DOMAIN: ENV_VAR_STEPZEN_DOMAIN} = process.env
|
|
6
|
+
|
|
7
|
+
export const EXPERIMENTAL_EXTENSIONS = `
|
|
8
|
+
directive @experimental(
|
|
9
|
+
debug: Boolean
|
|
10
|
+
function: String
|
|
11
|
+
mock: String
|
|
12
|
+
setter: String
|
|
13
|
+
) on OBJECT | FIELD_DEFINITION
|
|
14
|
+
`
|
|
15
|
+
|
|
16
|
+
export const STEPZEN_DOMAIN = ENV_VAR_STEPZEN_DOMAIN || 'stepzen.io'
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {DocumentNode, parse, print, visit} from 'graphql'
|
|
2
|
+
|
|
3
|
+
import {cloneDeep} from '../utils/graphql-helpers'
|
|
4
|
+
|
|
5
|
+
export default (schema: string): string => {
|
|
6
|
+
let ast: DocumentNode = parse(schema)
|
|
7
|
+
|
|
8
|
+
let queries: any = []
|
|
9
|
+
let mutations: any = []
|
|
10
|
+
|
|
11
|
+
// Loop through the AST and find Query and Mutation types.
|
|
12
|
+
// Store their fields.
|
|
13
|
+
// Return null to remove it from the tree
|
|
14
|
+
ast = visit(ast, {
|
|
15
|
+
ObjectTypeDefinition: {
|
|
16
|
+
enter(node) {
|
|
17
|
+
if (node.name.kind === 'Name' && node.name.value === 'Query') {
|
|
18
|
+
queries = queries.concat(node.fields)
|
|
19
|
+
return null
|
|
20
|
+
}
|
|
21
|
+
if (node.name.kind === 'Name' && node.name.value === 'Mutation') {
|
|
22
|
+
mutations = mutations.concat(node.fields)
|
|
23
|
+
return null
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
// This is the template for the new Query type
|
|
30
|
+
const queryTemplate = {
|
|
31
|
+
kind: 'ObjectTypeDefinition',
|
|
32
|
+
description: undefined,
|
|
33
|
+
name: {kind: 'Name', value: 'Query'},
|
|
34
|
+
interfaces: [],
|
|
35
|
+
directives: [],
|
|
36
|
+
fields: [],
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// This is the template for the new Mutation type
|
|
40
|
+
const mutationTemplate = {
|
|
41
|
+
kind: 'ObjectTypeDefinition',
|
|
42
|
+
description: undefined,
|
|
43
|
+
name: {kind: 'Name', value: 'Mutation'},
|
|
44
|
+
interfaces: [],
|
|
45
|
+
directives: [],
|
|
46
|
+
fields: [],
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// If there are queries, add a single Query type
|
|
50
|
+
// with all the concatenated queries
|
|
51
|
+
if (queries.length > 0) {
|
|
52
|
+
const mutated: any = cloneDeep(ast)
|
|
53
|
+
const query = {
|
|
54
|
+
...queryTemplate,
|
|
55
|
+
fields: queries,
|
|
56
|
+
}
|
|
57
|
+
mutated.definitions.push(query)
|
|
58
|
+
ast = mutated
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// If there are mutations, add a single Query type
|
|
62
|
+
// with all the concatenated mutations
|
|
63
|
+
if (mutations.length > 0) {
|
|
64
|
+
const mutated: any = cloneDeep(ast)
|
|
65
|
+
const query = {
|
|
66
|
+
...mutationTemplate,
|
|
67
|
+
fields: mutations,
|
|
68
|
+
}
|
|
69
|
+
mutated.definitions.push(query)
|
|
70
|
+
ast = mutated
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return print(ast)
|
|
74
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {DocumentNode, visit} from 'graphql'
|
|
2
|
+
|
|
3
|
+
import {cloneDeep} from '../utils/graphql-helpers'
|
|
4
|
+
|
|
5
|
+
export default (ast: DocumentNode): DocumentNode => {
|
|
6
|
+
let queries: any = []
|
|
7
|
+
let mutations: any = []
|
|
8
|
+
|
|
9
|
+
// Loop through the AST and find Query and Mutation types.
|
|
10
|
+
ast = visit(ast, {
|
|
11
|
+
ObjectTypeDefinition: {
|
|
12
|
+
enter(node) {
|
|
13
|
+
if (node.name.kind === 'Name' && node.name.value === 'Query') {
|
|
14
|
+
queries = queries.concat(node.fields)
|
|
15
|
+
}
|
|
16
|
+
if (node.name.kind === 'Name' && node.name.value === 'Mutation') {
|
|
17
|
+
mutations = mutations.concat(node.fields)
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
// If there are no queries, add a single empty Query type
|
|
24
|
+
if (queries.length === 0) {
|
|
25
|
+
const mutated: any = cloneDeep(ast)
|
|
26
|
+
mutated.definitions.push({
|
|
27
|
+
kind: 'ObjectTypeDefinition',
|
|
28
|
+
description: undefined,
|
|
29
|
+
name: {kind: 'Name', value: 'Query'},
|
|
30
|
+
interfaces: [],
|
|
31
|
+
directives: [],
|
|
32
|
+
fields: [],
|
|
33
|
+
})
|
|
34
|
+
ast = mutated
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// If there are mutations, add a single empty Mutation type
|
|
38
|
+
if (mutations.length === 0) {
|
|
39
|
+
const mutated: any = cloneDeep(ast)
|
|
40
|
+
mutated.definitions.push({
|
|
41
|
+
kind: 'ObjectTypeDefinition',
|
|
42
|
+
description: undefined,
|
|
43
|
+
name: {kind: 'Name', value: 'Mutation'},
|
|
44
|
+
interfaces: [],
|
|
45
|
+
directives: [],
|
|
46
|
+
fields: [],
|
|
47
|
+
})
|
|
48
|
+
ast = mutated
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return ast
|
|
52
|
+
}
|