@stepzen/transpiler 0.0.32 → 0.0.35
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.js +14 -15
- 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 +1 -1
- package/lib/utils/merge-helpers.js +9 -6
- 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 +186 -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 +176 -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,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
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import {BREAK, GraphQLSchema, visit} from 'graphql'
|
|
2
|
+
import {buildSchema} from 'graphql/utilities'
|
|
3
|
+
import fetch from 'node-fetch'
|
|
4
|
+
import * as fs from 'fs-extra'
|
|
5
|
+
import * as glob from 'glob'
|
|
6
|
+
import * as os from 'os'
|
|
7
|
+
import * as path from 'path'
|
|
8
|
+
import {replace} from 'lodash'
|
|
9
|
+
|
|
10
|
+
import {cloneDeep} from '../utils/graphql-helpers'
|
|
11
|
+
import {STEPZEN_DOMAIN} from './constants'
|
|
12
|
+
|
|
13
|
+
import configure from '../actions/configure'
|
|
14
|
+
import transpile from '../actions/transpile'
|
|
15
|
+
|
|
16
|
+
export const dedupeTempFolder = (dirpath: string) => {
|
|
17
|
+
do {
|
|
18
|
+
dirpath = replace(dirpath, os.tmpdir(), '')
|
|
19
|
+
} while (dirpath.includes(os.tmpdir()))
|
|
20
|
+
|
|
21
|
+
dirpath = path.join(os.tmpdir(), dirpath)
|
|
22
|
+
|
|
23
|
+
return dirpath
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const findQueryMutationInSchema = (
|
|
27
|
+
name: string,
|
|
28
|
+
files: any,
|
|
29
|
+
): Boolean => {
|
|
30
|
+
for (const file of files) {
|
|
31
|
+
let found = false
|
|
32
|
+
visit(file.ast, {
|
|
33
|
+
FieldDefinition(node) {
|
|
34
|
+
if (node.name.value === name) {
|
|
35
|
+
found = true
|
|
36
|
+
return BREAK
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
if (found) return true
|
|
41
|
+
}
|
|
42
|
+
return false
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const findTypeInSchema = (name: string, files: any): Boolean => {
|
|
46
|
+
for (const file of files) {
|
|
47
|
+
let found = false
|
|
48
|
+
visit(file.ast, {
|
|
49
|
+
ObjectTypeDefinition(node) {
|
|
50
|
+
if (node.name.value === name) {
|
|
51
|
+
found = true
|
|
52
|
+
return BREAK
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
if (found) return true
|
|
57
|
+
}
|
|
58
|
+
return false
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const getConfiguration = async (
|
|
62
|
+
directories: string[],
|
|
63
|
+
silent: boolean = false,
|
|
64
|
+
answers: any = {},
|
|
65
|
+
): Promise<string | boolean> => {
|
|
66
|
+
const tmp = path.join(os.tmpdir(), `stepzen-tmp-config-${Date.now()}`)
|
|
67
|
+
fs.ensureDirSync(tmp)
|
|
68
|
+
|
|
69
|
+
for (const directory of directories) {
|
|
70
|
+
const configs = [
|
|
71
|
+
...glob.sync('**/config.yaml', {cwd: directory}),
|
|
72
|
+
...glob.sync('**/stepzen.config.json', {cwd: directory}),
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
for (const config of configs) {
|
|
76
|
+
const configFolder = path.join(directory, config)
|
|
77
|
+
|
|
78
|
+
let writeFolder = path.join(tmp, directory, config)
|
|
79
|
+
writeFolder = dedupeTempFolder(writeFolder)
|
|
80
|
+
|
|
81
|
+
const content = fs.readFileSync(configFolder, 'utf8')
|
|
82
|
+
|
|
83
|
+
fs.ensureFileSync(writeFolder)
|
|
84
|
+
fs.writeFileSync(writeFolder, content)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const configuration = await configure(tmp, silent, answers)
|
|
89
|
+
fs.removeSync(tmp)
|
|
90
|
+
return configuration
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const getExtensions = async (): Promise<string> => {
|
|
94
|
+
const domain = STEPZEN_DOMAIN.replace('.io', '.net')
|
|
95
|
+
const response = await fetch(`https://www.${domain}/directives.graphql`)
|
|
96
|
+
const text = await response.text()
|
|
97
|
+
return text
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const getSchema = async (directory: string): Promise<GraphQLSchema> => {
|
|
101
|
+
const extensions = await getExtensions()
|
|
102
|
+
const transpiled = await transpile(directory)
|
|
103
|
+
return buildSchema(`${extensions}${os.EOL}${transpiled.schema}`)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const mergeQueryMutationIntoSchema = (type: any, files: any) => {
|
|
107
|
+
files = files.map((file: any) => {
|
|
108
|
+
return {
|
|
109
|
+
...file,
|
|
110
|
+
ast: visit(file.ast, {
|
|
111
|
+
FieldDefinition(node) {
|
|
112
|
+
if (node.name.value === type.name.value) {
|
|
113
|
+
const directives = cloneDeep(type.directives)
|
|
114
|
+
const mutated: any = cloneDeep(node)
|
|
115
|
+
mutated.directives = directives
|
|
116
|
+
return mutated
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
}),
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
return files
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export const mergeTypeIntoSchema = (type: any, files: any) => {
|
|
126
|
+
files = files.map((file: any) => {
|
|
127
|
+
return {
|
|
128
|
+
...file,
|
|
129
|
+
ast: visit(file.ast, {
|
|
130
|
+
ObjectTypeDefinition(node) {
|
|
131
|
+
if (node.name.value === type.name.value) {
|
|
132
|
+
const directives = cloneDeep(type.directives)
|
|
133
|
+
const fields = cloneDeep(type.fields)
|
|
134
|
+
const mutated: any = cloneDeep(node)
|
|
135
|
+
mutated.directives = directives
|
|
136
|
+
mutated.fields = fields
|
|
137
|
+
return mutated
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
}),
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
return files
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export const removeQueryMutationFromSchema = (name: string, files: any) => {
|
|
147
|
+
files = files.map((file: any) => {
|
|
148
|
+
return {
|
|
149
|
+
...file,
|
|
150
|
+
ast: visit(file.ast, {
|
|
151
|
+
FieldDefinition(node) {
|
|
152
|
+
if (node.name.value === name) {
|
|
153
|
+
return null
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
}),
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
return files
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export const removeTypeFromSchema = (name: string, files: any) => {
|
|
163
|
+
files = files.map((file: any) => {
|
|
164
|
+
return {
|
|
165
|
+
...file,
|
|
166
|
+
ast: visit(file.ast, {
|
|
167
|
+
ObjectTypeDefinition(node) {
|
|
168
|
+
if (node.name.value === name) {
|
|
169
|
+
return null
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
}),
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
return files
|
|
176
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as fs from 'fs'
|
|
2
|
+
import * as glob from 'glob'
|
|
3
|
+
import {parse, visit} from 'graphql'
|
|
4
|
+
import * as path from 'path'
|
|
5
|
+
|
|
6
|
+
import {cloneDeep} from './graphql-helpers'
|
|
7
|
+
import print from '../actions/print'
|
|
8
|
+
|
|
9
|
+
export default (source: string) => {
|
|
10
|
+
const files = glob
|
|
11
|
+
.sync('**/*.graphql', {cwd: source})
|
|
12
|
+
.filter(file => file !== 'index.graphql')
|
|
13
|
+
|
|
14
|
+
const output = path.join(source, 'index.graphql')
|
|
15
|
+
|
|
16
|
+
const index = fs.readFileSync(output, 'utf8')
|
|
17
|
+
|
|
18
|
+
let ast = parse(index)
|
|
19
|
+
ast = visit(ast, {
|
|
20
|
+
Directive(node) {
|
|
21
|
+
if (node.name.value === 'sdl') {
|
|
22
|
+
const mutated: any = cloneDeep(node)
|
|
23
|
+
|
|
24
|
+
mutated.arguments = mutated.arguments.map((arg: any) => {
|
|
25
|
+
if (arg.name.value === 'files') {
|
|
26
|
+
arg.value.values = files.map(file => ({
|
|
27
|
+
kind: 'StringValue',
|
|
28
|
+
value: file,
|
|
29
|
+
}))
|
|
30
|
+
}
|
|
31
|
+
return arg
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
return mutated
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
fs.writeFileSync(output, print(ast))
|
|
40
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {DocumentNode, visit} from 'graphql'
|
|
2
|
+
|
|
3
|
+
import {cloneDeep} from './graphql-helpers'
|
|
4
|
+
|
|
5
|
+
export default (ast: DocumentNode): DocumentNode => {
|
|
6
|
+
// Loop through the AST and nuke `__query` and `__mutation` stubs
|
|
7
|
+
ast = visit(ast, {
|
|
8
|
+
ObjectTypeDefinition: {
|
|
9
|
+
enter(node) {
|
|
10
|
+
if (node.name.kind === 'Name' && node.name.value === 'Query') {
|
|
11
|
+
const mutated: any = cloneDeep(node)
|
|
12
|
+
mutated.fields = mutated.fields.filter((field: any) => {
|
|
13
|
+
return field.name.value !== '__query'
|
|
14
|
+
})
|
|
15
|
+
return mutated
|
|
16
|
+
}
|
|
17
|
+
if (node.name.kind === 'Name' && node.name.value === 'Mutation') {
|
|
18
|
+
const mutated: any = cloneDeep(node)
|
|
19
|
+
mutated.fields = mutated.fields.filter((field: any) => {
|
|
20
|
+
return field.name.value !== '__mutated'
|
|
21
|
+
})
|
|
22
|
+
return mutated
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
// Strip empty Queries and Mutations definitions
|
|
29
|
+
ast = visit(ast, {
|
|
30
|
+
ObjectTypeDefinition: {
|
|
31
|
+
enter(node) {
|
|
32
|
+
if (node.name.kind === 'Name' && node.name.value === 'Query') {
|
|
33
|
+
if (node.fields?.length === 0) return null
|
|
34
|
+
}
|
|
35
|
+
if (node.name.kind === 'Name' && node.name.value === 'Mutation') {
|
|
36
|
+
if (node.fields?.length === 0) return null
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
return ast
|
|
43
|
+
}
|