@graphprotocol/graph-cli 0.37.2-alpha-20221219142030-0cf2a37 → 0.37.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.
- package/CHANGELOG.md +2 -3
- package/package.json +2 -1
- package/src/codegen/schema.js +58 -49
- package/src/codegen/schema.test.js +27 -32
- package/src/codegen/template.js +2 -1
- package/src/codegen/types/conversions.js +14 -43
- package/src/codegen/types/index.js +23 -20
- package/src/codegen/typescript.js +3 -0
- package/src/command-helpers/abi.js +3 -2
- package/src/command-helpers/data-sources.js +4 -3
- package/src/command-helpers/scaffold.js +14 -18
- package/src/command-helpers/spinner.js +1 -0
- package/src/commands/add.js +25 -42
- package/src/compiler/index.js +13 -12
- package/src/protocols/arweave/subgraph.js +7 -2
- package/src/protocols/cosmos/subgraph.js +9 -2
- package/src/protocols/ethereum/abi.js +7 -6
- package/src/protocols/ethereum/codegen/abi.js +223 -217
- package/src/protocols/ethereum/codegen/abi.test.js +16 -15
- package/src/protocols/ethereum/subgraph.js +67 -55
- package/src/protocols/ethereum/type-generator.js +25 -16
- package/src/protocols/index.js +6 -5
- package/src/protocols/near/subgraph.js +5 -3
- package/src/protocols/substreams/subgraph.js +4 -2
- package/src/scaffold/cosmos.test.js +1 -0
- package/src/scaffold/ethereum.test.js +3 -2
- package/src/scaffold/index.js +1 -1
- package/src/scaffold/near.test.js +1 -0
- package/src/schema.js +2 -1
- package/src/subgraph.js +53 -44
- package/src/type-generator.js +7 -6
- package/src/validation/contract.js +11 -6
- package/src/validation/manifest.js +84 -77
- package/src/validation/schema.js +294 -284
package/src/type-generator.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const fs = require('fs-extra')
|
|
2
|
+
const immutable = require('immutable')
|
|
2
3
|
const path = require('path')
|
|
3
4
|
const prettier = require('prettier')
|
|
4
5
|
const graphql = require('graphql/language')
|
|
@@ -119,14 +120,14 @@ module.exports = class TypeGenerator {
|
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
async loadSchema(subgraph) {
|
|
122
|
-
let maybeRelativePath = subgraph.schema
|
|
123
|
+
let maybeRelativePath = subgraph.getIn(['schema', 'file'])
|
|
123
124
|
let absolutePath = path.resolve(this.sourceDir, maybeRelativePath)
|
|
124
125
|
return await withSpinner(
|
|
125
126
|
`Load GraphQL schema from ${displayPath(absolutePath)}`,
|
|
126
127
|
`Failed to load GraphQL schema from ${displayPath(absolutePath)}`,
|
|
127
128
|
`Warnings while loading GraphQL schema from ${displayPath(absolutePath)}`,
|
|
128
129
|
async spinner => {
|
|
129
|
-
let maybeRelativePath = subgraph.schema
|
|
130
|
+
let maybeRelativePath = subgraph.getIn(['schema', 'file'])
|
|
130
131
|
let absolutePath = path.resolve(this.sourceDir, maybeRelativePath)
|
|
131
132
|
return Schema.load(absolutePath)
|
|
132
133
|
},
|
|
@@ -168,7 +169,7 @@ module.exports = class TypeGenerator {
|
|
|
168
169
|
async spinner => {
|
|
169
170
|
// Combine the generated code for all templates
|
|
170
171
|
let codeSegments = subgraph
|
|
171
|
-
.get('templates',
|
|
172
|
+
.get('templates', immutable.List())
|
|
172
173
|
.reduce((codeSegments, template) => {
|
|
173
174
|
step(
|
|
174
175
|
spinner,
|
|
@@ -188,7 +189,7 @@ module.exports = class TypeGenerator {
|
|
|
188
189
|
}
|
|
189
190
|
|
|
190
191
|
return codeSegments.concat(codeGenerator.generateTypes())
|
|
191
|
-
},
|
|
192
|
+
}, immutable.List())
|
|
192
193
|
|
|
193
194
|
if (!codeSegments.isEmpty()) {
|
|
194
195
|
let code = prettier.format([GENERATED_FILE_NOTE, ...codeSegments].join('\n'), {
|
|
@@ -213,11 +214,11 @@ module.exports = class TypeGenerator {
|
|
|
213
214
|
files.push(this.options.subgraphManifest)
|
|
214
215
|
|
|
215
216
|
// Add the GraphQL schema to the watched files
|
|
216
|
-
files.push(subgraph.schema
|
|
217
|
+
files.push(subgraph.getIn(['schema', 'file']))
|
|
217
218
|
|
|
218
219
|
// Add all file paths specified in manifest
|
|
219
220
|
subgraph.get('dataSources').map(dataSource => {
|
|
220
|
-
dataSource.mapping
|
|
221
|
+
dataSource.getIn(['mapping', 'abis']).map(abi => {
|
|
221
222
|
files.push(abi.get('file'))
|
|
222
223
|
})
|
|
223
224
|
})
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const immutable = require('immutable')
|
|
2
|
+
|
|
1
3
|
const validateContract = (value, ProtocolContract) => {
|
|
2
4
|
const contract = new ProtocolContract(value)
|
|
3
5
|
|
|
@@ -29,7 +31,8 @@ const validateContractValues = (manifest, protocol) => {
|
|
|
29
31
|
return errors
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
let contractValue = dataSource.source
|
|
34
|
+
let contractValue = dataSource.getIn(['source', fieldName])
|
|
35
|
+
|
|
33
36
|
|
|
34
37
|
const { valid, error } = validateContract(contractValue, ProtocolContract)
|
|
35
38
|
|
|
@@ -37,12 +40,14 @@ const validateContractValues = (manifest, protocol) => {
|
|
|
37
40
|
if (valid) {
|
|
38
41
|
return errors
|
|
39
42
|
} else {
|
|
40
|
-
return errors.push(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
return errors.push(
|
|
44
|
+
immutable.fromJS({
|
|
45
|
+
path,
|
|
46
|
+
message: error,
|
|
47
|
+
}),
|
|
48
|
+
)
|
|
44
49
|
}
|
|
45
|
-
},
|
|
50
|
+
}, immutable.List())
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
module.exports = {
|
|
@@ -1,16 +1,20 @@
|
|
|
1
|
+
const immutable = require('immutable')
|
|
1
2
|
const yaml = require('js-yaml')
|
|
2
3
|
const path = require('path')
|
|
3
4
|
|
|
4
5
|
const Protocol = require('../protocols')
|
|
5
6
|
|
|
7
|
+
const List = immutable.List
|
|
8
|
+
const Map = immutable.Map
|
|
9
|
+
|
|
6
10
|
/**
|
|
7
11
|
* Returns a user-friendly type name for a value.
|
|
8
12
|
*/
|
|
9
13
|
const typeName = value =>
|
|
10
|
-
|
|
14
|
+
List.isList(value) ? 'list' : Map.isMap(value) ? 'map' : typeof value
|
|
11
15
|
|
|
12
16
|
/**
|
|
13
|
-
* Converts
|
|
17
|
+
* Converts an immutable or plain JavaScript value to a YAML string.
|
|
14
18
|
*/
|
|
15
19
|
const toYAML = x =>
|
|
16
20
|
yaml
|
|
@@ -23,7 +27,9 @@ const toYAML = x =>
|
|
|
23
27
|
* Looks up the type of a field in a GraphQL object type.
|
|
24
28
|
*/
|
|
25
29
|
const getFieldType = (type, fieldName) => {
|
|
26
|
-
let fieldDef = type
|
|
30
|
+
let fieldDef = type
|
|
31
|
+
.get('fields')
|
|
32
|
+
.find(field => field.getIn(['name', 'value']) === fieldName)
|
|
27
33
|
|
|
28
34
|
return fieldDef !== undefined ? fieldDef.get('type') : undefined
|
|
29
35
|
}
|
|
@@ -35,17 +41,20 @@ const resolveType = (schema, type) =>
|
|
|
35
41
|
type.has('type')
|
|
36
42
|
? resolveType(schema, type.get('type'))
|
|
37
43
|
: type.get('kind') === 'NamedType'
|
|
38
|
-
? schema
|
|
44
|
+
? schema
|
|
45
|
+
.get('definitions')
|
|
46
|
+
.find(def => def.getIn(['name', 'value']) === type.getIn(['name', 'value']))
|
|
39
47
|
: 'resolveType: unimplemented'
|
|
40
48
|
|
|
41
49
|
/**
|
|
42
50
|
* A map of supported validators.
|
|
43
51
|
*/
|
|
44
|
-
const validators =
|
|
45
|
-
ScalarTypeDefinition: (value, ctx) =>
|
|
52
|
+
const validators = immutable.fromJS({
|
|
53
|
+
ScalarTypeDefinition: (value, ctx) =>
|
|
54
|
+
validators.get(ctx.getIn(['type', 'name', 'value']))(value, ctx),
|
|
46
55
|
|
|
47
56
|
UnionTypeDefinition: (value, ctx) => {
|
|
48
|
-
const unionVariants = ctx.type
|
|
57
|
+
const unionVariants = ctx.getIn(['type', 'types'])
|
|
49
58
|
|
|
50
59
|
let errors = List()
|
|
51
60
|
|
|
@@ -74,12 +83,12 @@ const validators = Object.freeze({
|
|
|
74
83
|
value,
|
|
75
84
|
ctx.update('type', type => type.get('type')),
|
|
76
85
|
)
|
|
77
|
-
: [
|
|
86
|
+
: immutable.fromJS([
|
|
78
87
|
{
|
|
79
88
|
path: ctx.get('path'),
|
|
80
89
|
message: `No value provided`,
|
|
81
90
|
},
|
|
82
|
-
],
|
|
91
|
+
]),
|
|
83
92
|
|
|
84
93
|
ListType: (value, ctx) =>
|
|
85
94
|
List.isList(value)
|
|
@@ -95,17 +104,18 @@ const validators = Object.freeze({
|
|
|
95
104
|
),
|
|
96
105
|
List(),
|
|
97
106
|
)
|
|
98
|
-
: [
|
|
107
|
+
: immutable.fromJS([
|
|
99
108
|
{
|
|
100
109
|
path: ctx.get('path'),
|
|
101
110
|
message: `Expected list, found ${typeName(value)}:\n${toYAML(value)}`,
|
|
102
111
|
},
|
|
103
|
-
],
|
|
112
|
+
]),
|
|
104
113
|
|
|
105
114
|
ObjectTypeDefinition: (value, ctx) => {
|
|
106
115
|
return Map.isMap(value)
|
|
107
|
-
? ctx
|
|
108
|
-
.
|
|
116
|
+
? ctx
|
|
117
|
+
.getIn(['type', 'fields'])
|
|
118
|
+
.map(fieldDef => fieldDef.getIn(['name', 'value']))
|
|
109
119
|
.concat(value.keySeq())
|
|
110
120
|
.toSet()
|
|
111
121
|
.reduce(
|
|
@@ -121,97 +131,97 @@ const validators = Object.freeze({
|
|
|
121
131
|
)
|
|
122
132
|
: errors.push(
|
|
123
133
|
key == 'templates' && ctx.get('protocol').hasTemplates()
|
|
124
|
-
? {
|
|
134
|
+
? immutable.fromJS({
|
|
125
135
|
path: ctx.get('path'),
|
|
126
136
|
message:
|
|
127
137
|
`The way to declare data source templates has changed, ` +
|
|
128
138
|
`please move the templates from inside data sources to ` +
|
|
129
139
|
`a \`templates:\` field at the top level of the manifest.`,
|
|
130
|
-
}
|
|
131
|
-
: {
|
|
140
|
+
})
|
|
141
|
+
: immutable.fromJS({
|
|
132
142
|
path: ctx.get('path'),
|
|
133
143
|
message: `Unexpected key in map: ${key}`,
|
|
134
|
-
},
|
|
144
|
+
}),
|
|
135
145
|
),
|
|
136
146
|
List(),
|
|
137
147
|
)
|
|
138
|
-
: [
|
|
148
|
+
: immutable.fromJS([
|
|
139
149
|
{
|
|
140
150
|
path: ctx.get('path'),
|
|
141
151
|
message: `Expected map, found ${typeName(value)}:\n${toYAML(value)}`,
|
|
142
152
|
},
|
|
143
|
-
]
|
|
153
|
+
])
|
|
144
154
|
},
|
|
145
155
|
|
|
146
156
|
EnumTypeDefinition: (value, ctx) => {
|
|
147
|
-
const enumValues = ctx.type
|
|
148
|
-
return v.name
|
|
157
|
+
const enumValues = ctx.getIn(['type', 'values']).map((v) => {
|
|
158
|
+
return v.getIn(['name', 'value'])
|
|
149
159
|
})
|
|
150
160
|
|
|
151
161
|
const allowedValues = enumValues.toArray().join(', ')
|
|
152
162
|
|
|
153
163
|
return enumValues.includes(value)
|
|
154
|
-
?
|
|
155
|
-
: [
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
164
|
+
? List()
|
|
165
|
+
: immutable.fromJS([
|
|
166
|
+
{
|
|
167
|
+
path: ctx.get('path'),
|
|
168
|
+
message: `Unexpected enum value: ${value}, allowed values: ${allowedValues}`,
|
|
169
|
+
},
|
|
170
|
+
])
|
|
161
171
|
},
|
|
162
172
|
|
|
163
173
|
String: (value, ctx) =>
|
|
164
174
|
typeof value === 'string'
|
|
165
175
|
? List()
|
|
166
|
-
: [
|
|
176
|
+
: immutable.fromJS([
|
|
167
177
|
{
|
|
168
178
|
path: ctx.get('path'),
|
|
169
179
|
message: `Expected string, found ${typeName(value)}:\n${toYAML(value)}`,
|
|
170
180
|
},
|
|
171
|
-
],
|
|
181
|
+
]),
|
|
172
182
|
|
|
173
183
|
BigInt: (value, ctx) =>
|
|
174
184
|
typeof value === 'number'
|
|
175
|
-
?
|
|
176
|
-
: [
|
|
185
|
+
? List()
|
|
186
|
+
: immutable.fromJS([
|
|
177
187
|
{
|
|
178
188
|
path: ctx.get('path'),
|
|
179
189
|
message: `Expected BigInt, found ${typeName(value)}:\n${toYAML(value)}`,
|
|
180
190
|
},
|
|
181
|
-
],
|
|
191
|
+
]),
|
|
182
192
|
|
|
183
193
|
File: (value, ctx) =>
|
|
184
194
|
typeof value === 'string'
|
|
185
195
|
? require('fs').existsSync(ctx.get('resolveFile')(value))
|
|
186
|
-
?
|
|
187
|
-
: [
|
|
196
|
+
? List()
|
|
197
|
+
: immutable.fromJS([
|
|
188
198
|
{
|
|
189
199
|
path: ctx.get('path'),
|
|
190
200
|
message: `File does not exist: ${path.relative(process.cwd(), value)}`,
|
|
191
201
|
},
|
|
192
|
-
]
|
|
193
|
-
: [
|
|
202
|
+
])
|
|
203
|
+
: immutable.fromJS([
|
|
194
204
|
{
|
|
195
205
|
path: ctx.get('path'),
|
|
196
206
|
message: `Expected filename, found ${typeName(value)}:\n${value}`,
|
|
197
207
|
},
|
|
198
|
-
],
|
|
208
|
+
]),
|
|
199
209
|
|
|
200
210
|
Boolean: (value, ctx) =>
|
|
201
211
|
typeof value === 'boolean'
|
|
202
|
-
?
|
|
203
|
-
: [
|
|
212
|
+
? List()
|
|
213
|
+
: immutable.fromJS([
|
|
204
214
|
{
|
|
205
215
|
path: ctx.get('path'),
|
|
206
216
|
message: `Expected true or false, found ${typeName(value)}:\n${toYAML(
|
|
207
217
|
value,
|
|
208
218
|
)}`,
|
|
209
219
|
},
|
|
210
|
-
],
|
|
220
|
+
]),
|
|
211
221
|
})
|
|
212
222
|
|
|
213
223
|
const validateValue = (value, ctx) => {
|
|
214
|
-
let kind = ctx.type
|
|
224
|
+
let kind = ctx.getIn(['type', 'kind'])
|
|
215
225
|
let validator = validators.get(kind)
|
|
216
226
|
|
|
217
227
|
if (validator !== undefined) {
|
|
@@ -219,17 +229,17 @@ const validateValue = (value, ctx) => {
|
|
|
219
229
|
// type is wrapped in a `NonNullType`, the validator for that `NonNullType`
|
|
220
230
|
// will catch the missing/unset value
|
|
221
231
|
if (kind !== 'NonNullType' && (value === undefined || value === null)) {
|
|
222
|
-
return
|
|
232
|
+
return List()
|
|
223
233
|
} else {
|
|
224
234
|
return validator(value, ctx)
|
|
225
235
|
}
|
|
226
236
|
} else {
|
|
227
|
-
return [
|
|
237
|
+
return immutable.fromJS([
|
|
228
238
|
{
|
|
229
239
|
path: ctx.get('path'),
|
|
230
240
|
message: `No validator for unsupported schema type: ${kind}`,
|
|
231
241
|
},
|
|
232
|
-
]
|
|
242
|
+
])
|
|
233
243
|
}
|
|
234
244
|
}
|
|
235
245
|
|
|
@@ -241,7 +251,7 @@ const validateValue = (value, ctx) => {
|
|
|
241
251
|
// { name: 'contract3', kind: 'near', network: 'near-mainnet' },
|
|
242
252
|
// ]
|
|
243
253
|
//
|
|
244
|
-
// Into JS structure like this (protocol kind is normalized):
|
|
254
|
+
// Into Immutable JS structure like this (protocol kind is normalized):
|
|
245
255
|
// {
|
|
246
256
|
// ethereum: {
|
|
247
257
|
// mainnet: ['contract0', 'contract1'],
|
|
@@ -252,17 +262,15 @@ const validateValue = (value, ctx) => {
|
|
|
252
262
|
// },
|
|
253
263
|
// }
|
|
254
264
|
const dataSourceListToMap = dataSources =>
|
|
255
|
-
dataSources
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
return protocolKinds
|
|
265
|
-
}, {})
|
|
265
|
+
dataSources
|
|
266
|
+
.reduce(
|
|
267
|
+
(protocolKinds, dataSource) =>
|
|
268
|
+
protocolKinds.update(Protocol.normalizeName(dataSource.kind), networks =>
|
|
269
|
+
(networks || immutable.OrderedMap()).update(dataSource.network, dataSourceNames =>
|
|
270
|
+
(dataSourceNames || immutable.OrderedSet()).add(dataSource.name)),
|
|
271
|
+
),
|
|
272
|
+
immutable.OrderedMap(),
|
|
273
|
+
)
|
|
266
274
|
|
|
267
275
|
const validateDataSourceProtocolAndNetworks = value => {
|
|
268
276
|
const dataSources = [...value.dataSources, ...(value.templates || [])]
|
|
@@ -270,7 +278,7 @@ const validateDataSourceProtocolAndNetworks = value => {
|
|
|
270
278
|
const protocolNetworkMap = dataSourceListToMap(dataSources)
|
|
271
279
|
|
|
272
280
|
if (protocolNetworkMap.size > 1) {
|
|
273
|
-
return [
|
|
281
|
+
return immutable.fromJS([
|
|
274
282
|
{
|
|
275
283
|
path: [],
|
|
276
284
|
message: `Conflicting protocol kinds used in data sources and templates:
|
|
@@ -281,22 +289,18 @@ ${protocolNetworkMap
|
|
|
281
289
|
protocolKind === undefined
|
|
282
290
|
? 'Data sources and templates having no protocol kind set'
|
|
283
291
|
: `Data sources and templates using '${protocolKind}'`
|
|
284
|
-
}:\n${dataSourceNames
|
|
285
|
-
.valueSeq()
|
|
286
|
-
.flatten()
|
|
287
|
-
.map(ds => ` - ${ds}`)
|
|
288
|
-
.join('\n')}`,
|
|
292
|
+
}:\n${dataSourceNames.valueSeq().flatten().map(ds => ` - ${ds}`).join('\n')}`,
|
|
289
293
|
)
|
|
290
294
|
.join('\n')}
|
|
291
295
|
Recommendation: Make all data sources and templates use the same protocol kind.`,
|
|
292
296
|
},
|
|
293
|
-
]
|
|
297
|
+
])
|
|
294
298
|
}
|
|
295
299
|
|
|
296
300
|
const networks = protocolNetworkMap.first()
|
|
297
301
|
|
|
298
302
|
if (networks.size > 1) {
|
|
299
|
-
return [
|
|
303
|
+
return immutable.fromJS([
|
|
300
304
|
{
|
|
301
305
|
path: [],
|
|
302
306
|
message: `Conflicting networks used in data sources and templates:
|
|
@@ -312,30 +316,33 @@ ${networks
|
|
|
312
316
|
.join('\n')}
|
|
313
317
|
Recommendation: Make all data sources and templates use the same network name.`,
|
|
314
318
|
},
|
|
315
|
-
]
|
|
319
|
+
])
|
|
316
320
|
}
|
|
317
321
|
|
|
318
|
-
return
|
|
322
|
+
return List()
|
|
319
323
|
}
|
|
320
324
|
|
|
321
325
|
const validateManifest = (value, type, schema, protocol, { resolveFile }) => {
|
|
322
326
|
// Validate manifest using the GraphQL schema that defines its structure
|
|
323
327
|
let errors =
|
|
324
328
|
value !== null && value !== undefined
|
|
325
|
-
? validateValue(
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
329
|
+
? validateValue(
|
|
330
|
+
immutable.fromJS(value),
|
|
331
|
+
immutable.fromJS({
|
|
332
|
+
schema: schema,
|
|
333
|
+
type: type,
|
|
334
|
+
path: [],
|
|
335
|
+
errors: [],
|
|
336
|
+
resolveFile,
|
|
337
|
+
protocol,
|
|
338
|
+
}),
|
|
339
|
+
)
|
|
340
|
+
: immutable.fromJS([
|
|
334
341
|
{
|
|
335
342
|
path: [],
|
|
336
343
|
message: `Expected non-empty value, found ${typeName(value)}:\n ${value}`,
|
|
337
344
|
},
|
|
338
|
-
]
|
|
345
|
+
])
|
|
339
346
|
|
|
340
347
|
// Fail early because a broken manifest prevents us from performing
|
|
341
348
|
// additional validation steps
|