@graphprotocol/graph-cli 0.22.4 → 0.23.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/README.md +83 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/.travis.yml +4 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/ethereum.ts +10 -16
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/near.ts +402 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/collections.ts +125 -4
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/eager_offset.ts +2 -1
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/json.ts +14 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/numbers.ts +58 -16
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/value.ts +2 -5
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/global/global.ts +108 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/helper-functions.ts +5 -5
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/index.ts +6 -15
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/package.json +5 -2
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/test/bigInt.ts +138 -108
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/test/bytes.ts +31 -20
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/test/test.js +120 -88
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/tsconfig.json +2 -2
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/types/tsconfig.base.json +3 -0
- package/examples/basic-event-handlers/package.json +1 -1
- package/examples/basic-event-handlers/yarn.lock +4 -4
- package/examples/example-subgraph/package.json +1 -1
- package/examples/example-subgraph/yarn.lock +4 -4
- package/jest.config.js +2 -2
- package/manifest-schema.graphql +35 -2
- package/package.json +2 -6
- package/src/codegen/schema.js +1 -2
- package/src/codegen/template.js +9 -51
- package/src/codegen/typescript.js +7 -0
- package/src/command-helpers/compiler.js +6 -2
- package/src/command-helpers/data-sources.js +38 -0
- package/src/command-helpers/fs.js +8 -0
- package/src/commands/build.js +14 -0
- package/src/commands/codegen.js +8 -0
- package/src/commands/deploy.js +11 -8
- package/src/commands/init.js +36 -11
- package/src/commands/test.js +37 -27
- package/src/compiler/index.js +90 -73
- package/src/{abi.js → protocols/ethereum/abi.js} +0 -0
- package/src/{codegen → protocols/ethereum/codegen}/abi.js +9 -6
- package/src/{codegen → protocols/ethereum/codegen}/abi.test.js +1 -1
- package/src/protocols/ethereum/codegen/template.js +42 -0
- package/src/protocols/ethereum/subgraph.js +205 -0
- package/src/protocols/ethereum/type-generator.js +203 -0
- package/src/protocols/index.js +97 -0
- package/src/protocols/near/subgraph.js +42 -0
- package/src/scaffold.js +21 -4
- package/src/scaffold.test.js +1 -1
- package/src/subgraph.js +30 -252
- package/src/type-generator.js +31 -211
- package/src/validation/index.js +1 -0
- package/src/validation/manifest.js +73 -23
- package/src/validation/schema.js +6 -0
- package/tests/cli/globalSetup.js +6 -0
- package/tests/cli/globalTeardown.js +6 -0
- package/tests/cli/init.test.js +1 -1
- package/tests/cli/util.js +17 -8
- package/tests/cli/validation/near-is-valid/mapping.ts +0 -0
- package/tests/cli/validation/near-is-valid/schema.graphql +8 -0
- package/tests/cli/validation/near-is-valid/subgraph.yaml +21 -0
- package/tests/cli/validation.test.js +8 -0
package/src/subgraph.js
CHANGED
|
@@ -5,7 +5,6 @@ let yaml = require('yaml')
|
|
|
5
5
|
let { strOptions } = require('yaml/types')
|
|
6
6
|
let graphql = require('graphql/language')
|
|
7
7
|
let validation = require('./validation')
|
|
8
|
-
let ABI = require('./abi')
|
|
9
8
|
|
|
10
9
|
const throwCombinedError = (filename, errors) => {
|
|
11
10
|
throw new Error(
|
|
@@ -39,7 +38,7 @@ const buildCombinedWarning = (filename, warnings) =>
|
|
|
39
38
|
: null
|
|
40
39
|
|
|
41
40
|
module.exports = class Subgraph {
|
|
42
|
-
static async validate(data, { resolveFile }) {
|
|
41
|
+
static async validate(data, protocol, { resolveFile }) {
|
|
43
42
|
// Parse the default subgraph schema
|
|
44
43
|
let schema = graphql.parse(
|
|
45
44
|
await fs.readFile(path.join(__dirname, '..', 'manifest-schema.graphql'), 'utf-8'),
|
|
@@ -51,7 +50,7 @@ module.exports = class Subgraph {
|
|
|
51
50
|
})
|
|
52
51
|
|
|
53
52
|
// Validate the subgraph manifest using this schema
|
|
54
|
-
return validation.validateManifest(data, rootType, schema, { resolveFile })
|
|
53
|
+
return validation.validateManifest(data, rootType, schema, protocol, { resolveFile })
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
static validateSchema(manifest, { resolveFile }) {
|
|
@@ -88,235 +87,6 @@ module.exports = class Subgraph {
|
|
|
88
87
|
}
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
static collectDataSources(manifest) {
|
|
92
|
-
return manifest
|
|
93
|
-
.get('dataSources')
|
|
94
|
-
.reduce(
|
|
95
|
-
(dataSources, dataSource, dataSourceIndex) =>
|
|
96
|
-
dataSource.get('kind') === 'ethereum/contract'
|
|
97
|
-
? dataSources.push(
|
|
98
|
-
immutable.Map({ path: ['dataSources', dataSourceIndex], dataSource }),
|
|
99
|
-
)
|
|
100
|
-
: dataSources,
|
|
101
|
-
immutable.List(),
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
static collectDataSourceTemplates(manifest) {
|
|
106
|
-
return manifest.get('templates', immutable.List()).reduce(
|
|
107
|
-
(templates, template, templateIndex) =>
|
|
108
|
-
template.get('kind') === 'ethereum/contract'
|
|
109
|
-
? templates.push(
|
|
110
|
-
immutable.Map({
|
|
111
|
-
path: ['templates', templateIndex],
|
|
112
|
-
dataSource: template,
|
|
113
|
-
}),
|
|
114
|
-
)
|
|
115
|
-
: templates,
|
|
116
|
-
immutable.List(),
|
|
117
|
-
)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
static validateDataSourceAbis(dataSource, { resolveFile, path }) {
|
|
121
|
-
// Validate that the the "source > abi" reference of all data sources
|
|
122
|
-
// points to an existing ABI in the data source ABIs
|
|
123
|
-
let abiName = dataSource.getIn(['source', 'abi'])
|
|
124
|
-
let abiNames = dataSource.getIn(['mapping', 'abis']).map(abi => abi.get('name'))
|
|
125
|
-
let nameErrors = abiNames.includes(abiName)
|
|
126
|
-
? immutable.List()
|
|
127
|
-
: immutable.fromJS([
|
|
128
|
-
{
|
|
129
|
-
path: [...path, 'source', 'abi'],
|
|
130
|
-
message: `\
|
|
131
|
-
ABI name '${abiName}' not found in mapping > abis.
|
|
132
|
-
Available ABIs:
|
|
133
|
-
${abiNames
|
|
134
|
-
.sort()
|
|
135
|
-
.map(name => `- ${name}`)
|
|
136
|
-
.join('\n')}`,
|
|
137
|
-
},
|
|
138
|
-
])
|
|
139
|
-
|
|
140
|
-
// Validate that all ABI files are valid
|
|
141
|
-
let fileErrors = dataSource
|
|
142
|
-
.getIn(['mapping', 'abis'])
|
|
143
|
-
.reduce((errors, abi, abiIndex) => {
|
|
144
|
-
try {
|
|
145
|
-
ABI.load(abi.get('name'), resolveFile(abi.get('file')))
|
|
146
|
-
return errors
|
|
147
|
-
} catch (e) {
|
|
148
|
-
return errors.push(
|
|
149
|
-
immutable.fromJS({
|
|
150
|
-
path: [...path, 'mapping', 'abis', abiIndex, 'file'],
|
|
151
|
-
message: e.message,
|
|
152
|
-
}),
|
|
153
|
-
)
|
|
154
|
-
}
|
|
155
|
-
}, immutable.List())
|
|
156
|
-
|
|
157
|
-
return nameErrors.concat(fileErrors)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
static validateAbis(manifest, { resolveFile }) {
|
|
161
|
-
let dataSources = Subgraph.collectDataSources(manifest)
|
|
162
|
-
let dataSourceTemplates = Subgraph.collectDataSourceTemplates(manifest)
|
|
163
|
-
|
|
164
|
-
return dataSources.concat(dataSourceTemplates).reduce(
|
|
165
|
-
(errors, dataSourceOrTemplate) =>
|
|
166
|
-
errors.concat(
|
|
167
|
-
Subgraph.validateDataSourceAbis(dataSourceOrTemplate.get('dataSource'), {
|
|
168
|
-
resolveFile,
|
|
169
|
-
path: dataSourceOrTemplate.get('path'),
|
|
170
|
-
}),
|
|
171
|
-
),
|
|
172
|
-
immutable.List(),
|
|
173
|
-
)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
static validateContractAddresses(manifest) {
|
|
177
|
-
return manifest
|
|
178
|
-
.get('dataSources')
|
|
179
|
-
.filter(dataSource => dataSource.get('kind') === 'ethereum/contract')
|
|
180
|
-
.reduce((errors, dataSource, dataSourceIndex) => {
|
|
181
|
-
let path = ['dataSources', dataSourceIndex, 'source', 'address']
|
|
182
|
-
|
|
183
|
-
// No need to validate if the source has no contract address
|
|
184
|
-
if (!dataSource.get('source').has('address')) {
|
|
185
|
-
return errors
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
let address = dataSource.getIn(['source', 'address'])
|
|
189
|
-
|
|
190
|
-
// Validate whether the address is valid
|
|
191
|
-
let pattern = /^(0x)?[0-9a-fA-F]{40}$/
|
|
192
|
-
if (pattern.test(address)) {
|
|
193
|
-
return errors
|
|
194
|
-
} else {
|
|
195
|
-
return errors.push(
|
|
196
|
-
immutable.fromJS({
|
|
197
|
-
path,
|
|
198
|
-
message: `\
|
|
199
|
-
Contract address is invalid: ${address}
|
|
200
|
-
Must be 40 hexadecimal characters, with an optional '0x' prefix.`,
|
|
201
|
-
}),
|
|
202
|
-
)
|
|
203
|
-
}
|
|
204
|
-
}, immutable.List())
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
static validateDataSourceEvents(dataSource, { resolveFile, path }) {
|
|
208
|
-
let abi
|
|
209
|
-
try {
|
|
210
|
-
// Resolve the source ABI name into a real ABI object
|
|
211
|
-
let abiName = dataSource.getIn(['source', 'abi'])
|
|
212
|
-
let abiEntry = dataSource
|
|
213
|
-
.getIn(['mapping', 'abis'])
|
|
214
|
-
.find(abi => abi.get('name') === abiName)
|
|
215
|
-
abi = ABI.load(abiEntry.get('name'), resolveFile(abiEntry.get('file')))
|
|
216
|
-
} catch (_) {
|
|
217
|
-
// Ignore errors silently; we can't really say anything about
|
|
218
|
-
// the events if the ABI can't even be loaded
|
|
219
|
-
return immutable.List()
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Obtain event signatures from the mapping
|
|
223
|
-
let manifestEvents = dataSource
|
|
224
|
-
.getIn(['mapping', 'eventHandlers'], immutable.List())
|
|
225
|
-
.map(handler => handler.get('event'))
|
|
226
|
-
|
|
227
|
-
// Obtain event signatures from the ABI
|
|
228
|
-
let abiEvents = abi.eventSignatures()
|
|
229
|
-
|
|
230
|
-
// Add errors for every manifest event signature that is not
|
|
231
|
-
// present in the ABI
|
|
232
|
-
return manifestEvents.reduce(
|
|
233
|
-
(errors, manifestEvent, index) =>
|
|
234
|
-
abiEvents.includes(manifestEvent)
|
|
235
|
-
? errors
|
|
236
|
-
: errors.push(
|
|
237
|
-
immutable.fromJS({
|
|
238
|
-
path: [...path, 'eventHandlers', index],
|
|
239
|
-
message: `\
|
|
240
|
-
Event with signature '${manifestEvent}' not present in ABI '${abi.name}'.
|
|
241
|
-
Available events:
|
|
242
|
-
${abiEvents
|
|
243
|
-
.sort()
|
|
244
|
-
.map(event => `- ${event}`)
|
|
245
|
-
.join('\n')}`,
|
|
246
|
-
}),
|
|
247
|
-
),
|
|
248
|
-
immutable.List(),
|
|
249
|
-
)
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
static validateEvents(manifest, { resolveFile }) {
|
|
253
|
-
let dataSources = Subgraph.collectDataSources(manifest)
|
|
254
|
-
let dataSourceTemplates = Subgraph.collectDataSourceTemplates(manifest)
|
|
255
|
-
|
|
256
|
-
return dataSources
|
|
257
|
-
.concat(dataSourceTemplates)
|
|
258
|
-
.reduce((errors, dataSourceOrTemplate) => {
|
|
259
|
-
return errors.concat(
|
|
260
|
-
Subgraph.validateDataSourceEvents(dataSourceOrTemplate.get('dataSource'), {
|
|
261
|
-
resolveFile,
|
|
262
|
-
path: dataSourceOrTemplate.get('path'),
|
|
263
|
-
}),
|
|
264
|
-
)
|
|
265
|
-
}, immutable.List())
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
static validateCallFunctions(manifest, { resolveFile }) {
|
|
269
|
-
return manifest
|
|
270
|
-
.get('dataSources')
|
|
271
|
-
.filter(dataSource => dataSource.get('kind') === 'ethereum/contract')
|
|
272
|
-
.reduce((errors, dataSource, dataSourceIndex) => {
|
|
273
|
-
let path = ['dataSources', dataSourceIndex, 'callHandlers']
|
|
274
|
-
|
|
275
|
-
let abi
|
|
276
|
-
try {
|
|
277
|
-
// Resolve the source ABI name into a real ABI object
|
|
278
|
-
let abiName = dataSource.getIn(['source', 'abi'])
|
|
279
|
-
let abiEntry = dataSource
|
|
280
|
-
.getIn(['mapping', 'abis'])
|
|
281
|
-
.find(abi => abi.get('name') === abiName)
|
|
282
|
-
abi = ABI.load(abiEntry.get('name'), resolveFile(abiEntry.get('file')))
|
|
283
|
-
} catch (e) {
|
|
284
|
-
// Ignore errors silently; we can't really say anything about
|
|
285
|
-
// the call functions if the ABI can't even be loaded
|
|
286
|
-
return errors
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// Obtain event signatures from the mapping
|
|
290
|
-
let manifestFunctions = dataSource
|
|
291
|
-
.getIn(['mapping', 'callHandlers'], immutable.List())
|
|
292
|
-
.map(handler => handler.get('function'))
|
|
293
|
-
|
|
294
|
-
// Obtain event signatures from the ABI
|
|
295
|
-
let abiFunctions = abi.callFunctionSignatures()
|
|
296
|
-
|
|
297
|
-
// Add errors for every manifest event signature that is not
|
|
298
|
-
// present in the ABI
|
|
299
|
-
return manifestFunctions.reduce(
|
|
300
|
-
(errors, manifestFunction, index) =>
|
|
301
|
-
abiFunctions.includes(manifestFunction)
|
|
302
|
-
? errors
|
|
303
|
-
: errors.push(
|
|
304
|
-
immutable.fromJS({
|
|
305
|
-
path: [...path, index],
|
|
306
|
-
message: `\
|
|
307
|
-
Call function with signature '${manifestFunction}' not present in ABI '${abi.name}'.
|
|
308
|
-
Available call functions:
|
|
309
|
-
${abiFunctions
|
|
310
|
-
.sort()
|
|
311
|
-
.map(tx => `- ${tx}`)
|
|
312
|
-
.join('\n')}`,
|
|
313
|
-
}),
|
|
314
|
-
),
|
|
315
|
-
errors,
|
|
316
|
-
)
|
|
317
|
-
}, immutable.List())
|
|
318
|
-
}
|
|
319
|
-
|
|
320
90
|
static validateRepository(manifest, { resolveFile }) {
|
|
321
91
|
return manifest.get('repository') !==
|
|
322
92
|
'https://github.com/graphprotocol/example-subgraph'
|
|
@@ -332,9 +102,9 @@ Please replace it with a link to your subgraph source code.`,
|
|
|
332
102
|
}
|
|
333
103
|
|
|
334
104
|
static validateDescription(manifest, { resolveFile }) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
105
|
+
// TODO: Maybe implement this in the future for each protocol example description
|
|
106
|
+
return manifest.get('description', '').startsWith('Gravatar for ')
|
|
107
|
+
? immutable.List().push(
|
|
338
108
|
immutable.fromJS({
|
|
339
109
|
path: ['description'],
|
|
340
110
|
message: `\
|
|
@@ -342,28 +112,32 @@ The description is still the one from the example subgraph.
|
|
|
342
112
|
Please update it to tell users more about your subgraph.`,
|
|
343
113
|
}),
|
|
344
114
|
)
|
|
115
|
+
: immutable.List()
|
|
345
116
|
}
|
|
346
117
|
|
|
347
|
-
static
|
|
118
|
+
static validateHandlers(manifest, protocol, protocolSubgraph) {
|
|
348
119
|
return manifest
|
|
349
120
|
.get('dataSources')
|
|
350
|
-
.filter(dataSource => dataSource.get('kind')
|
|
121
|
+
.filter(dataSource => protocol.isValidKindName(dataSource.get('kind')))
|
|
351
122
|
.reduce((errors, dataSource, dataSourceIndex) => {
|
|
352
123
|
let path = ['dataSources', dataSourceIndex, 'mapping']
|
|
353
124
|
|
|
354
125
|
let mapping = dataSource.get('mapping')
|
|
355
|
-
let blockHandlers = mapping.get('blockHandlers', immutable.List())
|
|
356
|
-
let callHandlers = mapping.get('callHandlers', immutable.List())
|
|
357
|
-
let eventHandlers = mapping.get('eventHandlers', immutable.List())
|
|
358
126
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
127
|
+
const handlerTypes = protocolSubgraph.handlerTypes()
|
|
128
|
+
|
|
129
|
+
const areAllHandlersEmpty = handlerTypes
|
|
130
|
+
.map(handlerType => mapping.get(handlerType, immutable.List()))
|
|
131
|
+
.every(handlers => handlers.isEmpty())
|
|
132
|
+
|
|
133
|
+
const handlerNamesWithoutLast = handlerTypes.pop().join(', ')
|
|
134
|
+
|
|
135
|
+
return areAllHandlersEmpty
|
|
362
136
|
? errors.push(
|
|
363
137
|
immutable.fromJS({
|
|
364
138
|
path: path,
|
|
365
139
|
message: `\
|
|
366
|
-
Mapping has no
|
|
140
|
+
Mapping has no ${handlerNamesWithoutLast} or ${handlerTypes.get(-1)}.
|
|
367
141
|
At least one such handler must be defined.`,
|
|
368
142
|
}),
|
|
369
143
|
)
|
|
@@ -419,7 +193,10 @@ More than one template named '${name}', template names must be unique.`,
|
|
|
419
193
|
return yaml.stringify(manifest.toJS())
|
|
420
194
|
}
|
|
421
195
|
|
|
422
|
-
static async load(
|
|
196
|
+
static async load(
|
|
197
|
+
filename,
|
|
198
|
+
{ protocol, skipValidation } = { skipValidation: false }
|
|
199
|
+
) {
|
|
423
200
|
// Load and validate the manifest
|
|
424
201
|
let data = null
|
|
425
202
|
|
|
@@ -434,7 +211,7 @@ More than one template named '${name}', template names must be unique.`,
|
|
|
434
211
|
let resolveFile = maybeRelativeFile =>
|
|
435
212
|
path.resolve(path.dirname(filename), maybeRelativeFile)
|
|
436
213
|
|
|
437
|
-
let manifestErrors = await Subgraph.validate(data, { resolveFile })
|
|
214
|
+
let manifestErrors = await Subgraph.validate(data, protocol, { resolveFile })
|
|
438
215
|
if (manifestErrors.size > 0) {
|
|
439
216
|
throwCombinedError(filename, manifestErrors)
|
|
440
217
|
}
|
|
@@ -445,16 +222,18 @@ More than one template named '${name}', template names must be unique.`,
|
|
|
445
222
|
Subgraph.validateSchema(manifest, { resolveFile })
|
|
446
223
|
|
|
447
224
|
// Perform other validations
|
|
225
|
+
const protocolSubgraph = protocol.getSubgraph({
|
|
226
|
+
manifest,
|
|
227
|
+
resolveFile,
|
|
228
|
+
})
|
|
229
|
+
|
|
448
230
|
let errors = skipValidation
|
|
449
231
|
? immutable.List()
|
|
450
232
|
: immutable.List.of(
|
|
451
|
-
...
|
|
452
|
-
...Subgraph.validateContractAddresses(manifest),
|
|
453
|
-
...Subgraph.validateEthereumContractHandlers(manifest),
|
|
454
|
-
...Subgraph.validateEvents(manifest, { resolveFile }),
|
|
455
|
-
...Subgraph.validateCallFunctions(manifest, { resolveFile }),
|
|
233
|
+
...protocolSubgraph.validateManifest(),
|
|
456
234
|
...Subgraph.validateUniqueDataSourceNames(manifest),
|
|
457
235
|
...Subgraph.validateUniqueTemplateNames(manifest),
|
|
236
|
+
...Subgraph.validateHandlers(manifest, protocol, protocolSubgraph),
|
|
458
237
|
)
|
|
459
238
|
|
|
460
239
|
if (errors.size > 0) {
|
|
@@ -467,7 +246,6 @@ More than one template named '${name}', template names must be unique.`,
|
|
|
467
246
|
: immutable.List.of(
|
|
468
247
|
...Subgraph.validateRepository(manifest, { resolveFile }),
|
|
469
248
|
...Subgraph.validateDescription(manifest, { resolveFile }),
|
|
470
|
-
...Subgraph.validateEthereumContractHandlers(manifest),
|
|
471
249
|
)
|
|
472
250
|
|
|
473
251
|
return {
|
package/src/type-generator.js
CHANGED
|
@@ -6,17 +6,14 @@ const graphql = require('graphql/language')
|
|
|
6
6
|
const chalk = require('chalk')
|
|
7
7
|
const toolbox = require('gluegun/toolbox')
|
|
8
8
|
|
|
9
|
-
const ABI = require('./abi')
|
|
10
9
|
const Schema = require('./schema')
|
|
11
10
|
const Subgraph = require('./subgraph')
|
|
12
11
|
const DataSourceTemplateCodeGenerator = require('./codegen/template')
|
|
13
12
|
const Watcher = require('./watcher')
|
|
14
13
|
const { step, withSpinner } = require('./command-helpers/spinner')
|
|
15
14
|
const { applyMigrations } = require('./migrations')
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
19
|
-
`
|
|
15
|
+
const { GENERATED_FILE_NOTE } = require('./codegen/typescript')
|
|
16
|
+
const { displayPath } = require('./command-helpers/fs')
|
|
20
17
|
|
|
21
18
|
module.exports = class TypeGenerator {
|
|
22
19
|
constructor(options) {
|
|
@@ -25,15 +22,17 @@ module.exports = class TypeGenerator {
|
|
|
25
22
|
this.options.sourceDir ||
|
|
26
23
|
(this.options.subgraphManifest && path.dirname(this.options.subgraphManifest))
|
|
27
24
|
|
|
25
|
+
this.protocol = this.options.protocol
|
|
26
|
+
this.protocolTypeGenerator = this.protocol.getTypeGenerator({
|
|
27
|
+
sourceDir: this.sourceDir,
|
|
28
|
+
outputDir: this.options.outputDir,
|
|
29
|
+
})
|
|
30
|
+
|
|
28
31
|
process.on('uncaughtException', function(e) {
|
|
29
32
|
toolbox.print.error(`UNCAUGHT EXCEPTION: ${e}`)
|
|
30
33
|
})
|
|
31
34
|
}
|
|
32
35
|
|
|
33
|
-
displayPath(p) {
|
|
34
|
-
return path.relative(process.cwd(), p)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
36
|
async generateTypes() {
|
|
38
37
|
try {
|
|
39
38
|
if (!this.options.skipMigrations && this.options.subgraphManifest) {
|
|
@@ -43,13 +42,20 @@ module.exports = class TypeGenerator {
|
|
|
43
42
|
})
|
|
44
43
|
}
|
|
45
44
|
let subgraph = await this.loadSubgraph()
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
|
|
46
|
+
// Not all protocols support/have ABIs.
|
|
47
|
+
if (this.protocol.hasABIs()) {
|
|
48
|
+
const abis = await this.protocolTypeGenerator.loadABIs(subgraph)
|
|
49
|
+
await this.protocolTypeGenerator.generateTypesForABIs(abis)
|
|
50
|
+
}
|
|
48
51
|
|
|
49
52
|
await this.generateTypesForDataSourceTemplates(subgraph)
|
|
50
53
|
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
// Not all protocols support/have ABIs.
|
|
55
|
+
if (this.protocol.hasABIs()) {
|
|
56
|
+
const templateAbis = await this.protocolTypeGenerator.loadDataSourceTemplateABIs(subgraph)
|
|
57
|
+
await this.protocolTypeGenerator.generateTypesForDataSourceTemplateABIs(templateAbis)
|
|
58
|
+
}
|
|
53
59
|
|
|
54
60
|
let schema = await this.loadSchema(subgraph)
|
|
55
61
|
await this.generateTypesForSchema(schema)
|
|
@@ -62,12 +68,14 @@ module.exports = class TypeGenerator {
|
|
|
62
68
|
}
|
|
63
69
|
|
|
64
70
|
async loadSubgraph({ quiet } = { quiet: false }) {
|
|
71
|
+
const subgraphLoadOptions = { protocol: this.protocol, skipValidation: false }
|
|
72
|
+
|
|
65
73
|
if (quiet) {
|
|
66
74
|
return this.options.subgraph
|
|
67
75
|
? this.options.subgraph
|
|
68
|
-
: Subgraph.load(this.options.subgraphManifest).result
|
|
76
|
+
: Subgraph.load(this.options.subgraphManifest, subgraphLoadOptions).result
|
|
69
77
|
} else {
|
|
70
|
-
const manifestPath =
|
|
78
|
+
const manifestPath = displayPath(this.options.subgraphManifest)
|
|
71
79
|
|
|
72
80
|
return await withSpinner(
|
|
73
81
|
`Load subgraph from ${manifestPath}`,
|
|
@@ -76,167 +84,19 @@ module.exports = class TypeGenerator {
|
|
|
76
84
|
async spinner => {
|
|
77
85
|
return this.options.subgraph
|
|
78
86
|
? this.options.subgraph
|
|
79
|
-
: Subgraph.load(this.options.subgraphManifest)
|
|
87
|
+
: Subgraph.load(this.options.subgraphManifest, subgraphLoadOptions)
|
|
80
88
|
},
|
|
81
89
|
)
|
|
82
90
|
}
|
|
83
91
|
}
|
|
84
92
|
|
|
85
|
-
async loadABIs(subgraph) {
|
|
86
|
-
return await withSpinner(
|
|
87
|
-
'Load contract ABIs',
|
|
88
|
-
'Failed to load contract ABIs',
|
|
89
|
-
`Warnings while loading contract ABIs`,
|
|
90
|
-
async spinner => {
|
|
91
|
-
try {
|
|
92
|
-
return subgraph
|
|
93
|
-
.get('dataSources')
|
|
94
|
-
.reduce(
|
|
95
|
-
(abis, dataSource) =>
|
|
96
|
-
dataSource
|
|
97
|
-
.getIn(['mapping', 'abis'])
|
|
98
|
-
.reduce(
|
|
99
|
-
(abis, abi) =>
|
|
100
|
-
abis.push(
|
|
101
|
-
this._loadABI(
|
|
102
|
-
dataSource,
|
|
103
|
-
abi.get('name'),
|
|
104
|
-
abi.get('file'),
|
|
105
|
-
spinner,
|
|
106
|
-
),
|
|
107
|
-
),
|
|
108
|
-
abis,
|
|
109
|
-
),
|
|
110
|
-
immutable.List(),
|
|
111
|
-
)
|
|
112
|
-
} catch (e) {
|
|
113
|
-
throw Error(`Failed to load contract ABIs: ${e.message}`)
|
|
114
|
-
}
|
|
115
|
-
},
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
_loadABI(dataSource, name, maybeRelativePath, spinner) {
|
|
120
|
-
try {
|
|
121
|
-
if (this.sourceDir) {
|
|
122
|
-
let absolutePath = path.resolve(this.sourceDir, maybeRelativePath)
|
|
123
|
-
step(spinner, `Load contract ABI from`, this.displayPath(absolutePath))
|
|
124
|
-
return { dataSource: dataSource, abi: ABI.load(name, absolutePath) }
|
|
125
|
-
} else {
|
|
126
|
-
return { dataSource: dataSource, abi: ABI.load(name, maybeRelativePath) }
|
|
127
|
-
}
|
|
128
|
-
} catch (e) {
|
|
129
|
-
throw Error(`Failed to load contract ABI: ${e.message}`)
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
_loadDataSourceTemplateABI(template, name, maybeRelativePath, spinner) {
|
|
134
|
-
try {
|
|
135
|
-
if (this.sourceDir) {
|
|
136
|
-
let absolutePath = path.resolve(this.sourceDir, maybeRelativePath)
|
|
137
|
-
step(
|
|
138
|
-
spinner,
|
|
139
|
-
`Load data source template ABI from`,
|
|
140
|
-
this.displayPath(absolutePath),
|
|
141
|
-
)
|
|
142
|
-
return { template, abi: ABI.load(name, absolutePath) }
|
|
143
|
-
} else {
|
|
144
|
-
return { template, abi: ABI.load(name, maybeRelativePath) }
|
|
145
|
-
}
|
|
146
|
-
} catch (e) {
|
|
147
|
-
throw Error(`Failed to load data source template ABI: ${e.message}`)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
generateTypesForABIs(abis) {
|
|
152
|
-
return withSpinner(
|
|
153
|
-
`Generate types for contract ABIs`,
|
|
154
|
-
`Failed to generate types for contract ABIs`,
|
|
155
|
-
`Warnings while generating types for contract ABIs`,
|
|
156
|
-
async spinner => {
|
|
157
|
-
return await Promise.all(
|
|
158
|
-
abis.map(async (abi, name) => await this._generateTypesForABI(abi, spinner)),
|
|
159
|
-
)
|
|
160
|
-
},
|
|
161
|
-
)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
async _generateTypesForABI(abi, spinner) {
|
|
165
|
-
try {
|
|
166
|
-
step(
|
|
167
|
-
spinner,
|
|
168
|
-
`Generate types for contract ABI:`,
|
|
169
|
-
`${abi.abi.name} (${this.displayPath(abi.abi.file)})`,
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
let codeGenerator = abi.abi.codeGenerator()
|
|
173
|
-
let code = prettier.format(
|
|
174
|
-
[
|
|
175
|
-
GENERATED_FILE_NOTE,
|
|
176
|
-
...codeGenerator.generateModuleImports(),
|
|
177
|
-
...codeGenerator.generateTypes(),
|
|
178
|
-
].join('\n'),
|
|
179
|
-
{
|
|
180
|
-
parser: 'typescript',
|
|
181
|
-
},
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
let outputFile = path.join(
|
|
185
|
-
this.options.outputDir,
|
|
186
|
-
abi.dataSource.get('name'),
|
|
187
|
-
`${abi.abi.name}.ts`,
|
|
188
|
-
)
|
|
189
|
-
step(spinner, `Write types to`, this.displayPath(outputFile))
|
|
190
|
-
await fs.mkdirs(path.dirname(outputFile))
|
|
191
|
-
await fs.writeFile(outputFile, code)
|
|
192
|
-
} catch (e) {
|
|
193
|
-
throw Error(`Failed to generate types for contract ABI: ${e.message}`)
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
async _generateTypesForDataSourceTemplateABI(abi, spinner) {
|
|
198
|
-
try {
|
|
199
|
-
step(
|
|
200
|
-
spinner,
|
|
201
|
-
`Generate types for data source template ABI:`,
|
|
202
|
-
`${abi.template.get('name')} > ${abi.abi.name} (${this.displayPath(
|
|
203
|
-
abi.abi.file,
|
|
204
|
-
)})`,
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
let codeGenerator = abi.abi.codeGenerator()
|
|
208
|
-
let code = prettier.format(
|
|
209
|
-
[
|
|
210
|
-
GENERATED_FILE_NOTE,
|
|
211
|
-
...codeGenerator.generateModuleImports(),
|
|
212
|
-
...codeGenerator.generateTypes(),
|
|
213
|
-
].join('\n'),
|
|
214
|
-
{
|
|
215
|
-
parser: 'typescript',
|
|
216
|
-
},
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
let outputFile = path.join(
|
|
220
|
-
this.options.outputDir,
|
|
221
|
-
'templates',
|
|
222
|
-
abi.template.get('name'),
|
|
223
|
-
`${abi.abi.name}.ts`,
|
|
224
|
-
)
|
|
225
|
-
step(spinner, `Write types to`, this.displayPath(outputFile))
|
|
226
|
-
await fs.mkdirs(path.dirname(outputFile))
|
|
227
|
-
await fs.writeFile(outputFile, code)
|
|
228
|
-
} catch (e) {
|
|
229
|
-
throw Error(`Failed to generate types for data source template ABI: ${e.message}`)
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
93
|
async loadSchema(subgraph) {
|
|
234
94
|
let maybeRelativePath = subgraph.getIn(['schema', 'file'])
|
|
235
95
|
let absolutePath = path.resolve(this.sourceDir, maybeRelativePath)
|
|
236
96
|
return await withSpinner(
|
|
237
|
-
`Load GraphQL schema from ${
|
|
238
|
-
`Failed to load GraphQL schema from ${
|
|
239
|
-
`Warnings while loading GraphQL schema from ${
|
|
97
|
+
`Load GraphQL schema from ${displayPath(absolutePath)}`,
|
|
98
|
+
`Failed to load GraphQL schema from ${displayPath(absolutePath)}`,
|
|
99
|
+
`Warnings while loading GraphQL schema from ${displayPath(absolutePath)}`,
|
|
240
100
|
async spinner => {
|
|
241
101
|
let maybeRelativePath = subgraph.getIn(['schema', 'file'])
|
|
242
102
|
let absolutePath = path.resolve(this.sourceDir, maybeRelativePath)
|
|
@@ -265,7 +125,7 @@ module.exports = class TypeGenerator {
|
|
|
265
125
|
)
|
|
266
126
|
|
|
267
127
|
let outputFile = path.join(this.options.outputDir, 'schema.ts')
|
|
268
|
-
step(spinner, 'Write types to',
|
|
128
|
+
step(spinner, 'Write types to', displayPath(outputFile))
|
|
269
129
|
await fs.mkdirs(path.dirname(outputFile))
|
|
270
130
|
await fs.writeFile(outputFile, code)
|
|
271
131
|
},
|
|
@@ -288,7 +148,7 @@ module.exports = class TypeGenerator {
|
|
|
288
148
|
`${template.get('name')}`,
|
|
289
149
|
)
|
|
290
150
|
|
|
291
|
-
let codeGenerator = new DataSourceTemplateCodeGenerator(template)
|
|
151
|
+
let codeGenerator = new DataSourceTemplateCodeGenerator(template, this.protocol)
|
|
292
152
|
|
|
293
153
|
// Only generate module imports once, because they are identical for
|
|
294
154
|
// all types generated for data source templates.
|
|
@@ -305,7 +165,7 @@ module.exports = class TypeGenerator {
|
|
|
305
165
|
})
|
|
306
166
|
|
|
307
167
|
let outputFile = path.join(this.options.outputDir, 'templates.ts')
|
|
308
|
-
step(spinner, `Write types for templates to`,
|
|
168
|
+
step(spinner, `Write types for templates to`, displayPath(outputFile))
|
|
309
169
|
await fs.mkdirs(path.dirname(outputFile))
|
|
310
170
|
await fs.writeFile(outputFile, code)
|
|
311
171
|
}
|
|
@@ -313,46 +173,6 @@ module.exports = class TypeGenerator {
|
|
|
313
173
|
)
|
|
314
174
|
}
|
|
315
175
|
|
|
316
|
-
async loadDataSourceTemplateABIs(subgraph) {
|
|
317
|
-
return await withSpinner(
|
|
318
|
-
`Load data source template ABIs`,
|
|
319
|
-
`Failed to load data source template ABIs`,
|
|
320
|
-
`Warnings while loading data source template ABIs`,
|
|
321
|
-
async spinner => {
|
|
322
|
-
let abis = []
|
|
323
|
-
for (let template of subgraph.get('templates', immutable.List())) {
|
|
324
|
-
for (let abi of template.getIn(['mapping', 'abis'])) {
|
|
325
|
-
abis.push(
|
|
326
|
-
this._loadDataSourceTemplateABI(
|
|
327
|
-
template,
|
|
328
|
-
abi.get('name'),
|
|
329
|
-
abi.get('file'),
|
|
330
|
-
spinner,
|
|
331
|
-
),
|
|
332
|
-
)
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
return abis
|
|
336
|
-
},
|
|
337
|
-
)
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
async generateTypesForDataSourceTemplateABIs(abis) {
|
|
341
|
-
return await withSpinner(
|
|
342
|
-
`Generate types for data source template ABIs`,
|
|
343
|
-
`Failed to generate types for data source template ABIs`,
|
|
344
|
-
`Warnings while generating types for data source template ABIs`,
|
|
345
|
-
async spinner => {
|
|
346
|
-
return await Promise.all(
|
|
347
|
-
abis.map(
|
|
348
|
-
async (abi, name) =>
|
|
349
|
-
await this._generateTypesForDataSourceTemplateABI(abi, spinner),
|
|
350
|
-
),
|
|
351
|
-
)
|
|
352
|
-
},
|
|
353
|
-
)
|
|
354
|
-
}
|
|
355
|
-
|
|
356
176
|
async getFilesToWatch() {
|
|
357
177
|
try {
|
|
358
178
|
let files = []
|
|
@@ -387,7 +207,7 @@ module.exports = class TypeGenerator {
|
|
|
387
207
|
onReady: () => (spinner = toolbox.print.spin('Watching subgraph files')),
|
|
388
208
|
onTrigger: async changedFile => {
|
|
389
209
|
if (changedFile !== undefined) {
|
|
390
|
-
spinner.info(`File change detected: ${
|
|
210
|
+
spinner.info(`File change detected: ${displayPath(changedFile)}\n`)
|
|
391
211
|
}
|
|
392
212
|
await generator.generateTypes()
|
|
393
213
|
spinner.start()
|