@graphprotocol/graph-cli 0.22.2 → 0.23.0

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.
Files changed (43) hide show
  1. package/examples/basic-event-handlers/yarn.lock +4 -4
  2. package/examples/example-subgraph/yarn.lock +4 -4
  3. package/examples/near/.gitkeep +0 -0
  4. package/manifest-schema.graphql +35 -2
  5. package/package.json +1 -1
  6. package/src/codegen/schema.js +1 -2
  7. package/src/codegen/template.js +9 -51
  8. package/src/codegen/typescript.js +7 -0
  9. package/src/command-helpers/compiler.js +6 -2
  10. package/src/command-helpers/data-sources.js +38 -0
  11. package/src/command-helpers/fs.js +8 -0
  12. package/src/commands/build.js +14 -0
  13. package/src/commands/codegen.js +8 -0
  14. package/src/commands/deploy.js +11 -8
  15. package/src/commands/init.js +5 -8
  16. package/src/commands/test.js +8 -3
  17. package/src/compiler/index.js +93 -76
  18. package/src/{abi.js → protocols/ethereum/abi.js} +0 -0
  19. package/src/{codegen → protocols/ethereum/codegen}/abi.js +47 -40
  20. package/src/{codegen → protocols/ethereum/codegen}/abi.test.js +1 -1
  21. package/src/protocols/ethereum/codegen/template.js +42 -0
  22. package/src/protocols/ethereum/subgraph.js +205 -0
  23. package/src/protocols/ethereum/type-generator.js +203 -0
  24. package/src/protocols/index.js +97 -0
  25. package/src/protocols/near/subgraph.js +42 -0
  26. package/src/scaffold.js +3 -2
  27. package/src/scaffold.test.js +1 -1
  28. package/src/subgraph.js +30 -252
  29. package/src/type-generator.js +31 -211
  30. package/src/validation/index.js +1 -0
  31. package/src/validation/manifest.js +73 -23
  32. package/src/validation/schema.js +6 -0
  33. package/subgraph-ethereum.yaml +134 -0
  34. package/subgraph-near.yaml +134 -0
  35. package/tests/cli/init/from-contract/abis/Contract.json +69 -0
  36. package/tests/cli/init/from-contract/package.json +16 -0
  37. package/tests/cli/init/from-contract/schema.graphql +6 -0
  38. package/tests/cli/init/from-contract/src/mapping.ts +49 -0
  39. package/tests/cli/init/from-contract/subgraph.yaml +26 -0
  40. package/tests/cli/validation/near-is-valid/mapping.ts +0 -0
  41. package/tests/cli/validation/near-is-valid/schema.graphql +8 -0
  42. package/tests/cli/validation/near-is-valid/subgraph.yaml +21 -0
  43. package/tests/cli/validation.test.js +8 -0
@@ -0,0 +1,203 @@
1
+ const fs = require('fs-extra')
2
+ const path = require('path')
3
+ const immutable = require('immutable')
4
+ const prettier = require('prettier')
5
+ const ABI = require('./abi')
6
+ const { step, withSpinner } = require('../../command-helpers/spinner')
7
+ const { GENERATED_FILE_NOTE } = require('../../codegen/typescript')
8
+ const { displayPath } = require('../../command-helpers/fs')
9
+
10
+ module.exports = class EthereumTypeGenerator {
11
+ constructor(options = {}) {
12
+ this.sourceDir = options.sourceDir
13
+ this.outputDir = options.outputDir
14
+ }
15
+
16
+ async loadABIs(subgraph) {
17
+ return await withSpinner(
18
+ 'Load contract ABIs',
19
+ 'Failed to load contract ABIs',
20
+ `Warnings while loading contract ABIs`,
21
+ async spinner => {
22
+ try {
23
+ return subgraph
24
+ .get('dataSources')
25
+ .reduce(
26
+ (abis, dataSource) =>
27
+ dataSource
28
+ .getIn(['mapping', 'abis'])
29
+ .reduce(
30
+ (abis, abi) =>
31
+ abis.push(
32
+ this._loadABI(
33
+ dataSource,
34
+ abi.get('name'),
35
+ abi.get('file'),
36
+ spinner,
37
+ ),
38
+ ),
39
+ abis,
40
+ ),
41
+ immutable.List(),
42
+ )
43
+ } catch (e) {
44
+ throw Error(`Failed to load contract ABIs: ${e.message}`)
45
+ }
46
+ },
47
+ )
48
+ }
49
+
50
+ _loadABI(dataSource, name, maybeRelativePath, spinner) {
51
+ try {
52
+ if (this.sourceDir) {
53
+ let absolutePath = path.resolve(this.sourceDir, maybeRelativePath)
54
+ step(spinner, `Load contract ABI from`, displayPath(absolutePath))
55
+ return { dataSource: dataSource, abi: ABI.load(name, absolutePath) }
56
+ } else {
57
+ return { dataSource: dataSource, abi: ABI.load(name, maybeRelativePath) }
58
+ }
59
+ } catch (e) {
60
+ throw Error(`Failed to load contract ABI: ${e.message}`)
61
+ }
62
+ }
63
+
64
+ async loadDataSourceTemplateABIs(subgraph) {
65
+ return await withSpinner(
66
+ `Load data source template ABIs`,
67
+ `Failed to load data source template ABIs`,
68
+ `Warnings while loading data source template ABIs`,
69
+ async spinner => {
70
+ let abis = []
71
+ for (let template of subgraph.get('templates', immutable.List())) {
72
+ for (let abi of template.getIn(['mapping', 'abis'])) {
73
+ abis.push(
74
+ this._loadDataSourceTemplateABI(
75
+ template,
76
+ abi.get('name'),
77
+ abi.get('file'),
78
+ spinner,
79
+ ),
80
+ )
81
+ }
82
+ }
83
+ return abis
84
+ },
85
+ )
86
+ }
87
+
88
+ _loadDataSourceTemplateABI(template, name, maybeRelativePath, spinner) {
89
+ try {
90
+ if (this.sourceDir) {
91
+ let absolutePath = path.resolve(this.sourceDir, maybeRelativePath)
92
+ step(
93
+ spinner,
94
+ `Load data source template ABI from`,
95
+ displayPath(absolutePath),
96
+ )
97
+ return { template, abi: ABI.load(name, absolutePath) }
98
+ } else {
99
+ return { template, abi: ABI.load(name, maybeRelativePath) }
100
+ }
101
+ } catch (e) {
102
+ throw Error(`Failed to load data source template ABI: ${e.message}`)
103
+ }
104
+ }
105
+
106
+ generateTypesForABIs(abis) {
107
+ return withSpinner(
108
+ `Generate types for contract ABIs`,
109
+ `Failed to generate types for contract ABIs`,
110
+ `Warnings while generating types for contract ABIs`,
111
+ async spinner => {
112
+ return await Promise.all(
113
+ abis.map(async (abi, name) => await this._generateTypesForABI(abi, spinner)),
114
+ )
115
+ },
116
+ )
117
+ }
118
+
119
+ async _generateTypesForABI(abi, spinner) {
120
+ try {
121
+ step(
122
+ spinner,
123
+ `Generate types for contract ABI:`,
124
+ `${abi.abi.name} (${displayPath(abi.abi.file)})`,
125
+ )
126
+
127
+ let codeGenerator = abi.abi.codeGenerator()
128
+ let code = prettier.format(
129
+ [
130
+ GENERATED_FILE_NOTE,
131
+ ...codeGenerator.generateModuleImports(),
132
+ ...codeGenerator.generateTypes(),
133
+ ].join('\n'),
134
+ {
135
+ parser: 'typescript',
136
+ },
137
+ )
138
+
139
+ let outputFile = path.join(
140
+ this.outputDir,
141
+ abi.dataSource.get('name'),
142
+ `${abi.abi.name}.ts`,
143
+ )
144
+ step(spinner, `Write types to`, displayPath(outputFile))
145
+ await fs.mkdirs(path.dirname(outputFile))
146
+ await fs.writeFile(outputFile, code)
147
+ } catch (e) {
148
+ throw Error(`Failed to generate types for contract ABI: ${e.message}`)
149
+ }
150
+ }
151
+
152
+ async generateTypesForDataSourceTemplateABIs(abis) {
153
+ return await withSpinner(
154
+ `Generate types for data source template ABIs`,
155
+ `Failed to generate types for data source template ABIs`,
156
+ `Warnings while generating types for data source template ABIs`,
157
+ async spinner => {
158
+ return await Promise.all(
159
+ abis.map(
160
+ async (abi, name) =>
161
+ await this._generateTypesForDataSourceTemplateABI(abi, spinner),
162
+ ),
163
+ )
164
+ },
165
+ )
166
+ }
167
+
168
+ async _generateTypesForDataSourceTemplateABI(abi, spinner) {
169
+ try {
170
+ step(
171
+ spinner,
172
+ `Generate types for data source template ABI:`,
173
+ `${abi.template.get('name')} > ${abi.abi.name} (${displayPath(
174
+ abi.abi.file,
175
+ )})`,
176
+ )
177
+
178
+ let codeGenerator = abi.abi.codeGenerator()
179
+ let code = prettier.format(
180
+ [
181
+ GENERATED_FILE_NOTE,
182
+ ...codeGenerator.generateModuleImports(),
183
+ ...codeGenerator.generateTypes(),
184
+ ].join('\n'),
185
+ {
186
+ parser: 'typescript',
187
+ },
188
+ )
189
+
190
+ let outputFile = path.join(
191
+ this.outputDir,
192
+ 'templates',
193
+ abi.template.get('name'),
194
+ `${abi.abi.name}.ts`,
195
+ )
196
+ step(spinner, `Write types to`, displayPath(outputFile))
197
+ await fs.mkdirs(path.dirname(outputFile))
198
+ await fs.writeFile(outputFile, code)
199
+ } catch (e) {
200
+ throw Error(`Failed to generate types for data source template ABI: ${e.message}`)
201
+ }
202
+ }
203
+ }
@@ -0,0 +1,97 @@
1
+ const immutable = require('immutable')
2
+ const EthereumTypeGenerator = require('./ethereum/type-generator')
3
+ const EthereumTemplateCodeGen = require('./ethereum/codegen/template')
4
+ const EthereumABI = require('./ethereum/abi')
5
+ const EthereumSubgraph = require('./ethereum/subgraph')
6
+ const NearSubgraph = require('./near/subgraph')
7
+
8
+ module.exports = class Protocol {
9
+ static fromDataSources(dataSourcesAndTemplates) {
10
+ const firstDataSourceKind = dataSourcesAndTemplates[0].kind
11
+ return new Protocol(firstDataSourceKind)
12
+ }
13
+
14
+ constructor(name) {
15
+ this.name = this.normalizeName(name)
16
+ }
17
+
18
+ availableProtocols() {
19
+ return immutable.fromJS({
20
+ // `ethereum/contract` is kept for backwards compatibility.
21
+ // New networks (or protocol perhaps) shouldn't have the `/contract` anymore (unless a new case makes use of it).
22
+ ethereum: ['ethereum', 'ethereum/contract'],
23
+ near: ['near'],
24
+ })
25
+ }
26
+
27
+ normalizeName(name) {
28
+ return this.availableProtocols()
29
+ .findKey(possibleNames => possibleNames.includes(name))
30
+ }
31
+
32
+ // Receives a data source kind, and checks if it's valid
33
+ // for the given protocol instance (this).
34
+ isValidKindName(kind) {
35
+ return this.availableProtocols()
36
+ .get(this.name, immutable.List())
37
+ .includes(kind)
38
+ }
39
+
40
+ hasABIs() {
41
+ switch (this.name) {
42
+ case 'ethereum':
43
+ case 'ethereum/contract':
44
+ return true
45
+ case 'near':
46
+ return false
47
+ }
48
+ }
49
+
50
+ getTypeGenerator(options) {
51
+ switch (this.name) {
52
+ case 'ethereum':
53
+ case 'ethereum/contract':
54
+ return new EthereumTypeGenerator(options)
55
+ case 'near':
56
+ return null
57
+ }
58
+ }
59
+
60
+ getTemplateCodeGen(template) {
61
+ switch (this.name) {
62
+ case 'ethereum':
63
+ case 'ethereum/contract':
64
+ return new EthereumTemplateCodeGen(template)
65
+ default:
66
+ throw new Error(
67
+ `Template data sources with kind '${this.name}' are not supported yet`,
68
+ )
69
+ }
70
+ }
71
+
72
+ getABI() {
73
+ switch (this.name) {
74
+ case 'ethereum':
75
+ case 'ethereum/contract':
76
+ return EthereumABI
77
+ case 'near':
78
+ return null
79
+ }
80
+ }
81
+
82
+ getSubgraph(options = {}) {
83
+ const optionsWithProtocol = { ...options, protocol: this }
84
+
85
+ switch (this.name) {
86
+ case 'ethereum':
87
+ case 'ethereum/contract':
88
+ return new EthereumSubgraph(optionsWithProtocol)
89
+ case 'near':
90
+ return new NearSubgraph(optionsWithProtocol)
91
+ default:
92
+ throw new Error(
93
+ `Data sources with kind '${this.name}' are not supported yet`,
94
+ )
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,42 @@
1
+ const immutable = require('immutable')
2
+ const { validateContractValues } = require('../../validation')
3
+
4
+ module.exports = class NearSubgraph {
5
+ constructor(options = {}) {
6
+ this.manifest = options.manifest
7
+ this.resolveFile = options.resolveFile
8
+ this.protocol = options.protocol
9
+ }
10
+
11
+ validateManifest() {
12
+ return this.validateContractAccounts()
13
+ }
14
+
15
+ validateContractAccounts() {
16
+ // Reference: https://docs.near.org/docs/concepts/account#account-id-rules
17
+ const MINIMUM_ACCOUNT_ID_LENGTH = 2
18
+ const MAXIMUM_ACCOUNT_ID_LENGTH = 64
19
+ const validateLength = accountId =>
20
+ accountId.length >= MINIMUM_ACCOUNT_ID_LENGTH &&
21
+ accountId.length <= MAXIMUM_ACCOUNT_ID_LENGTH
22
+ const nearAccountIdPattern = /^(([a-z\d]+[\-_])*[a-z\d]+\.)*([a-z\d]+[\-_])*[a-z\d]+$/
23
+
24
+ return validateContractValues(
25
+ this.manifest,
26
+ this.protocol,
27
+ 'account',
28
+ accountId => validateLength(accountId) && nearAccountIdPattern.test(accountId),
29
+ `Must be between '${MINIMUM_ACCOUNT_ID_LENGTH}' and '${MAXIMUM_ACCOUNT_ID_LENGTH}' characters
30
+ An Account ID consists of Account ID parts separated by '.' (dots)
31
+ Each Account ID part consists of lowercase alphanumeric symbols separated by either a '_' (underscore) or '-' (dash)
32
+ For further information look for: https://docs.near.org/docs/concepts/account#account-id-rules`,
33
+ )
34
+ }
35
+
36
+ handlerTypes() {
37
+ return immutable.List([
38
+ 'blockHandlers',
39
+ 'receiptHandlers',
40
+ ])
41
+ }
42
+ }
package/src/scaffold.js CHANGED
@@ -6,8 +6,9 @@ const pkginfo = require('pkginfo')(module)
6
6
  const { getSubgraphBasename } = require('./command-helpers/subgraph')
7
7
  const { step } = require('./command-helpers/spinner')
8
8
  const { ascTypeForEthereum, valueTypeForAsc } = require('./codegen/types')
9
- const ABI = require('./abi')
10
- const AbiCodeGenerator = require('./codegen/abi')
9
+ // TODO: Use Protocol class to getABI
10
+ const ABI = require('./protocols/ethereum/abi')
11
+ const AbiCodeGenerator = require('./protocols/ethereum/codegen/abi')
11
12
  const util = require('./codegen/util')
12
13
 
13
14
  const abiEvents = abi =>
@@ -1,4 +1,4 @@
1
- const ABI = require('./abi')
1
+ const ABI = require('./protocols/ethereum/abi')
2
2
  const immutable = require('immutable')
3
3
  const {
4
4
  generateEventFieldAssignments,