@graphprotocol/graph-cli 0.37.4 → 0.37.5

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 (100) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/bin.js +6 -0
  3. package/dist/cli.js +26 -0
  4. package/dist/codegen/schema.js +244 -0
  5. package/dist/codegen/schema.test.js +455 -0
  6. package/dist/codegen/template.js +66 -0
  7. package/dist/codegen/types/conversions.js +335 -0
  8. package/dist/codegen/types/index.js +71 -0
  9. package/dist/codegen/types/index.test.js +563 -0
  10. package/dist/codegen/typescript.js +200 -0
  11. package/dist/codegen/util.js +40 -0
  12. package/dist/codegen/util.test.js +93 -0
  13. package/dist/command-helpers/abi.js +76 -0
  14. package/dist/command-helpers/auth.js +76 -0
  15. package/dist/command-helpers/compiler.js +66 -0
  16. package/dist/command-helpers/data-sources.js +29 -0
  17. package/dist/command-helpers/fs.js +9 -0
  18. package/dist/command-helpers/gluegun.js +48 -0
  19. package/dist/command-helpers/ipfs.js +5 -0
  20. package/dist/command-helpers/jsonrpc.js +27 -0
  21. package/dist/command-helpers/network.js +90 -0
  22. package/dist/command-helpers/network.test.js +86 -0
  23. package/dist/command-helpers/node.js +40 -0
  24. package/dist/command-helpers/scaffold.js +110 -0
  25. package/dist/command-helpers/spinner.js +80 -0
  26. package/dist/command-helpers/studio.js +14 -0
  27. package/dist/command-helpers/studio.test.js +41 -0
  28. package/dist/command-helpers/subgraph.js +22 -0
  29. package/dist/command-helpers/version.js +66 -0
  30. package/dist/command-helpers/version.test.js +186 -0
  31. package/dist/commands/add.js +187 -0
  32. package/dist/commands/auth.js +122 -0
  33. package/dist/commands/build.js +136 -0
  34. package/dist/commands/codegen.js +128 -0
  35. package/dist/commands/create.js +94 -0
  36. package/dist/commands/deploy.js +335 -0
  37. package/dist/commands/init.js +800 -0
  38. package/dist/commands/local.js +380 -0
  39. package/dist/commands/remove.js +95 -0
  40. package/dist/commands/test.js +293 -0
  41. package/dist/compiler/asc.js +83 -0
  42. package/dist/compiler/index.js +466 -0
  43. package/dist/debug.js +16 -0
  44. package/dist/migrations/mapping_api_version_0_0_1.js +83 -0
  45. package/dist/migrations/mapping_api_version_0_0_2.js +83 -0
  46. package/dist/migrations/mapping_api_version_0_0_3.js +83 -0
  47. package/dist/migrations/mapping_api_version_0_0_4.js +85 -0
  48. package/dist/migrations/mapping_api_version_0_0_5.js +85 -0
  49. package/dist/migrations/spec_version_0_0_2.js +45 -0
  50. package/dist/migrations/spec_version_0_0_3.js +50 -0
  51. package/dist/migrations/util/load-manifest.js +16 -0
  52. package/dist/migrations/util/versions.js +28 -0
  53. package/dist/migrations.js +54 -0
  54. package/dist/protocols/arweave/manifest.graphql +57 -0
  55. package/dist/protocols/arweave/scaffold/manifest.js +18 -0
  56. package/dist/protocols/arweave/scaffold/mapping.js +52 -0
  57. package/dist/protocols/arweave/subgraph.js +23 -0
  58. package/dist/protocols/contract.js +2 -0
  59. package/dist/protocols/cosmos/manifest.graphql +76 -0
  60. package/dist/protocols/cosmos/scaffold/manifest.js +15 -0
  61. package/dist/protocols/cosmos/scaffold/mapping.js +38 -0
  62. package/dist/protocols/cosmos/subgraph.js +28 -0
  63. package/dist/protocols/ethereum/abi.js +138 -0
  64. package/dist/protocols/ethereum/codegen/abi.js +474 -0
  65. package/dist/protocols/ethereum/codegen/abi.test.js +325 -0
  66. package/dist/protocols/ethereum/codegen/template.js +52 -0
  67. package/dist/protocols/ethereum/contract.js +22 -0
  68. package/dist/protocols/ethereum/manifest.graphql +94 -0
  69. package/dist/protocols/ethereum/scaffold/manifest.js +32 -0
  70. package/dist/protocols/ethereum/scaffold/mapping.js +65 -0
  71. package/dist/protocols/ethereum/subgraph.js +172 -0
  72. package/dist/protocols/ethereum/type-generator.js +123 -0
  73. package/dist/protocols/index.js +266 -0
  74. package/dist/protocols/ipfs/codegen/file_template.js +53 -0
  75. package/dist/protocols/near/contract.js +41 -0
  76. package/dist/protocols/near/manifest.graphql +64 -0
  77. package/dist/protocols/near/scaffold/manifest.js +16 -0
  78. package/dist/protocols/near/scaffold/mapping.js +38 -0
  79. package/dist/protocols/near/subgraph.js +23 -0
  80. package/dist/protocols/subgraph.js +2 -0
  81. package/dist/protocols/substreams/manifest.graphql +45 -0
  82. package/dist/protocols/substreams/scaffold/manifest.js +12 -0
  83. package/dist/protocols/substreams/subgraph.js +23 -0
  84. package/dist/scaffold/cosmos.test.js +82 -0
  85. package/dist/scaffold/ethereum.test.js +496 -0
  86. package/dist/scaffold/index.js +133 -0
  87. package/dist/scaffold/mapping.js +57 -0
  88. package/dist/scaffold/near.test.js +85 -0
  89. package/dist/scaffold/schema.js +86 -0
  90. package/dist/scaffold/tests.js +179 -0
  91. package/dist/schema.js +54 -0
  92. package/dist/subgraph.js +243 -0
  93. package/dist/type-generator.js +225 -0
  94. package/dist/validation/contract.js +44 -0
  95. package/dist/validation/index.js +10 -0
  96. package/dist/validation/manifest.js +266 -0
  97. package/dist/validation/schema.js +768 -0
  98. package/dist/validation/schema.test.js +35 -0
  99. package/dist/watcher.js +79 -0
  100. package/package.json +1 -1
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const protocols_1 = __importDefault(require("../protocols"));
7
+ const index_1 = __importDefault(require("./index"));
8
+ const protocol = new protocols_1.default('near');
9
+ const scaffoldOptions = {
10
+ protocol,
11
+ contract: 'abc.def.near',
12
+ network: 'near-mainnet',
13
+ contractName: 'Contract',
14
+ };
15
+ const scaffold = new index_1.default(scaffoldOptions);
16
+ describe('NEAR subgraph scaffolding', () => {
17
+ test('Manifest', () => {
18
+ expect(scaffold.generateManifest()).toEqual(`\
19
+ specVersion: 0.0.5
20
+ schema:
21
+ file: ./schema.graphql
22
+ dataSources:
23
+ - kind: near
24
+ name: Contract
25
+ network: near-mainnet
26
+ source:
27
+ account: "abc.def.near"
28
+ mapping:
29
+ apiVersion: 0.0.5
30
+ language: wasm/assemblyscript
31
+ entities:
32
+ - ExampleEntity
33
+ receiptHandlers:
34
+ - handler: handleReceipt
35
+ file: ./src/contract.ts
36
+ `);
37
+ });
38
+ test('Schema (default)', () => {
39
+ expect(scaffold.generateSchema()).toEqual(`\
40
+ type ExampleEntity @entity {
41
+ id: ID!
42
+ block: Bytes!
43
+ count: BigInt!
44
+ }
45
+ `);
46
+ });
47
+ test('Mapping (default)', () => {
48
+ expect(scaffold.generateMapping()).toEqual(`\
49
+ import { near, BigInt } from "@graphprotocol/graph-ts"
50
+ import { ExampleEntity } from "../generated/schema"
51
+
52
+ export function handleReceipt(
53
+ receiptWithOutcome: near.ReceiptWithOutcome
54
+ ): void {
55
+ // Entities can be loaded from the store using a string ID; this ID
56
+ // needs to be unique across all entities of the same type
57
+ let entity = ExampleEntity.load(receiptWithOutcome.receipt.id.toHex())
58
+
59
+ // Entities only exist after they have been saved to the store;
60
+ // \`null\` checks allow to create entities on demand
61
+ if (!entity) {
62
+ entity = new ExampleEntity(receiptWithOutcome.receipt.id.toHex())
63
+
64
+ // Entity fields can be set using simple assignments
65
+ entity.count = BigInt.fromI32(0)
66
+ }
67
+
68
+ // BigInt and BigDecimal math are supported
69
+ entity.count = entity.count + BigInt.fromI32(1)
70
+
71
+ // Entity fields can be set based on receipt information
72
+ entity.block = receiptWithOutcome.block.header.hash
73
+
74
+ // Entities can be written to the store with \`.save()\`
75
+ entity.save()
76
+
77
+ // Note: If a handler doesn't require existing field values, it is faster
78
+ // _not_ to load the entity from the store. Instead, create it fresh with
79
+ // \`new Entity(...)\`, set the fields that should be updated and save the
80
+ // entity back to the store. Fields that were not set or unset remain
81
+ // unchanged, allowing for partial updates to be applied.
82
+ }
83
+ `);
84
+ });
85
+ });
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.generateExampleEntityType = exports.generateEventType = exports.generateEventFields = exports.generateField = exports.protocolTypeToGraphQL = exports.abiEvents = void 0;
27
+ const types_1 = require("../codegen/types");
28
+ const util = __importStar(require("../codegen/util"));
29
+ function abiEvents(abi) {
30
+ return util.disambiguateNames({
31
+ // @ts-expect-error improve typings of disambiguateNames to handle iterables
32
+ values: abi.data.filter(item => item.get('type') === 'event'),
33
+ // @ts-expect-error improve typings of disambiguateNames to handle iterables
34
+ getName: event => event.get('name'),
35
+ // @ts-expect-error improve typings of disambiguateNames to handle iterables
36
+ setName: (event, name) => event.set('_alias', name),
37
+ });
38
+ }
39
+ exports.abiEvents = abiEvents;
40
+ const protocolTypeToGraphQL = (protocol, name) => {
41
+ const ascType = (0, types_1.ascTypeForProtocol)(protocol, name);
42
+ return (0, types_1.valueTypeForAsc)(ascType);
43
+ };
44
+ exports.protocolTypeToGraphQL = protocolTypeToGraphQL;
45
+ const generateField = ({ name, type, protocolName, }) => `${name}: ${(0, exports.protocolTypeToGraphQL)(protocolName, type)}! # ${type}`;
46
+ exports.generateField = generateField;
47
+ const generateEventFields = ({ index, input, protocolName, }) => input.type == 'tuple'
48
+ ? util
49
+ .unrollTuple({ value: input, path: [input.name || `param${index}`], index })
50
+ .map(({ path, type }) => (0, exports.generateField)({ name: path.join('_'), type, protocolName }))
51
+ : [
52
+ (0, exports.generateField)({
53
+ name: input.name || `param${index}`,
54
+ type: input.type,
55
+ protocolName,
56
+ }),
57
+ ];
58
+ exports.generateEventFields = generateEventFields;
59
+ const generateEventType = (event, protocolName) => `type ${event._alias} @entity(immutable: true) {
60
+ id: Bytes!
61
+ ${event.inputs
62
+ .reduce((acc, input, index) => acc.concat((0, exports.generateEventFields)({ input, index, protocolName })), [])
63
+ .join('\n')}
64
+ blockNumber: BigInt!
65
+ blockTimestamp: BigInt!
66
+ transactionHash: Bytes!
67
+ }`;
68
+ exports.generateEventType = generateEventType;
69
+ const generateExampleEntityType = (protocol, events) => {
70
+ if (protocol.hasABIs() && events.length > 0) {
71
+ return `type ExampleEntity @entity {
72
+ id: Bytes!
73
+ count: BigInt!
74
+ ${events[0].inputs
75
+ .reduce((acc, input, index) => acc.concat((0, exports.generateEventFields)({ input, index, protocolName: protocol.name })), [])
76
+ .slice(0, 2)
77
+ .join('\n')}
78
+ }`;
79
+ }
80
+ return `type ExampleEntity @entity {
81
+ id: ID!
82
+ block: Bytes!
83
+ count: BigInt!
84
+ }`;
85
+ };
86
+ exports.generateExampleEntityType = generateExampleEntityType;
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateTestsFiles = void 0;
7
+ const gluegun_1 = require("gluegun");
8
+ const prettier_1 = __importDefault(require("prettier"));
9
+ const types_1 = require("../codegen/types");
10
+ const VARIABLES_VALUES = {
11
+ i32: 123,
12
+ BigInt: 234,
13
+ Bytes: 1234567890,
14
+ Address: '0x0000000000000000000000000000000000000001',
15
+ string: 'Example string value',
16
+ bool: true,
17
+ };
18
+ const generateTestsFiles = (contract, events, indexEvents) => {
19
+ const eventsTypes = events
20
+ .flatMap(event => event.inputs.map((input) => {
21
+ // If the asc type is Array<T> we need to check if T is a native type or a custom graph-ts type
22
+ // If we don't do that we may miss a type that should be imported from graph-ts
23
+ const ascType = (0, types_1.ascTypeForEthereum)(input.type);
24
+ const inner = fetchArrayInnerType(String(ascType));
25
+ return inner ? inner[1] : ascType;
26
+ }))
27
+ .filter(type => !type.startsWith('ethereum.') && !isNativeType(type));
28
+ const importTypes = [...new Set(eventsTypes)].join(', ');
29
+ return {
30
+ [`${gluegun_1.strings.kebabCase(contract)}.test.ts`]: prettier_1.default.format(generateExampleTest(contract, events[0], indexEvents, importTypes), { parser: 'typescript', semi: false }),
31
+ [`${gluegun_1.strings.kebabCase(contract)}-utils.ts`]: prettier_1.default.format(generateTestHelper(contract, events, importTypes), { parser: 'typescript', semi: false }),
32
+ };
33
+ };
34
+ exports.generateTestsFiles = generateTestsFiles;
35
+ /*
36
+ Generates the arguments that will be passed to the mock event function from the event inputs. Example:
37
+ let id = BigInt.fromI32(234)
38
+ let owner = Address.fromString("0x0000000000000000000000000000000000000001")
39
+ let displayName = "Example string value"
40
+ let imageUrl = "Example string value"
41
+ */
42
+ const generateArguments = (eventInputs) => {
43
+ return eventInputs
44
+ .map((input, index) => {
45
+ const ascType = (0, types_1.ascTypeForEthereum)(input.type);
46
+ return `let ${input.name || `param${index}`} = ${assignValue(ascType)}`;
47
+ })
48
+ .join('\n');
49
+ };
50
+ // Generates the value that will be assigned to a variable in generateArguments()
51
+ const assignValue = (type) => {
52
+ switch (type) {
53
+ case 'string':
54
+ return `"${VARIABLES_VALUES[type]}"`;
55
+ case 'BigInt':
56
+ return `BigInt.fromI32(${VARIABLES_VALUES[type]})`;
57
+ case 'Address':
58
+ return `Address.fromString("${VARIABLES_VALUES[type]}")`;
59
+ case 'Bytes':
60
+ return `Bytes.fromI32(${VARIABLES_VALUES[type]})`;
61
+ case fetchArrayInnerType(type)?.input: {
62
+ const innerType = fetchArrayInnerType(type)[1];
63
+ return `[${assignValue(innerType)}]`;
64
+ }
65
+ default: {
66
+ const value = VARIABLES_VALUES[type];
67
+ return value ? value : `"${type} Not implemented"`;
68
+ }
69
+ }
70
+ };
71
+ /*
72
+ Generates the assert.fieldEquals() for a given entity and event inputs. Example:
73
+ assert.fieldEquals(
74
+ "ExampleEntity",
75
+ "0xa16081f360e3847006db660bae1c6d1b2e17ec2a",
76
+ "owner",
77
+ "0x0000000000000000000000000000000000000001"
78
+ )
79
+ */
80
+ const generateFieldsAssertions = (entity, eventInputs, indexEvents) => eventInputs
81
+ .filter(input => input.name != 'id')
82
+ .map((input, index) => `assert.fieldEquals(
83
+ "${entity}",
84
+ "0xa16081f360e3847006db660bae1c6d1b2e17ec2a${indexEvents ? '-1' : ''}",
85
+ "${input.name || `param${index}`}",
86
+ "${expectedValue((0, types_1.ascTypeForEthereum)(input.type))}"
87
+ )`)
88
+ .join('\n');
89
+ // Returns the expected value for a given type in generateFieldsAssertions()
90
+ const expectedValue = (type) => {
91
+ switch (type) {
92
+ case fetchArrayInnerType(type)?.input: {
93
+ const innerType = fetchArrayInnerType(type)[1];
94
+ return `[${expectedValue(innerType)}]`;
95
+ }
96
+ default: {
97
+ const value = VARIABLES_VALUES[type];
98
+ return value ? value : `${type} Not implemented`;
99
+ }
100
+ }
101
+ };
102
+ // Checks if the type is a native AS type or should be imported from graph-ts
103
+ const isNativeType = (type) => {
104
+ const natives = [/i32/, /string/, /boolean/];
105
+ return natives.some(rx => rx.test(type));
106
+ };
107
+ const fetchArrayInnerType = (type) => type.match(/Array<(.*?)>/);
108
+ // Generates the example test.ts file
109
+ const generateExampleTest = (contract, event, indexEvents, importTypes) => {
110
+ const entity = indexEvents ? String(event._alias) : 'ExampleEntity';
111
+ const eventInputs = event.inputs;
112
+ const eventName = event._alias;
113
+ return `
114
+ import { assert, describe, test, clearStore, beforeAll, afterAll } from "matchstick-as/assembly/index"
115
+ import { ${importTypes} } from "@graphprotocol/graph-ts"
116
+ import { ${entity} } from "../generated/schema"
117
+ import { ${indexEvents ? `${eventName} as ${eventName}Event` : eventName} } from "../generated/${contract}/${contract}"
118
+ import { handle${eventName} } from "../src/${gluegun_1.strings.kebabCase(contract)}"
119
+ import { create${eventName}Event } from "./${gluegun_1.strings.kebabCase(contract)}-utils"
120
+
121
+
122
+ // Tests structure (matchstick-as >=0.5.0)
123
+ // https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0
124
+
125
+ describe("Describe entity assertions", () => {
126
+ beforeAll(() => {
127
+ ${generateArguments(eventInputs)}
128
+ let new${eventName}Event = create${eventName}Event(${eventInputs
129
+ .map((input, index) => input.name || `param${index}`)
130
+ .join(', ')});
131
+ handle${eventName}(new${eventName}Event)
132
+ })
133
+
134
+ afterAll(() => {
135
+ clearStore()
136
+ })
137
+
138
+ // For more test scenarios, see:
139
+ // https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test
140
+
141
+ test("${entity} created and stored", () => {
142
+ assert.entityCount('${entity}', 1)
143
+
144
+ // 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function
145
+ ${generateFieldsAssertions(entity, eventInputs, indexEvents)}
146
+
147
+ // More assert options:
148
+ // https://thegraph.com/docs/en/developer/matchstick/#asserts
149
+ })
150
+ })
151
+ `;
152
+ };
153
+ // Generates the utils helper file
154
+ const generateTestHelper = (contract, events, importTypes) => {
155
+ const eventsNames = events.map(event => event._alias);
156
+ return `
157
+ import { newMockEvent } from 'matchstick-as';
158
+ import { ethereum, ${importTypes} } from '@graphprotocol/graph-ts';
159
+ import { ${eventsNames.join(', ')} } from '../generated/${contract}/${contract}';
160
+
161
+ ${generateMockedEvents(events).join('\n')}`;
162
+ };
163
+ const generateMockedEvents = (events) => events.reduce((acc, event) => acc.concat(generateMockedEvent(event)), []);
164
+ const generateMockedEvent = (event) => {
165
+ const varName = `${gluegun_1.strings.camelCase(event._alias)}Event`;
166
+ const fnArgs = event.inputs.map((input, index) => `${input.name || `param${index}`}: ${(0, types_1.ascTypeForEthereum)(input.type)}`);
167
+ const ascToEth = event.inputs.map((input, index) => `${varName}.parameters.push(new ethereum.EventParam("${input.name || `param${index}`}", ${(0, types_1.ethereumFromAsc)(input.name || `param${index}`, input.type)}))`);
168
+ return `
169
+ export function create${event._alias}Event(${fnArgs.join(', ')}): ${event._alias} {
170
+ let ${varName} = changetype<${event._alias}>(newMockEvent());
171
+
172
+ ${varName}.parameters = new Array();
173
+
174
+ ${ascToEth.join('\n')}
175
+
176
+ return ${varName};
177
+ }
178
+ `;
179
+ };
package/dist/schema.js ADDED
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ const fs_extra_1 = __importDefault(require("fs-extra"));
30
+ const graphql = __importStar(require("graphql/language"));
31
+ const immutable_1 = __importDefault(require("immutable"));
32
+ const schema_1 = __importDefault(require("./codegen/schema"));
33
+ class Schema {
34
+ filename;
35
+ document;
36
+ ast;
37
+ constructor(filename, document, ast) {
38
+ this.filename = filename;
39
+ this.document = document;
40
+ this.ast = ast;
41
+ this.filename = filename;
42
+ this.document = document;
43
+ this.ast = ast;
44
+ }
45
+ codeGenerator() {
46
+ return new schema_1.default(this);
47
+ }
48
+ static async load(filename) {
49
+ const document = await fs_extra_1.default.readFile(filename, 'utf-8');
50
+ const ast = graphql.parse(document);
51
+ return new Schema(filename, document, immutable_1.default.fromJS(ast));
52
+ }
53
+ }
54
+ exports.default = Schema;
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ const path_1 = __importDefault(require("path"));
30
+ const fs_extra_1 = __importDefault(require("fs-extra"));
31
+ const graphql = __importStar(require("graphql/language"));
32
+ const immutable_1 = __importDefault(require("immutable"));
33
+ const yaml_1 = __importDefault(require("yaml"));
34
+ const types_1 = require("yaml/types");
35
+ const debug_1 = __importDefault(require("./debug"));
36
+ const validation = __importStar(require("./validation"));
37
+ const subgraphDebug = (0, debug_1.default)('graph-cli:subgraph');
38
+ const throwCombinedError = (filename, errors) => {
39
+ throw new Error(errors.reduce((msg, e) => `${msg}
40
+
41
+ Path: ${e.get('path').size === 0 ? '/' : e.get('path').join(' > ')}
42
+ ${e.get('message').split('\n').join('\n ')}`, `Error in ${path_1.default.relative(process.cwd(), filename)}:`));
43
+ };
44
+ const buildCombinedWarning = (filename, warnings) => warnings.size > 0
45
+ ? warnings.reduce((msg, w) => `${msg}
46
+
47
+ Path: ${w.get('path').size === 0 ? '/' : w.get('path').join(' > ')}
48
+ ${w.get('message').split('\n').join('\n ')}`, `Warnings in ${path_1.default.relative(process.cwd(), filename)}:`) + '\n'
49
+ : null;
50
+ class Subgraph {
51
+ static async validate(data, protocol, { resolveFile }) {
52
+ subgraphDebug(`Validating Subgraph with protocol "%s"`, protocol);
53
+ if (protocol.name == null) {
54
+ return immutable_1.default.fromJS([
55
+ {
56
+ path: [],
57
+ message: `Unable to determine for which protocol manifest file is built for. Ensure you have at least one 'dataSources' and/or 'templates' elements defined in your subgraph.`,
58
+ },
59
+ ]);
60
+ }
61
+ // Parse the default subgraph schema
62
+ const schema = graphql.parse(await fs_extra_1.default.readFile(path_1.default.join(__dirname, 'protocols', protocol.name, `manifest.graphql`), 'utf-8'));
63
+ // Obtain the root `SubgraphManifest` type from the schema
64
+ const rootType = schema.definitions.find(definition => {
65
+ // @ts-expect-error TODO: name field does not exist on definition, really?
66
+ return definition.name.value === 'SubgraphManifest';
67
+ });
68
+ // Validate the subgraph manifest using this schema
69
+ return validation.validateManifest(data, rootType, schema, protocol, { resolveFile });
70
+ }
71
+ static validateSchema(manifest, { resolveFile }) {
72
+ const filename = resolveFile(manifest.getIn(['schema', 'file']));
73
+ const validationErrors = validation.validateSchema(filename);
74
+ let errors;
75
+ if (validationErrors.size > 0) {
76
+ errors = validationErrors.groupBy(error => error.get('entity')).sort();
77
+ const msg = errors.reduce((msg, errors, entity) => {
78
+ errors = errors.groupBy((error) => error.get('directive'));
79
+ const inner_msgs = errors.reduce((msg, errors, directive) => {
80
+ return `${msg}${directive
81
+ ? `
82
+ ${directive}:`
83
+ : ''}
84
+ ${errors
85
+ .map(error => error.get('message').split('\n').join('\n '))
86
+ .map(msg => `${directive ? ' ' : ''}- ${msg}`)
87
+ .join('\n ')}`;
88
+ }, ``);
89
+ return `${msg}
90
+
91
+ ${entity}:${inner_msgs}`;
92
+ }, `Error in ${path_1.default.relative(process.cwd(), filename)}:`);
93
+ throw new Error(msg);
94
+ }
95
+ }
96
+ static validateRepository(manifest) {
97
+ const repository = manifest.get('repository');
98
+ return /^https:\/\/github\.com\/graphprotocol\/example-subgraphs?$/.test(repository)
99
+ ? immutable_1.default.List().push(immutable_1.default.fromJS({
100
+ path: ['repository'],
101
+ message: `\
102
+ The repository is still set to ${repository}.
103
+ Please replace it with a link to your subgraph source code.`,
104
+ }))
105
+ : immutable_1.default.List();
106
+ }
107
+ static validateDescription(manifest) {
108
+ // TODO: Maybe implement this in the future for each protocol example description
109
+ return manifest.get('description', '').startsWith('Gravatar for ')
110
+ ? immutable_1.default.List().push(immutable_1.default.fromJS({
111
+ path: ['description'],
112
+ message: `\
113
+ The description is still the one from the example subgraph.
114
+ Please update it to tell users more about your subgraph.`,
115
+ }))
116
+ : immutable_1.default.List();
117
+ }
118
+ static validateHandlers(manifest, protocol, protocolSubgraph) {
119
+ return manifest
120
+ .get('dataSources')
121
+ .filter((dataSource) => protocol.isValidKindName(dataSource.get('kind')))
122
+ .reduce((errors, dataSource, dataSourceIndex) => {
123
+ const path = ['dataSources', dataSourceIndex, 'mapping'];
124
+ const mapping = dataSource.get('mapping');
125
+ const handlerTypes = protocolSubgraph.handlerTypes();
126
+ subgraphDebug('Validating dataSource "%s" handlers with %d handlers types defined for protocol', dataSource.get('name'), handlerTypes.size);
127
+ if (handlerTypes.size == 0) {
128
+ return errors;
129
+ }
130
+ const areAllHandlersEmpty = handlerTypes
131
+ .map((handlerType) => mapping.get(handlerType, immutable_1.default.List()))
132
+ .every((handlers) => handlers.isEmpty());
133
+ const handlerNamesWithoutLast = handlerTypes.pop().join(', ');
134
+ return areAllHandlersEmpty
135
+ ? errors.push(immutable_1.default.fromJS({
136
+ path,
137
+ message: `\
138
+ Mapping has no ${handlerNamesWithoutLast} or ${handlerTypes.get(-1)}.
139
+ At least one such handler must be defined.`,
140
+ }))
141
+ : errors;
142
+ }, immutable_1.default.List());
143
+ }
144
+ static validateContractValues(manifest, protocol) {
145
+ if (!protocol.hasContract()) {
146
+ return immutable_1.default.List();
147
+ }
148
+ return validation.validateContractValues(manifest, protocol);
149
+ }
150
+ // Validate that data source names are unique, so they don't overwrite each other.
151
+ static validateUniqueDataSourceNames(manifest) {
152
+ const names = [];
153
+ return manifest
154
+ .get('dataSources')
155
+ .reduce((errors, dataSource, dataSourceIndex) => {
156
+ const path = ['dataSources', dataSourceIndex, 'name'];
157
+ const name = dataSource.get('name');
158
+ if (names.includes(name)) {
159
+ errors = errors.push(immutable_1.default.fromJS({
160
+ path,
161
+ message: `\
162
+ More than one data source named '${name}', data source names must be unique.`,
163
+ }));
164
+ }
165
+ names.push(name);
166
+ return errors;
167
+ }, immutable_1.default.List());
168
+ }
169
+ static validateUniqueTemplateNames(manifest) {
170
+ const names = [];
171
+ return manifest
172
+ .get('templates', immutable_1.default.List())
173
+ .reduce((errors, template, templateIndex) => {
174
+ const path = ['templates', templateIndex, 'name'];
175
+ const name = template.get('name');
176
+ if (names.includes(name)) {
177
+ errors = errors.push(immutable_1.default.fromJS({
178
+ path,
179
+ message: `\
180
+ More than one template named '${name}', template names must be unique.`,
181
+ }));
182
+ }
183
+ names.push(name);
184
+ return errors;
185
+ }, immutable_1.default.List());
186
+ }
187
+ static dump(manifest) {
188
+ types_1.strOptions.fold.lineWidth = 90;
189
+ // @ts-expect-error TODO: plain is the value behind the TS constant
190
+ types_1.strOptions.defaultType = 'PLAIN';
191
+ return yaml_1.default.stringify(manifest.toJS());
192
+ }
193
+ static async load(filename, { protocol, skipValidation } = {
194
+ skipValidation: false,
195
+ }) {
196
+ // Load and validate the manifest
197
+ let data = null;
198
+ let has_file_data_sources = false;
199
+ if (filename.match(/.js$/)) {
200
+ data = require(path_1.default.resolve(filename));
201
+ }
202
+ else {
203
+ const raw_data = await fs_extra_1.default.readFile(filename, 'utf-8');
204
+ has_file_data_sources = raw_data.includes('kind: file');
205
+ data = yaml_1.default.parse(raw_data);
206
+ }
207
+ // Helper to resolve files relative to the subgraph manifest
208
+ const resolveFile = maybeRelativeFile => path_1.default.resolve(path_1.default.dirname(filename), maybeRelativeFile);
209
+ // TODO: Validation for file data sources
210
+ if (!has_file_data_sources) {
211
+ const manifestErrors = await Subgraph.validate(data, protocol, { resolveFile });
212
+ if (manifestErrors.size > 0) {
213
+ throwCombinedError(filename, manifestErrors);
214
+ }
215
+ }
216
+ const manifest = immutable_1.default.fromJS(data);
217
+ // Validate the schema
218
+ Subgraph.validateSchema(manifest, { resolveFile });
219
+ // Perform other validations
220
+ const protocolSubgraph = protocol.getSubgraph({
221
+ manifest,
222
+ resolveFile,
223
+ });
224
+ const errors = skipValidation
225
+ ? immutable_1.default.List()
226
+ : immutable_1.default.List.of(...protocolSubgraph.validateManifest(), ...Subgraph.validateContractValues(manifest, protocol), ...Subgraph.validateUniqueDataSourceNames(manifest), ...Subgraph.validateUniqueTemplateNames(manifest), ...Subgraph.validateHandlers(manifest, protocol, protocolSubgraph));
227
+ if (errors.size > 0) {
228
+ throwCombinedError(filename, errors);
229
+ }
230
+ // Perform warning validations
231
+ const warnings = skipValidation
232
+ ? immutable_1.default.List()
233
+ : immutable_1.default.List.of(...Subgraph.validateRepository(manifest), ...Subgraph.validateDescription(manifest));
234
+ return {
235
+ result: manifest,
236
+ warning: warnings.size > 0 ? buildCombinedWarning(filename, warnings) : null,
237
+ };
238
+ }
239
+ static async write(manifest, filename) {
240
+ await fs_extra_1.default.writeFile(filename, Subgraph.dump(manifest));
241
+ }
242
+ }
243
+ exports.default = Subgraph;