@graphprotocol/graph-cli 0.37.3 → 0.37.4

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 (267) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/package.json +5 -1
  3. package/babel.config.js +0 -3
  4. package/jest.config.js +0 -175
  5. package/src/bin.ts +0 -6
  6. package/src/cli.ts +0 -30
  7. package/src/codegen/schema.test.ts +0 -460
  8. package/src/codegen/schema.ts +0 -299
  9. package/src/codegen/template.ts +0 -45
  10. package/src/codegen/types/conversions.ts +0 -358
  11. package/src/codegen/types/index.test.ts +0 -715
  12. package/src/codegen/types/index.ts +0 -111
  13. package/src/codegen/typescript.ts +0 -224
  14. package/src/codegen/util.test.ts +0 -112
  15. package/src/codegen/util.ts +0 -54
  16. package/src/command-helpers/abi.ts +0 -99
  17. package/src/command-helpers/auth.ts +0 -46
  18. package/src/command-helpers/compiler.ts +0 -60
  19. package/src/command-helpers/data-sources.ts +0 -36
  20. package/src/command-helpers/fs.ts +0 -5
  21. package/src/command-helpers/gluegun.ts +0 -52
  22. package/src/command-helpers/ipfs-http-client.d.ts +0 -1
  23. package/src/command-helpers/ipfs.ts +0 -3
  24. package/src/command-helpers/jsonrpc.ts +0 -22
  25. package/src/command-helpers/network.test.ts +0 -85
  26. package/src/command-helpers/network.ts +0 -133
  27. package/src/command-helpers/node.ts +0 -46
  28. package/src/command-helpers/scaffold.ts +0 -174
  29. package/src/command-helpers/spinner.ts +0 -60
  30. package/src/command-helpers/studio.test.ts +0 -84
  31. package/src/command-helpers/studio.ts +0 -25
  32. package/src/command-helpers/subgraph.ts +0 -21
  33. package/src/command-helpers/version.test.ts +0 -241
  34. package/src/command-helpers/version.ts +0 -53
  35. package/src/commands/add.ts +0 -220
  36. package/src/commands/auth.ts +0 -138
  37. package/src/commands/binary-install-raw.d.ts +0 -1
  38. package/src/commands/build.ts +0 -147
  39. package/src/commands/codegen.ts +0 -123
  40. package/src/commands/create.ts +0 -109
  41. package/src/commands/deploy.ts +0 -388
  42. package/src/commands/init.ts +0 -1060
  43. package/src/commands/local.ts +0 -539
  44. package/src/commands/remove.ts +0 -110
  45. package/src/commands/test.ts +0 -369
  46. package/src/compiler/asc.ts +0 -77
  47. package/src/compiler/index.ts +0 -677
  48. package/src/debug.ts +0 -15
  49. package/src/migrations/mapping_api_version_0_0_1.ts +0 -75
  50. package/src/migrations/mapping_api_version_0_0_2.ts +0 -75
  51. package/src/migrations/mapping_api_version_0_0_3.ts +0 -75
  52. package/src/migrations/mapping_api_version_0_0_4.ts +0 -77
  53. package/src/migrations/mapping_api_version_0_0_5.ts +0 -77
  54. package/src/migrations/spec_version_0_0_2.ts +0 -24
  55. package/src/migrations/spec_version_0_0_3.ts +0 -29
  56. package/src/migrations/util/load-manifest.ts +0 -10
  57. package/src/migrations/util/versions.ts +0 -27
  58. package/src/migrations.ts +0 -33
  59. package/src/protocols/arweave/manifest.graphql +0 -57
  60. package/src/protocols/arweave/scaffold/manifest.ts +0 -14
  61. package/src/protocols/arweave/scaffold/mapping.ts +0 -49
  62. package/src/protocols/arweave/subgraph.ts +0 -22
  63. package/src/protocols/contract.ts +0 -9
  64. package/src/protocols/cosmos/manifest.graphql +0 -76
  65. package/src/protocols/cosmos/scaffold/manifest.ts +0 -11
  66. package/src/protocols/cosmos/scaffold/mapping.ts +0 -35
  67. package/src/protocols/cosmos/subgraph.ts +0 -27
  68. package/src/protocols/ethereum/abi.ts +0 -153
  69. package/src/protocols/ethereum/codegen/abi.test.ts +0 -330
  70. package/src/protocols/ethereum/codegen/abi.ts +0 -719
  71. package/src/protocols/ethereum/codegen/template.ts +0 -41
  72. package/src/protocols/ethereum/contract.ts +0 -24
  73. package/src/protocols/ethereum/manifest.graphql +0 -94
  74. package/src/protocols/ethereum/scaffold/manifest.ts +0 -28
  75. package/src/protocols/ethereum/scaffold/mapping.ts +0 -76
  76. package/src/protocols/ethereum/subgraph.ts +0 -189
  77. package/src/protocols/ethereum/type-generator.ts +0 -191
  78. package/src/protocols/index.ts +0 -287
  79. package/src/protocols/ipfs/codegen/file_template.ts +0 -43
  80. package/src/protocols/near/contract.ts +0 -47
  81. package/src/protocols/near/manifest.graphql +0 -64
  82. package/src/protocols/near/scaffold/manifest.ts +0 -13
  83. package/src/protocols/near/scaffold/mapping.ts +0 -35
  84. package/src/protocols/near/subgraph.ts +0 -22
  85. package/src/protocols/subgraph.ts +0 -12
  86. package/src/protocols/substreams/manifest.graphql +0 -45
  87. package/src/protocols/substreams/scaffold/manifest.ts +0 -8
  88. package/src/protocols/substreams/subgraph.ts +0 -22
  89. package/src/scaffold/cosmos.test.ts +0 -83
  90. package/src/scaffold/ethereum.test.ts +0 -512
  91. package/src/scaffold/index.ts +0 -172
  92. package/src/scaffold/mapping.ts +0 -44
  93. package/src/scaffold/near.test.ts +0 -86
  94. package/src/scaffold/schema.ts +0 -89
  95. package/src/scaffold/tests.ts +0 -217
  96. package/src/schema.ts +0 -26
  97. package/src/subgraph.ts +0 -302
  98. package/src/type-generator.ts +0 -266
  99. package/src/validation/contract.ts +0 -51
  100. package/src/validation/index.ts +0 -5
  101. package/src/validation/manifest.ts +0 -360
  102. package/src/validation/schema.test.ts +0 -38
  103. package/src/validation/schema.ts +0 -957
  104. package/src/watcher.ts +0 -96
  105. package/tests/cli/globalSetup.ts +0 -8
  106. package/tests/cli/globalTeardown.ts +0 -8
  107. package/tests/cli/init/ethereum/abis/Marketplace.json +0 -408
  108. package/tests/cli/init/ethereum/abis/OverloadedElements.json +0 -91
  109. package/tests/cli/init/ethereum/abis/SoloMargin.json +0 -2729
  110. package/tests/cli/init/ethereum/from-contract-with-abi-and-structs.stderr +0 -14
  111. package/tests/cli/init/ethereum/from-contract-with-abi-and-structs.stdout +0 -12
  112. package/tests/cli/init/ethereum/from-contract-with-abi.stderr +0 -14
  113. package/tests/cli/init/ethereum/from-contract-with-abi.stdout +0 -12
  114. package/tests/cli/init/ethereum/from-contract-with-overloaded-elements.stderr +0 -14
  115. package/tests/cli/init/ethereum/from-contract-with-overloaded-elements.stdout +0 -12
  116. package/tests/cli/init/ethereum/from-contract.stderr +0 -16
  117. package/tests/cli/init/ethereum/from-contract.stdout +0 -12
  118. package/tests/cli/init/ethereum/from-example.stderr +0 -12
  119. package/tests/cli/init/ethereum/from-example.stdout +0 -12
  120. package/tests/cli/init/near/from-contract.stderr +0 -14
  121. package/tests/cli/init/near/from-contract.stdout +0 -12
  122. package/tests/cli/init.test.ts +0 -157
  123. package/tests/cli/spawn-command.d.ts +0 -7
  124. package/tests/cli/util.ts +0 -132
  125. package/tests/cli/validation/abi-not-found/Abi.json +0 -7
  126. package/tests/cli/validation/abi-not-found/mapping.ts +0 -0
  127. package/tests/cli/validation/abi-not-found/schema.graphql +0 -3
  128. package/tests/cli/validation/abi-not-found/subgraph.yaml +0 -42
  129. package/tests/cli/validation/abi-not-found copy.stderr +0 -13
  130. package/tests/cli/validation/big-decimal-is-valid/Abi.json +0 -7
  131. package/tests/cli/validation/big-decimal-is-valid/mapping.ts +0 -0
  132. package/tests/cli/validation/big-decimal-is-valid/schema.graphql +0 -4
  133. package/tests/cli/validation/big-decimal-is-valid/subgraph.yaml +0 -23
  134. package/tests/cli/validation/call-function-not-found/Abi.json +0 -57
  135. package/tests/cli/validation/call-function-not-found/mapping.ts +0 -0
  136. package/tests/cli/validation/call-function-not-found/schema.graphql +0 -3
  137. package/tests/cli/validation/call-function-not-found/subgraph.yaml +0 -22
  138. package/tests/cli/validation/call-function-not-found.stderr +0 -10
  139. package/tests/cli/validation/call-handler-with-tuple/Abi.json +0 -24
  140. package/tests/cli/validation/call-handler-with-tuple/generated/schema.ts +0 -44
  141. package/tests/cli/validation/call-handler-with-tuple/mapping.ts +0 -0
  142. package/tests/cli/validation/call-handler-with-tuple/schema.graphql +0 -3
  143. package/tests/cli/validation/call-handler-with-tuple/subgraph.yaml +0 -22
  144. package/tests/cli/validation/call-handler-with-tuple.stderr +0 -24
  145. package/tests/cli/validation/conflicting-network-names/Abi.json +0 -7
  146. package/tests/cli/validation/conflicting-network-names/mapping.ts +0 -0
  147. package/tests/cli/validation/conflicting-network-names/schema.graphql +0 -3
  148. package/tests/cli/validation/conflicting-network-names/subgraph.yaml +0 -41
  149. package/tests/cli/validation/conflicting-network-names.stderr +0 -10
  150. package/tests/cli/validation/conflicting-protocol-names/Abi.json +0 -7
  151. package/tests/cli/validation/conflicting-protocol-names/mapping.ts +0 -0
  152. package/tests/cli/validation/conflicting-protocol-names/schema.graphql +0 -3
  153. package/tests/cli/validation/conflicting-protocol-names/subgraph.yaml +0 -41
  154. package/tests/cli/validation/conflicting-protocol-names.stderr +0 -10
  155. package/tests/cli/validation/derived-from-target-type-missing/Abi.json +0 -6
  156. package/tests/cli/validation/derived-from-target-type-missing/mapping.ts +0 -0
  157. package/tests/cli/validation/derived-from-target-type-missing/schema.graphql +0 -4
  158. package/tests/cli/validation/derived-from-target-type-missing/subgraph.yaml +0 -22
  159. package/tests/cli/validation/derived-from-target-type-missing.stderr +0 -5
  160. package/tests/cli/validation/derived-from-with-interface/Gravity.json +0 -1
  161. package/tests/cli/validation/derived-from-with-interface/mapping.ts +0 -22
  162. package/tests/cli/validation/derived-from-with-interface/schema.graphql +0 -19
  163. package/tests/cli/validation/derived-from-with-interface/subgraph.yaml +0 -25
  164. package/tests/cli/validation/duplicate-data-source-name/Abi.json +0 -7
  165. package/tests/cli/validation/duplicate-data-source-name/mapping.ts +0 -0
  166. package/tests/cli/validation/duplicate-data-source-name/schema.graphql +0 -4
  167. package/tests/cli/validation/duplicate-data-source-name/subgraph.yaml +0 -40
  168. package/tests/cli/validation/duplicate-data-source-name.stderr +0 -5
  169. package/tests/cli/validation/duplicate-template-name/Abi.json +0 -7
  170. package/tests/cli/validation/duplicate-template-name/mapping.ts +0 -0
  171. package/tests/cli/validation/duplicate-template-name/schema.graphql +0 -4
  172. package/tests/cli/validation/duplicate-template-name/subgraph.yaml +0 -59
  173. package/tests/cli/validation/duplicate-template-name.stderr +0 -5
  174. package/tests/cli/validation/entity-field-args/Abi.json +0 -7
  175. package/tests/cli/validation/entity-field-args/mapping.ts +0 -0
  176. package/tests/cli/validation/entity-field-args/schema.graphql +0 -4
  177. package/tests/cli/validation/entity-field-args/subgraph.yaml +0 -22
  178. package/tests/cli/validation/entity-field-args.stderr +0 -5
  179. package/tests/cli/validation/ethereum-contract-without-handlers/Abi.json +0 -7
  180. package/tests/cli/validation/ethereum-contract-without-handlers/mapping.ts +0 -0
  181. package/tests/cli/validation/ethereum-contract-without-handlers/schema.graphql +0 -3
  182. package/tests/cli/validation/ethereum-contract-without-handlers/subgraph.yaml +0 -19
  183. package/tests/cli/validation/ethereum-contract-without-handlers.stderr +0 -6
  184. package/tests/cli/validation/event-not-found/Abi.json +0 -7
  185. package/tests/cli/validation/event-not-found/mapping.ts +0 -0
  186. package/tests/cli/validation/event-not-found/schema.graphql +0 -3
  187. package/tests/cli/validation/event-not-found/subgraph.yaml +0 -40
  188. package/tests/cli/validation/event-not-found.stderr +0 -12
  189. package/tests/cli/validation/example-values-found/Abi.json +0 -7
  190. package/tests/cli/validation/example-values-found/generated/ExampleSubgraph/ExampleContract.ts +0 -35
  191. package/tests/cli/validation/example-values-found/generated/schema.ts +0 -44
  192. package/tests/cli/validation/example-values-found/mapping.ts +0 -0
  193. package/tests/cli/validation/example-values-found/schema.graphql +0 -3
  194. package/tests/cli/validation/example-values-found/subgraph.yaml +0 -24
  195. package/tests/cli/validation/example-values-found.stderr +0 -34
  196. package/tests/cli/validation/invalid-abis/InvalidAbi.json +0 -1
  197. package/tests/cli/validation/invalid-abis/mapping.ts +0 -0
  198. package/tests/cli/validation/invalid-abis/schema.graphql +0 -3
  199. package/tests/cli/validation/invalid-abis/subgraph.yaml +0 -22
  200. package/tests/cli/validation/invalid-abis.stderr +0 -5
  201. package/tests/cli/validation/invalid-contract-addresses/Abi.json +0 -7
  202. package/tests/cli/validation/invalid-contract-addresses/mapping.ts +0 -0
  203. package/tests/cli/validation/invalid-contract-addresses/schema.graphql +0 -3
  204. package/tests/cli/validation/invalid-contract-addresses/subgraph.yaml +0 -58
  205. package/tests/cli/validation/invalid-contract-addresses.stderr +0 -14
  206. package/tests/cli/validation/invalid-data-source-template/mapping.ts +0 -0
  207. package/tests/cli/validation/invalid-data-source-template/schema.graphql +0 -3
  208. package/tests/cli/validation/invalid-data-source-template/subgraph.yaml +0 -32
  209. package/tests/cli/validation/invalid-data-source-template.stderr +0 -30
  210. package/tests/cli/validation/invalid-entity-field-types/Abi.json +0 -7
  211. package/tests/cli/validation/invalid-entity-field-types/mapping.ts +0 -0
  212. package/tests/cli/validation/invalid-entity-field-types/schema.graphql +0 -157
  213. package/tests/cli/validation/invalid-entity-field-types/subgraph.yaml +0 -22
  214. package/tests/cli/validation/invalid-entity-field-types.stderr +0 -148
  215. package/tests/cli/validation/invalid-fulltext-directive/Abi.json +0 -7
  216. package/tests/cli/validation/invalid-fulltext-directive/mapping.ts +0 -0
  217. package/tests/cli/validation/invalid-fulltext-directive/schema.graphql +0 -140
  218. package/tests/cli/validation/invalid-fulltext-directive/subgraph.yaml +0 -22
  219. package/tests/cli/validation/invalid-fulltext-directive.stderr +0 -32
  220. package/tests/cli/validation/invalid-graphql-schema/Abi.json +0 -7
  221. package/tests/cli/validation/invalid-graphql-schema/mapping.ts +0 -0
  222. package/tests/cli/validation/invalid-graphql-schema/schema.graphql +0 -8
  223. package/tests/cli/validation/invalid-graphql-schema/subgraph.yaml +0 -22
  224. package/tests/cli/validation/invalid-graphql-schema.stderr +0 -25
  225. package/tests/cli/validation/invalid-manifest/subgraph.yaml +0 -13
  226. package/tests/cli/validation/invalid-manifest-cannot-infer-protocol/subgraph.yaml +0 -12
  227. package/tests/cli/validation/invalid-manifest-cannot-infer-protocol.stderr +0 -5
  228. package/tests/cli/validation/invalid-manifest.stderr +0 -28
  229. package/tests/cli/validation/missing-entity-id/Abi.json +0 -7
  230. package/tests/cli/validation/missing-entity-id/mapping.ts +0 -0
  231. package/tests/cli/validation/missing-entity-id/schema.graphql +0 -3
  232. package/tests/cli/validation/missing-entity-id/subgraph.yaml +0 -22
  233. package/tests/cli/validation/missing-entity-id/types/ExampleSubgraph/ExampleContract.ts +0 -35
  234. package/tests/cli/validation/missing-entity-id/types/schema.ts +0 -27
  235. package/tests/cli/validation/missing-entity-id.stderr +0 -5
  236. package/tests/cli/validation/missing-or-invalid-derived-from-fields/Abi.json +0 -7
  237. package/tests/cli/validation/missing-or-invalid-derived-from-fields/mapping.ts +0 -0
  238. package/tests/cli/validation/missing-or-invalid-derived-from-fields/schema.graphql +0 -40
  239. package/tests/cli/validation/missing-or-invalid-derived-from-fields/subgraph.yaml +0 -22
  240. package/tests/cli/validation/missing-or-invalid-derived-from-fields.stderr +0 -10
  241. package/tests/cli/validation/missing-or-invalid-derived-from-fields.stdout +0 -0
  242. package/tests/cli/validation/near-is-valid/mapping.ts +0 -0
  243. package/tests/cli/validation/near-is-valid/schema.graphql +0 -8
  244. package/tests/cli/validation/near-is-valid/subgraph.yaml +0 -30
  245. package/tests/cli/validation/nested-template-nice-error/Abi.json +0 -7
  246. package/tests/cli/validation/nested-template-nice-error/mapping.ts +0 -0
  247. package/tests/cli/validation/nested-template-nice-error/schema.graphql +0 -3
  248. package/tests/cli/validation/nested-template-nice-error/subgraph.yaml +0 -35
  249. package/tests/cli/validation/nested-template-nice-error.stderr +0 -5
  250. package/tests/cli/validation/no-network-names/Abi.json +0 -7
  251. package/tests/cli/validation/no-network-names/mapping.ts +0 -0
  252. package/tests/cli/validation/no-network-names/schema.graphql +0 -3
  253. package/tests/cli/validation/no-network-names/subgraph.yaml +0 -40
  254. package/tests/cli/validation/no-network-names.stderr +0 -34
  255. package/tests/cli/validation/source-without-address-is-valid/Abi.json +0 -7
  256. package/tests/cli/validation/source-without-address-is-valid/generated/ExampleSubgraph/ExampleContract.ts +0 -35
  257. package/tests/cli/validation/source-without-address-is-valid/mapping.ts +0 -0
  258. package/tests/cli/validation/source-without-address-is-valid/schema.graphql +0 -3
  259. package/tests/cli/validation/source-without-address-is-valid/subgraph.yaml +0 -23
  260. package/tests/cli/validation/source-without-address-is-valid.stderr +0 -24
  261. package/tests/cli/validation/topic0-is-valid/Abi.json +0 -7
  262. package/tests/cli/validation/topic0-is-valid/mapping.ts +0 -0
  263. package/tests/cli/validation/topic0-is-valid/schema.graphql +0 -4
  264. package/tests/cli/validation/topic0-is-valid/subgraph.yaml +0 -24
  265. package/tests/cli/validation.test.ts +0 -226
  266. package/tsconfig.build.json +0 -4
  267. package/tsconfig.json +0 -19
@@ -1,957 +0,0 @@
1
- import fs from 'fs';
2
- import * as graphql from 'graphql/language';
3
- import immutable from 'immutable';
4
-
5
- const List = immutable.List;
6
- const Set = immutable.Set;
7
-
8
- // Builtin scalar types
9
- const BUILTIN_SCALAR_TYPES = ['Boolean', 'Int', 'BigDecimal', 'String', 'BigInt', 'Bytes', 'ID'];
10
-
11
- // Type suggestions for common mistakes
12
- const TYPE_SUGGESTIONS = [
13
- ['Address', 'Bytes'],
14
- ['address', 'Bytes'],
15
- ['Account', 'String'],
16
- ['account', 'String'],
17
- ['AccountId', 'String'],
18
- ['AccountID', 'String'],
19
- ['accountId', 'String'],
20
- ['accountid', 'String'],
21
- ['bytes', 'Bytes'],
22
- ['string', 'String'],
23
- ['bool', 'Boolean'],
24
- ['boolean', 'Boolean'],
25
- ['Bool', 'Boolean'],
26
- ['float', 'BigDecimal'],
27
- ['Float', 'BigDecimal'],
28
- ['int', 'Int'],
29
- ['uint', 'BigInt'],
30
- ['owner', 'String'],
31
- ['Owner', 'String'],
32
- [/^(u|uint)(8|16|24)$/, 'Int'],
33
- [/^(i|int)(8|16|24|32)$/, 'Int'],
34
- [/^(u|uint)32$/, 'BigInt'],
35
- [
36
- /^(u|uint|i|int)(40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)$/,
37
- 'BigInt',
38
- ],
39
- ];
40
-
41
- // As a convention, the type _Schema_ is reserved to define imports on.
42
- const RESERVED_TYPE = '_Schema_';
43
-
44
- /**
45
- * Returns a GraphQL type suggestion for a given input type.
46
- * Returns `undefined` if no suggestion is available for the type.
47
- */
48
- export const typeSuggestion = (typeName: string) =>
49
- TYPE_SUGGESTIONS.filter(([pattern, _]) => {
50
- return typeof pattern === 'string' ? pattern === typeName : typeName.match(pattern);
51
- }).map(([_, suggestion]) => suggestion)[0];
52
-
53
- const loadSchema = (filename: string) => {
54
- try {
55
- return fs.readFileSync(filename, 'utf-8');
56
- } catch (e) {
57
- throw new Error(`Failed to load GraphQL schema: ${e}`);
58
- }
59
- };
60
-
61
- const parseSchema = (doc: string) => {
62
- try {
63
- return graphql.parse(doc);
64
- } catch (e) {
65
- throw new Error(`Invalid GraphQL schema: ${e}`);
66
- }
67
- };
68
-
69
- const validateEntityDirective = (def: any) =>
70
- def.directives.find((directive: any) => directive.name.value === 'entity')
71
- ? List()
72
- : immutable.fromJS([
73
- {
74
- loc: def.loc,
75
- entity: def.name.value,
76
- message: `Defined without @entity directive`,
77
- },
78
- ]);
79
-
80
- const validateEntityID = (def: any) => {
81
- const idField = def.fields.find((field: any) => field.name.value === 'id');
82
-
83
- if (idField === undefined) {
84
- return immutable.fromJS([
85
- {
86
- loc: def.loc,
87
- entity: def.name.value,
88
- message: `Missing field: id: ID!`,
89
- },
90
- ]);
91
- }
92
-
93
- if (
94
- idField.type.kind === 'NonNullType' &&
95
- idField.type.type.kind === 'NamedType' &&
96
- (idField.type.type.name.value === 'ID' ||
97
- idField.type.type.name.value === 'Bytes' ||
98
- idField.type.type.name.value === 'String')
99
- ) {
100
- return List();
101
- }
102
- return immutable.fromJS([
103
- {
104
- loc: idField.loc,
105
- entity: def.name.value,
106
- message: `Field 'id': Entity ids must be of type Bytes! or String!`,
107
- },
108
- ]);
109
- };
110
-
111
- const validateListFieldType = (def: any, field: any) =>
112
- field.type.kind === 'NonNullType' &&
113
- field.type.kind === 'ListType' &&
114
- field.type.type.kind !== 'NonNullType'
115
- ? immutable.fromJS([
116
- {
117
- loc: field.loc,
118
- entity: def.name.value,
119
- message: `\
120
- Field '${field.name.value}':
121
- Field has type [${field.type.type.name.value}]! but
122
- must have type [${field.type.type.name.value}!]!
123
-
124
- Reason: Lists with null elements are not supported.`,
125
- },
126
- ])
127
- : field.type.kind === 'ListType' && field.type.type.kind !== 'NonNullType'
128
- ? immutable.fromJS([
129
- {
130
- loc: field.loc,
131
- entity: def.name.value,
132
- message: `\
133
- Field '${field.name.value}':
134
- Field has type [${field.type.type.name.value}] but
135
- must have type [${field.type.type.name.value}!]
136
-
137
- Reason: Lists with null elements are not supported.`,
138
- },
139
- ])
140
- : List();
141
-
142
- const unwrapType = (type: any) => {
143
- const innerTypeFromList = (listType: any): any =>
144
- listType.type.kind === 'NonNullType' ? innerTypeFromNonNull(listType.type) : listType.type;
145
-
146
- const innerTypeFromNonNull = (nonNullType: any): any =>
147
- nonNullType.type.kind === 'ListType' ? innerTypeFromList(nonNullType.type) : nonNullType.type;
148
-
149
- // Obtain the inner-most type from the field
150
- return type.kind === 'NonNullType'
151
- ? innerTypeFromNonNull(type)
152
- : type.kind === 'ListType'
153
- ? innerTypeFromList(type)
154
- : type;
155
- };
156
-
157
- const gatherLocalTypes = (defs: readonly graphql.DefinitionNode[]) =>
158
- defs
159
- .filter(
160
- def =>
161
- def.kind === 'ObjectTypeDefinition' ||
162
- def.kind === 'EnumTypeDefinition' ||
163
- def.kind === 'InterfaceTypeDefinition',
164
- )
165
- .map(
166
- def =>
167
- // @ts-expect-error TODO: name field does not exist on definition, really?
168
- def.name.value,
169
- );
170
-
171
- const gatherImportedTypes = (defs: readonly graphql.DefinitionNode[]) =>
172
- defs
173
- .filter(
174
- def =>
175
- def.kind === 'ObjectTypeDefinition' &&
176
- def.name.value == RESERVED_TYPE &&
177
- def.directives?.find(
178
- (directive: any) =>
179
- directive.name.value == 'import' &&
180
- directive.arguments.find((argument: any) => argument.name.value == 'types'),
181
- ),
182
- )
183
- .map(def =>
184
- // @ts-expect-error TODO: directives field does not exist on definition, really?
185
- def.directives
186
- .filter(
187
- (directive: any) =>
188
- directive.name.value == 'import' &&
189
- directive.arguments.find((argument: any) => argument.name.value == 'types'),
190
- )
191
- .map((imp: any) =>
192
- imp.arguments.find(
193
- (argument: any) => argument.name.value == 'types' && argument.value.kind == 'ListValue',
194
- ),
195
- )
196
- .map((arg: any) =>
197
- arg.value.values.map((type: any) =>
198
- type.kind == 'StringValue'
199
- ? type.value
200
- : type.kind == 'ObjectValue' &&
201
- type.fields.find(
202
- (field: any) => field.name.value == 'as' && field.value.kind == 'StringValue',
203
- )
204
- ? type.fields.find((field: any) => field.name.value == 'as').value.value
205
- : undefined,
206
- ),
207
- ),
208
- )
209
- .reduce(
210
- (flattened, types_args) =>
211
- flattened.concat(
212
- types_args.reduce((flattened: any, types_arg: any[]) => {
213
- types_arg.forEach(type => (type ? flattened.push(type) : undefined));
214
- return flattened;
215
- }, []),
216
- ),
217
- [],
218
- );
219
-
220
- const entityTypeByName = (defs: any[], name: string) =>
221
- defs
222
- .filter(
223
- def =>
224
- def.kind === 'InterfaceTypeDefinition' ||
225
- (def.kind === 'ObjectTypeDefinition' &&
226
- def.directives.find((directive: any) => directive.name.value === 'entity')),
227
- )
228
- .find(def => def.name.value === name);
229
-
230
- const fieldTargetEntityName = (field: any) => unwrapType(field.type).name.value;
231
-
232
- const fieldTargetEntity = (defs: any[], field: any) =>
233
- entityTypeByName(defs, fieldTargetEntityName(field));
234
-
235
- const validateInnerFieldType = (defs: any[], def: any, field: any) => {
236
- const innerType = unwrapType(field.type);
237
-
238
- // Get the name of the type
239
- const typeName = innerType.name.value;
240
-
241
- // Look up a possible suggestion for the type to catch common mistakes
242
- const suggestion = typeSuggestion(typeName);
243
-
244
- // Collect all types that we can use here: built-ins + entities + enums + interfaces
245
- const availableTypes = List.of(
246
- ...BUILTIN_SCALAR_TYPES,
247
- ...gatherLocalTypes(defs),
248
- ...gatherImportedTypes(defs),
249
- );
250
-
251
- // Check whether the type name is available, otherwise return an error
252
- return availableTypes.includes(typeName)
253
- ? List()
254
- : immutable.fromJS([
255
- {
256
- loc: field.loc,
257
- entity: def.name.value,
258
- message: `\
259
- Field '${field.name.value}': \
260
- Unknown type '${typeName}'.${suggestion !== undefined ? ` Did you mean '${suggestion}'?` : ''}`,
261
- },
262
- ]);
263
- };
264
-
265
- const validateEntityFieldType = (defs: any[], def: any, field: any) =>
266
- List.of(...validateListFieldType(def, field), ...validateInnerFieldType(defs, def, field));
267
-
268
- const validateEntityFieldArguments = (_defs: any[], def: any, field: any) =>
269
- field.arguments.length > 0
270
- ? immutable.fromJS([
271
- {
272
- loc: field.loc,
273
- entity: def.name.value,
274
- message: `\
275
- Field '${field.name.value}': \
276
- Field arguments are not supported.`,
277
- },
278
- ])
279
- : List();
280
-
281
- const validateDerivedFromDirective = (defs: any[], def: any, field: any, directive: any) => {
282
- // Validate that there is a `field` argument and nothing else
283
- if (directive.arguments.length !== 1 || directive.arguments[0].name.value !== 'field') {
284
- return immutable.fromJS([
285
- {
286
- loc: directive.loc,
287
- entity: def.name.value,
288
- message: `\
289
- Field '${field.name.value}': \
290
- @derivedFrom directive must have a 'field' argument`,
291
- },
292
- ]);
293
- }
294
-
295
- // Validate that the "field" argument value is a string
296
- if (directive.arguments[0].value.kind !== 'StringValue') {
297
- return immutable.fromJS([
298
- {
299
- loc: directive.loc,
300
- entity: def.name.value,
301
- message: `\
302
- Field '${field.name.value}': \
303
- Value of the @derivedFrom 'field' argument must be a string`,
304
- },
305
- ]);
306
- }
307
-
308
- const targetEntity = fieldTargetEntity(defs, field);
309
- if (targetEntity === undefined) {
310
- // This is handled in `validateInnerFieldType` but if we don't catch
311
- // the undefined case here, the code below will throw, as it assumes
312
- // the target entity exists
313
- return immutable.fromJS([]);
314
- }
315
-
316
- const derivedFromField = targetEntity.fields.find(
317
- (field: any) => field.name.value === directive.arguments[0].value.value,
318
- );
319
-
320
- if (derivedFromField === undefined) {
321
- return immutable.fromJS([
322
- {
323
- loc: directive.loc,
324
- entity: def.name.value,
325
- message: `\
326
- Field '${field.name.value}': \
327
- @derivedFrom field '${directive.arguments[0].value.value}' \
328
- does not exist on type '${targetEntity.name.value}'`,
329
- },
330
- ]);
331
- }
332
-
333
- const backrefTypeName = unwrapType(derivedFromField.type);
334
- const backRefEntity = entityTypeByName(defs, backrefTypeName.name.value);
335
-
336
- // The field we are deriving from must either have type 'def' or one of the
337
- // interface types that 'def' is implementing
338
- if (
339
- !backRefEntity ||
340
- (backRefEntity.name.value !== def.name.value &&
341
- !def.interfaces.find((intf: any) => intf.name.value === backRefEntity.name.value))
342
- ) {
343
- return immutable.fromJS([
344
- {
345
- loc: directive.loc,
346
- entity: def.name.value,
347
- message: `\
348
- Field '${field.name.value}': \
349
- @derivedFrom field '${directive.arguments[0].value.value}' \
350
- on type '${targetEntity.name.value}' must have the type \
351
- '${def.name.value}', '${def.name.value}!', '[${def.name.value}!]!', \
352
- or one of the interface types that '${def.name.value}' implements`,
353
- },
354
- ]);
355
- }
356
-
357
- return List();
358
- };
359
-
360
- const validateEntityFieldDirective = (defs: any[], def: any, field: any, directive: any) =>
361
- directive.name.value === 'derivedFrom'
362
- ? validateDerivedFromDirective(defs, def, field, directive)
363
- : List();
364
-
365
- const validateEntityFieldDirectives = (defs: any[], def: any, field: any) =>
366
- field.directives.reduce(
367
- (errors: any[], directive: any) =>
368
- errors.concat(validateEntityFieldDirective(defs, def, field, directive)),
369
- List(),
370
- );
371
-
372
- const validateEntityFields = (defs: any, def: any) =>
373
- def.fields.reduce(
374
- (errors: any[], field: any) =>
375
- errors
376
- .concat(validateEntityFieldType(defs, def, field))
377
- .concat(validateEntityFieldArguments(defs, def, field))
378
- .concat(validateEntityFieldDirectives(defs, def, field)),
379
- List(),
380
- );
381
-
382
- const validateNoImportDirective = (def: any) =>
383
- def.directives.find((directive: any) => directive.name.value == 'import')
384
- ? List([
385
- immutable.fromJS({
386
- loc: def.name.loc,
387
- entity: def.name.value,
388
- message: `@import directive only allowed on '${RESERVED_TYPE}' type`,
389
- }),
390
- ])
391
- : List();
392
-
393
- const validateNoFulltext = (def: any) =>
394
- def.directives.find((directive: any) => directive.name.value == 'fulltext')
395
- ? List([
396
- immutable.fromJS({
397
- loc: def.name.loc,
398
- entity: def.name.value,
399
- message: `@fulltext directive only allowed on '${RESERVED_TYPE}' type`,
400
- }),
401
- ])
402
- : List();
403
-
404
- const validateFulltextFields = (def: any, directive: any) => {
405
- return directive.arguments.reduce((errors: any[], argument: any) => {
406
- return errors.concat(
407
- ['name', 'language', 'algorithm', 'include'].includes(argument.name.value)
408
- ? List([])
409
- : List([
410
- immutable.fromJS({
411
- loc: directive.name.loc,
412
- entity: def.name.value,
413
- directive: fulltextDirectiveName(directive),
414
- message: `found invalid argument: '${argument.name.value}', @fulltext directives only allow 'name', 'language', 'algorithm', and 'includes' arguments`,
415
- }),
416
- ]),
417
- );
418
- }, List([]));
419
- };
420
-
421
- const validateFulltextName = (def: any, directive: any) => {
422
- const name = directive.arguments.find((argument: any) => argument.name.value == 'name');
423
- return name
424
- ? validateFulltextArgumentName(def, directive, name)
425
- : List([
426
- immutable.fromJS({
427
- loc: directive.name.loc,
428
- entity: def.name.value,
429
- directive: fulltextDirectiveName(directive),
430
- message: `@fulltext argument 'name' must be specified`,
431
- }),
432
- ]);
433
- };
434
-
435
- const validateFulltextArgumentName = (def: any, directive: any, argument: any) => {
436
- return argument.value.kind != 'StringValue'
437
- ? List([
438
- immutable.fromJS({
439
- loc: directive.name.loc,
440
- entity: def.name.value,
441
- directive: fulltextDirectiveName(directive),
442
- message: `@fulltext argument 'name' must be a string`,
443
- }),
444
- ])
445
- : List([]);
446
- };
447
-
448
- const fulltextDirectiveName = (directive: any) => {
449
- const arg = directive.arguments.find((argument: any) => argument.name.value == 'name');
450
- return arg ? arg.value.value : 'Other';
451
- };
452
-
453
- const validateFulltextLanguage = (def: any, directive: any) => {
454
- const language = directive.arguments.find((argument: any) => argument.name.value == 'language');
455
- return language
456
- ? validateFulltextArgumentLanguage(def, directive, language)
457
- : List([
458
- immutable.fromJS({
459
- loc: directive.name.loc,
460
- entity: def.name.value,
461
- directive: fulltextDirectiveName(directive),
462
- message: `@fulltext argument 'language' must be specified`,
463
- }),
464
- ]);
465
- };
466
-
467
- const validateFulltextArgumentLanguage = (def: any, directive: any, argument: any) => {
468
- const languages = [
469
- 'simple',
470
- 'da',
471
- 'nl',
472
- 'en',
473
- 'fi',
474
- 'fr',
475
- 'de',
476
- 'hu',
477
- 'it',
478
- 'no',
479
- 'pt',
480
- 'ro',
481
- 'ru',
482
- 'es',
483
- 'sv',
484
- 'tr',
485
- ];
486
- if (argument.value.kind != 'EnumValue') {
487
- return List([
488
- immutable.fromJS({
489
- loc: directive.name.loc,
490
- entity: def.name.value,
491
- directive: fulltextDirectiveName(directive),
492
- message: `@fulltext 'language' value must be one of: ${languages.join(', ')}`,
493
- }),
494
- ]);
495
- }
496
- if (!languages.includes(argument.value.value)) {
497
- return List([
498
- immutable.fromJS({
499
- loc: directive.name.loc,
500
- entity: def.name.value,
501
- directive: fulltextDirectiveName(directive),
502
- message: `@fulltext directive 'language' value must be one of: ${languages.join(', ')}`,
503
- }),
504
- ]);
505
- }
506
- return List([]);
507
- };
508
-
509
- const validateFulltextAlgorithm = (def: any, directive: any) => {
510
- const algorithm = directive.arguments.find((argument: any) => argument.name.value == 'algorithm');
511
- return algorithm
512
- ? validateFulltextArgumentAlgorithm(def, directive, algorithm)
513
- : List([
514
- immutable.fromJS({
515
- loc: directive.name.loc,
516
- entity: def.name.value,
517
- directive: fulltextDirectiveName(directive),
518
- message: `@fulltext argument 'algorithm' must be specified`,
519
- }),
520
- ]);
521
- };
522
-
523
- const validateFulltextArgumentAlgorithm = (def: any, directive: any, argument: any) => {
524
- if (argument.value.kind != 'EnumValue') {
525
- return List([
526
- immutable.fromJS({
527
- loc: directive.name.loc,
528
- entity: def.name.value,
529
- directive: fulltextDirectiveName(directive),
530
- message: `@fulltext argument 'algorithm' must be one of: rank, proximityRank`,
531
- }),
532
- ]);
533
- }
534
- if (!['rank', 'proximityRank'].includes(argument.value.value)) {
535
- return List([
536
- immutable.fromJS({
537
- loc: directive.name.loc,
538
- entity: def.name.value,
539
- directive: fulltextDirectiveName(directive),
540
- message: `@fulltext 'algorithm' value, '${argument.value.value}', must be one of: rank, proximityRank`,
541
- }),
542
- ]);
543
- }
544
- return List([]);
545
- };
546
-
547
- const validateFulltextInclude = (def: any, directive: any) => {
548
- const include = directive.arguments.find((argument: any) => argument.name.value == 'include');
549
- if (include) {
550
- if (include.value.kind != 'ListValue') {
551
- return List([
552
- immutable.fromJS({
553
- loc: directive.name.loc,
554
- entity: def.name.value,
555
- directive: fulltextDirectiveName(directive),
556
- message: `@fulltext argument 'include' must be a list`,
557
- }),
558
- ]);
559
- }
560
- return include.value.values.reduce(
561
- (errors: any, type: any) =>
562
- errors.concat(validateFulltextArgumentInclude(def, directive, type)),
563
- List(),
564
- );
565
- }
566
- return List([
567
- immutable.fromJS({
568
- loc: directive.name.loc,
569
- entity: def.name.value,
570
- directive: fulltextDirectiveName(directive),
571
- message: `@fulltext argument 'include' must be specified`,
572
- }),
573
- ]);
574
- };
575
-
576
- const validateFulltextArgumentInclude = (def: any, directive: any, argument: any) => {
577
- if (argument.kind != 'ObjectValue') {
578
- return List([
579
- immutable.fromJS({
580
- loc: directive.name.loc,
581
- entity: def.name.value,
582
- directive: fulltextDirectiveName(directive),
583
- message: `@fulltext argument 'include' must have the form '[{entity: "entityName", fields: [{name: "fieldName"}, ...]} ...]`,
584
- }),
585
- ]);
586
- }
587
- if (argument.fields.length != 2) {
588
- return List([
589
- immutable.fromJS({
590
- loc: directive.name.loc,
591
- entity: def.name.value,
592
- directive: fulltextDirectiveName(directive),
593
- message: `@fulltext argument include must have two fields, 'entity' and 'fields'`,
594
- }),
595
- ]);
596
- }
597
- return argument.fields.reduce(
598
- (errors: any[], field: any) =>
599
- errors.concat(validateFulltextArgumentIncludeFields(def, directive, field)),
600
- List([]),
601
- );
602
- };
603
-
604
- const validateFulltextArgumentIncludeFields = (def: any, directive: any, field: any) => {
605
- if (!['entity', 'fields'].includes(field.name.value)) {
606
- return List([
607
- immutable.fromJS({
608
- loc: directive.name.loc,
609
- entity: def.name.value,
610
- directive: fulltextDirectiveName(directive),
611
- message: `@fulltext argument 'include > ${field.name.value}' must be be one of: entity, fields`,
612
- }),
613
- ]);
614
- }
615
- if (field.name.value == 'entity' && field.value.kind != 'StringValue') {
616
- return List([
617
- immutable.fromJS({
618
- loc: directive.name.loc,
619
- entity: def.name.value,
620
- directive: fulltextDirectiveName(directive),
621
- message: `@fulltext argument 'include > entity' must be the name of an entity in the schema enclosed in double quotes`,
622
- }),
623
- ]);
624
- }
625
- if (field.name.value == 'fields' && field.value.kind != 'ListValue') {
626
- return List([
627
- immutable.fromJS({
628
- loc: directive.name.loc,
629
- entity: def.name.value,
630
- directive: fulltextDirectiveName(directive),
631
- message: `@fulltext argument 'include > fields' must be a list`,
632
- }),
633
- ]);
634
- }
635
- if (field.name.value == 'fields' && field.value.kind == 'ListValue') {
636
- return field.value.values.reduce(
637
- (errors: any[], field: any) =>
638
- errors.concat(validateFulltextArgumentIncludeFieldsObjects(def, directive, field)),
639
- List([]),
640
- );
641
- }
642
- return List([]);
643
- };
644
-
645
- const validateFulltextArgumentIncludeFieldsObjects = (def: any, directive: any, argument: any) => {
646
- if (argument.kind != 'ObjectValue') {
647
- return List([
648
- immutable.fromJS({
649
- loc: directive.name.loc,
650
- entity: def.name.value,
651
- directive: fulltextDirectiveName(directive),
652
- message: `@fulltext argument 'include > fields' must have the form '[{ name: "fieldName" }, ...]`,
653
- }),
654
- ]);
655
- }
656
- return argument.fields.reduce(
657
- (errors: any[], field: any) =>
658
- errors.concat(validateFulltextArgumentIncludeArgumentFieldsObject(def, directive, field)),
659
- List(),
660
- );
661
- };
662
-
663
- const validateFulltextArgumentIncludeArgumentFieldsObject = (
664
- def: any,
665
- directive: any,
666
- field: any,
667
- ) => {
668
- if (!['name'].includes(field.name.value)) {
669
- return List([
670
- immutable.fromJS({
671
- loc: directive.name.loc,
672
- entity: def.name.value,
673
- directive: fulltextDirectiveName(directive),
674
- message: `@fulltext argument 'include > fields' has invalid member '${field.name.value}', must be one of: name`,
675
- }),
676
- ]);
677
- }
678
- if (field.name.value == 'name' && field.value.kind != 'StringValue') {
679
- return List([
680
- immutable.fromJS({
681
- loc: directive.name.loc,
682
- entity: def.name.value,
683
- directive: fulltextDirectiveName(directive),
684
- message: `@fulltext argument 'include > fields > name' must be the name of an entity field enclosed in double quotes`,
685
- }),
686
- ]);
687
- }
688
- return List([]);
689
- };
690
-
691
- const importDirectiveTypeValidators = {
692
- StringValue: (_def: any, _directive: any, _type: any) => List(),
693
- ObjectValue: (def: any, directive: any, type: any) => {
694
- const errors = List();
695
- if (type.fields.length != 2) {
696
- return errors.push(
697
- immutable.fromJS({
698
- loc: directive.name.loc,
699
- entity: def.name.value,
700
- message: `Import must be one of "Name" or { name: "Name", as: "Alias" }`,
701
- }),
702
- );
703
- }
704
- return type.fields.reduce((errors: any[], field: any) => {
705
- if (!['name', 'as'].includes(field.name.value)) {
706
- return errors.push(
707
- immutable.fromJS({
708
- loc: directive.name.loc,
709
- entity: def.name.value,
710
- message: `@import field '${field.name.value}' invalid, may only be one of: name, as`,
711
- }),
712
- );
713
- }
714
- if (field.value.kind != 'StringValue') {
715
- return errors.push(
716
- immutable.fromJS({
717
- loc: directive.name.loc,
718
- entity: def.name.value,
719
- message: `@import fields [name, as] must be strings`,
720
- }),
721
- );
722
- }
723
- return errors;
724
- }, errors);
725
- },
726
- };
727
-
728
- const validateImportDirectiveType = (
729
- def: any,
730
- directive: any,
731
- type: { kind: keyof typeof importDirectiveTypeValidators },
732
- ) => {
733
- return importDirectiveTypeValidators[type.kind]
734
- ? importDirectiveTypeValidators[type.kind](def, directive, type)
735
- : List([
736
- immutable.fromJS({
737
- loc: directive.name.loc,
738
- entity: def.name.value,
739
- message: `Import must be one of "Name" or { name: "Name", as: "Alias" }`,
740
- }),
741
- ]);
742
- };
743
-
744
- const validateImportDirectiveArgumentTypes = (def: any, directive: any, argument: any) => {
745
- if (argument.value.kind != 'ListValue') {
746
- return List([
747
- immutable.fromJS({
748
- loc: directive.name.loc,
749
- entity: def.name.value,
750
- message: `@import argument 'types' must be an list`,
751
- }),
752
- ]);
753
- }
754
-
755
- return argument.value.values.reduce(
756
- (errors: any[], type: any) => errors.concat(validateImportDirectiveType(def, directive, type)),
757
- List(),
758
- );
759
- };
760
-
761
- const validateImportDirectiveArgumentFrom = (def: any, directive: any, argument: any) => {
762
- if (argument.value.kind != 'ObjectValue') {
763
- return List([
764
- immutable.fromJS({
765
- loc: directive.name.loc,
766
- entity: def.name.value,
767
- message: `@import argument 'from' must be an object`,
768
- }),
769
- ]);
770
- }
771
-
772
- if (argument.value.fields.length != 1) {
773
- return List([
774
- immutable.fromJS({
775
- loc: directive.name.loc,
776
- entity: def.name.value,
777
- message: `@import argument 'from' must have an 'id' or 'name' field`,
778
- }),
779
- ]);
780
- }
781
-
782
- return argument.value.fields.reduce((errors: any[], field: any) => {
783
- if (!['name', 'id'].includes(field.name.value)) {
784
- return errors.push(
785
- immutable.fromJS({
786
- loc: field.name.loc,
787
- entity: def.name.value,
788
- message: `@import argument 'from' must be one of { name: "Name" } or { id: "ID" }`,
789
- }),
790
- );
791
- }
792
- if (field.value.kind != 'StringValue') {
793
- return errors.push(
794
- immutable.fromJS({
795
- loc: field.name.loc,
796
- entity: def.name.value,
797
- message: `@import argument 'from' must be one of { name: "Name" } or { id: "ID" } with string values`,
798
- }),
799
- );
800
- }
801
- return errors;
802
- }, List());
803
- };
804
-
805
- const validateImportDirectiveFields = (def: any, directive: any) => {
806
- return directive.arguments.reduce((errors: any[], argument: any) => {
807
- return errors.concat(
808
- ['types', 'from'].includes(argument.name.value)
809
- ? List([])
810
- : List([
811
- immutable.fromJS({
812
- loc: directive.name.loc,
813
- entity: def.name.value,
814
- message: `found invalid argument: '${argument.name.value}', @import directives only allow 'types' and 'from' arguments`,
815
- }),
816
- ]),
817
- );
818
- }, List([]));
819
- };
820
-
821
- const validateImportDirectiveTypes = (def: any, directive: any) => {
822
- const types = directive.arguments.find((argument: any) => argument.name.value == 'types');
823
- return types
824
- ? validateImportDirectiveArgumentTypes(def, directive, types)
825
- : List([
826
- immutable.fromJS({
827
- loc: directive.name.loc,
828
- entity: def.name.value,
829
- message: `@import argument 'types' must be specified`,
830
- }),
831
- ]);
832
- };
833
-
834
- const validateImportDirectiveFrom = (def: any, directive: any) => {
835
- const from = directive.arguments.find((argument: any) => argument.name.value == 'from');
836
- return from
837
- ? validateImportDirectiveArgumentFrom(def, directive, from)
838
- : List([
839
- immutable.fromJS({
840
- loc: directive.name.loc,
841
- entity: def.name.value,
842
- message: `@import argument 'from' must be specified`,
843
- }),
844
- ]);
845
- };
846
-
847
- const validateImportDirective = (def: any, directive: any) =>
848
- List.of(
849
- ...validateImportDirectiveFields(def, directive),
850
- ...validateImportDirectiveTypes(def, directive),
851
- ...validateImportDirectiveFrom(def, directive),
852
- );
853
-
854
- const validateFulltext = (def: any, directive: any) =>
855
- List.of(
856
- ...validateFulltextFields(def, directive),
857
- ...validateFulltextName(def, directive),
858
- ...validateFulltextLanguage(def, directive),
859
- ...validateFulltextAlgorithm(def, directive),
860
- ...validateFulltextInclude(def, directive),
861
- );
862
-
863
- const validateSubgraphSchemaDirective = (def: any, directive: any) => {
864
- if (directive.name.value == 'import') {
865
- return validateImportDirective(def, directive);
866
- }
867
- if (directive.name.value == 'fulltext') {
868
- return validateFulltext(def, directive);
869
- }
870
- return List([
871
- immutable.fromJS({
872
- loc: directive.name.loc,
873
- entity: def.name.value,
874
- message: `${RESERVED_TYPE} type only allows @import and @fulltext directives`,
875
- }),
876
- ]);
877
- };
878
-
879
- const validateSubgraphSchemaDirectives = (def: any) =>
880
- def.directives.reduce(
881
- (errors: any[], directive: any) =>
882
- errors.concat(validateSubgraphSchemaDirective(def, directive)),
883
- List(),
884
- );
885
-
886
- const validateTypeHasNoFields = (def: any) =>
887
- def.fields.length
888
- ? List([
889
- immutable.fromJS({
890
- loc: def.name.loc,
891
- entity: def.name.value,
892
- message: `${def.name.value} type is not allowed any fields by convention`,
893
- }),
894
- ])
895
- : List();
896
-
897
- const validateAtLeastOneExtensionField = (_def: any) => List();
898
-
899
- const typeDefinitionValidators = {
900
- ObjectTypeDefinition: (defs: any[], def: any) =>
901
- def.name && def.name.value == RESERVED_TYPE
902
- ? List.of(...validateSubgraphSchemaDirectives(def), ...validateTypeHasNoFields(def))
903
- : List.of(
904
- ...validateEntityDirective(def),
905
- ...validateEntityID(def),
906
- ...validateEntityFields(defs, def),
907
- ...validateNoImportDirective(def),
908
- ...validateNoFulltext(def),
909
- ),
910
- ObjectTypeExtension: (_defs: any[], def: any) => validateAtLeastOneExtensionField(def),
911
- };
912
-
913
- const validateTypeDefinition = (defs: any, def: { kind: keyof typeof typeDefinitionValidators }) =>
914
- typeDefinitionValidators[def.kind] !== undefined
915
- ? typeDefinitionValidators[def.kind](defs, def)
916
- : List();
917
-
918
- const validateTypeDefinitions = (defs: any) =>
919
- defs.reduce(
920
- (errors: any[], def: any) => errors.concat(validateTypeDefinition(defs, def)),
921
- List(),
922
- );
923
-
924
- const validateNamingCollisionsInTypes = (types: any) => {
925
- let seen = Set();
926
- let conflicting = Set();
927
- return types.reduce((errors: immutable.List<any>, type: any) => {
928
- if (seen.has(type) && !conflicting.has(type)) {
929
- errors = errors.push(
930
- immutable.fromJS({
931
- loc: { start: 1, end: 1 },
932
- entity: type,
933
- message: `Type '${type}' is defined more than once`,
934
- }),
935
- );
936
- conflicting = conflicting.add(type);
937
- } else {
938
- seen = seen.add(type);
939
- }
940
- return errors;
941
- }, List());
942
- };
943
-
944
- const validateNamingCollisions = (local: any[], imported: any) =>
945
- validateNamingCollisionsInTypes(local.concat(imported));
946
-
947
- export const validateSchema = (filename: string) => {
948
- const doc = loadSchema(filename);
949
- const schema = parseSchema(doc);
950
- return List.of(
951
- ...validateTypeDefinitions(schema.definitions),
952
- ...validateNamingCollisions(
953
- gatherLocalTypes(schema.definitions),
954
- gatherImportedTypes(schema.definitions),
955
- ),
956
- );
957
- };