/
visitor.js
150 lines (122 loc) · 4.25 KB
/
visitor.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import * as t from '@babel/types'
import { freeText } from './utils'
const defaults = {
defaultGqlIdentifierName: 'gql',
gqlMagicComment: 'graphql',
gqlPackName: 'graphql-tag',
}
export default (code, out, options = {}) => {
// Apply defaults to options
let {
defaultGqlIdentifierName,
gqlMagicComment,
gqlPackName,
} = { ...defaults, ...options }
// Prevent case related potential errors
defaultGqlIdentifierName = defaultGqlIdentifierName.toLowerCase()
gqlMagicComment = gqlMagicComment.toLowerCase()
gqlPackName = gqlPackName.toLowerCase()
// Will accumulate all template literals
const gqlTemplateLiterals = []
// By default, we will look for `gql` calls
let gqlIdentifierName = defaultGqlIdentifierName
const pluckStringFromFile = ({ start, end }) => {
return freeText(code
// Slice quotes
.slice(start + 1, end - 1)
// Erase string interpolations as we gonna export everything as a single
// string anyways
.replace(/\$\{[^}]*\}/g, '')
)
}
// Push all template literals leaded by graphql magic comment
// e.g. /* GraphQL */ `query myQuery {}` -> query myQuery {}
const pluckMagicTemplateLiteral = (node) => {
const leadingComments = node.leadingComments
if (!leadingComments) return
if (!leadingComments.length) return
const leadingComment = leadingComments[leadingComments.length - 1]
const leadingCommentValue = leadingComment.value.trim().toLowerCase()
if (leadingCommentValue != gqlMagicComment) return
const gqlTemplateLiteral = pluckStringFromFile(node)
if (gqlTemplateLiteral) {
gqlTemplateLiterals.push(gqlTemplateLiteral)
}
}
return {
CallExpression: {
enter(path) {
// Find the identifier name used from graphql-tag, commonJS
// e.g. import gql from 'graphql-tag' -> gql
if (
path.node.callee.name == 'require' &&
path.node.arguments[0].value == gqlPackName
) {
if (!t.isVariableDeclarator(path.parent)) return
if (!t.isIdentifier(path.parent.id)) return
gqlIdentifierName = path.parent.id.name
return
}
const arg0 = path.node.arguments[0]
// Push strings template literals to gql calls
// e.g. gql(`query myQuery {}`) -> query myQuery {}
if (
t.isIdentifier(path.node.callee) &&
path.node.callee.name == gqlIdentifierName &&
t.isTemplateLiteral(arg0)
) {
const gqlTemplateLiteral = pluckStringFromFile(arg0)
// If the entire template was made out of interpolations it should be an empty
// string by now and thus should be ignored
if (gqlTemplateLiteral) {
gqlTemplateLiterals.push(gqlTemplateLiteral)
}
}
},
},
ImportDeclaration: {
enter(path) {
// Find the identifier name used from graphql-tag, es6
// e.g. import gql from 'graphql-tag' -> gql
if (path.node.source.value != gqlPackName) return
const gqlImportSpecifier = path.node.specifiers.find((importSpecifier) => {
return t.isImportDefaultSpecifier(importSpecifier)
})
if (!gqlImportSpecifier) return
gqlIdentifierName = gqlImportSpecifier.local.name
},
},
ExpressionStatement: {
exit(path) {
// Push all template literals leaded by graphql magic comment
// e.g. /* GraphQL */ `query myQuery {}` -> query myQuery {}
if (!t.isTemplateLiteral(path.node.expression)) return
pluckMagicTemplateLiteral(path.node)
},
},
TemplateLiteral: {
exit(path) {
pluckMagicTemplateLiteral(path.node)
},
},
TaggedTemplateExpression: {
exit(path) {
// Push all template literals provided to the found identifier name
// e.g. gql `query myQuery {}` -> query myQuery {}
if (
!t.isIdentifier(path.node.tag) ||
path.node.tag.name != gqlIdentifierName
) {
return
}
const gqlTemplateLiteral = pluckStringFromFile(path.node.quasi)
if (gqlTemplateLiteral) {
gqlTemplateLiterals.push(gqlTemplateLiteral)
}
},
},
exit() {
out.returnValue = gqlTemplateLiterals.join('\n\n')
},
}
}