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