Skip to content

Commit 4311d0e

Browse files
graph codegen: handle reserved words (#1929)
* handle reserved words in abi * handle reserved words in schema.ts generation * handle reserved words in scaffolding * cleanup * don't rename fields themselves, only functions * add test * changeset * remove unnecessary reserved words
1 parent 4914d79 commit 4311d0e

File tree

5 files changed

+92
-7
lines changed

5 files changed

+92
-7
lines changed

.changeset/giant-eyes-play.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphprotocol/graph-cli': minor
3+
---
4+
5+
`graph codegen`: handle events with fields with reserved names #1896

packages/cli/src/codegen/schema.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ describe('Schema code generator', { concurrent: true }, () => {
7272
count: Int!
7373
isActive: Boolean
7474
75+
# reserved word
76+
yield: Int!
77+
7578
# derivedFrom
7679
wallets: [Wallet!] @derivedFrom(field: "account")
7780
@@ -248,6 +251,26 @@ describe('Schema code generator', { concurrent: true }, () => {
248251
this.set('count', Value.fromI32(value))
249252
`,
250253
},
254+
{
255+
name: 'get yield_',
256+
params: [],
257+
returnType: new NamedType('i32'),
258+
body: `let value = this.get('yield')
259+
if (!value || value.kind == ValueKind.NULL) {
260+
return 0
261+
} else {
262+
return value.toI32()
263+
}
264+
`,
265+
},
266+
{
267+
name: 'set yield_',
268+
params: [new Param('value', new NamedType('i32'))],
269+
returnType: undefined,
270+
body: `
271+
this.set('yield', Value.fromI32(value))
272+
`,
273+
},
251274
{
252275
name: 'get isActive',
253276
params: [],

packages/cli/src/codegen/schema.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import debug from '../debug.js';
1111
import Schema from '../schema.js';
1212
import * as typesCodegen from './types/index.js';
1313
import * as tsCodegen from './typescript.js';
14+
import * as util from './util.js';
1415

1516
class IdField {
1617
static BYTES = Symbol('Bytes');
@@ -308,6 +309,7 @@ export default class SchemaCodeGenerator {
308309
_generateEntityFieldGetter(_entityDef: ObjectTypeDefinitionNode, fieldDef: FieldDefinitionNode) {
309310
const isDerivedField = this._isDerivedField(fieldDef);
310311
const name = fieldDef.name.value;
312+
const safeName = util.handleReservedWord(name);
311313

312314
if (isDerivedField) {
313315
schemaCodeGeneratorDebug.extend('_generateEntityFieldGetter')(
@@ -339,7 +341,7 @@ export default class SchemaCodeGenerator {
339341
}`;
340342

341343
return tsCodegen.method(
342-
`get ${name}`,
344+
`get ${safeName}`,
343345
[],
344346
returnType,
345347
`
@@ -351,6 +353,8 @@ export default class SchemaCodeGenerator {
351353
_generateDerivedFieldGetter(entityDef: ObjectTypeDefinitionNode, fieldDef: FieldDefinitionNode) {
352354
const entityName = entityDef.name.value;
353355
const name = fieldDef.name.value;
356+
const safeName = util.handleReservedWord(name);
357+
354358
schemaCodeGeneratorDebug.extend('_generateDerivedFieldGetter')(
355359
`Generating derived field '${name}' getter for Entity '${entityName}'`,
356360
);
@@ -390,7 +394,7 @@ export default class SchemaCodeGenerator {
390394
const toValueString = idIsBytes ? '.toBytes().toHexString()' : '.toString()';
391395

392396
return tsCodegen.method(
393-
`get ${name}`,
397+
`get ${safeName}`,
394398
[],
395399
returnType,
396400
`
@@ -415,6 +419,7 @@ export default class SchemaCodeGenerator {
415419
fieldDef: FieldDefinitionNode,
416420
) {
417421
const name = fieldDef.name.value;
422+
const safeName = util.handleReservedWord(name);
418423
const gqlType = fieldDef.type;
419424
const fieldValueType = this._valueTypeFromGraphQl(gqlType);
420425
const returnType = this._typeFromGraphQl(gqlType);
@@ -428,7 +433,7 @@ export default class SchemaCodeGenerator {
428433
}`;
429434

430435
return tsCodegen.method(
431-
`get ${name}`,
436+
`get ${safeName}`,
432437
[],
433438
returnType,
434439
`
@@ -439,6 +444,7 @@ export default class SchemaCodeGenerator {
439444
}
440445
_generateEntityFieldSetter(_entityDef: ObjectTypeDefinitionNode, fieldDef: FieldDefinitionNode) {
441446
const name = fieldDef.name.value;
447+
const safeName = util.handleReservedWord(name);
442448
const isDerivedField = !!fieldDef.directives?.find(
443449
directive => directive.name.value === 'derivedFrom',
444450
);
@@ -477,7 +483,7 @@ Suggestion: add an '!' to the member type of the List, change from '[${baseType}
477483
`;
478484

479485
return tsCodegen.method(
480-
`set ${name}`,
486+
`set ${safeName}`,
481487
[tsCodegen.param('value', paramType)],
482488
undefined,
483489
isNullable ? setNullable : setNonNullable,

packages/cli/src/codegen/util.ts

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function disambiguateNames<T>({
99
}) {
1010
const collisionCounter = new Map();
1111
return values.map((value, index) => {
12-
const name = getName(value, index);
12+
const name = handleReservedWord(getName(value, index));
1313
const counter = collisionCounter.get(name);
1414
if (counter === undefined) {
1515
collisionCounter.set(name, 1);
@@ -20,6 +20,54 @@ export function disambiguateNames<T>({
2020
});
2121
}
2222

23+
const RESERVED_WORDS = new Set([
24+
'await',
25+
'break',
26+
'case',
27+
'catch',
28+
'class',
29+
'const',
30+
'continue',
31+
'debugger',
32+
'delete',
33+
'do',
34+
'else',
35+
'enum',
36+
'export',
37+
'extends',
38+
'false',
39+
'finally',
40+
'function',
41+
'if',
42+
'implements',
43+
'import',
44+
'in',
45+
'interface',
46+
'let',
47+
'new',
48+
'package',
49+
'private',
50+
'protected',
51+
'public',
52+
'return',
53+
'super',
54+
'switch',
55+
'static',
56+
'this',
57+
'throw',
58+
'true',
59+
'try',
60+
'typeof',
61+
'var',
62+
'while',
63+
'with',
64+
'yield',
65+
]);
66+
67+
export function handleReservedWord(name: string): string {
68+
return RESERVED_WORDS.has(name) ? `${name}_` : name;
69+
}
70+
2371
export function isTupleType(t: string) {
2472
return t === 'tuple';
2573
}

packages/cli/src/scaffold/mapping.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ export const generateFieldAssignment = (
1313
value: string[],
1414
type: string,
1515
): { assignment: string; imports: string[] } => {
16-
let rightSide = `event.params.${value.join('.')}`;
16+
const safeKey = key.map(k => util.handleReservedWord(k));
17+
const safeValue = value.map(v => util.handleReservedWord(v));
18+
19+
let rightSide = `event.params.${safeValue.join('.')}`;
1720
const imports = [];
1821

1922
if (type in VALUE_TYPECAST_MAP) {
@@ -23,7 +26,7 @@ export const generateFieldAssignment = (
2326
}
2427

2528
return {
26-
assignment: `entity.${key.join('_')} = ${rightSide}`,
29+
assignment: `entity.${safeKey.join('_')} = ${rightSide}`,
2730
imports,
2831
};
2932
};

0 commit comments

Comments
 (0)