Skip to content

Commit

Permalink
graph codegen: handle reserved words (#1929)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
YaroShkvorets authored Jan 29, 2025
1 parent 4914d79 commit 4311d0e
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/giant-eyes-play.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphprotocol/graph-cli': minor
---

`graph codegen`: handle events with fields with reserved names #1896
23 changes: 23 additions & 0 deletions packages/cli/src/codegen/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ describe('Schema code generator', { concurrent: true }, () => {
count: Int!
isActive: Boolean
# reserved word
yield: Int!
# derivedFrom
wallets: [Wallet!] @derivedFrom(field: "account")
Expand Down Expand Up @@ -248,6 +251,26 @@ describe('Schema code generator', { concurrent: true }, () => {
this.set('count', Value.fromI32(value))
`,
},
{
name: 'get yield_',
params: [],
returnType: new NamedType('i32'),
body: `let value = this.get('yield')
if (!value || value.kind == ValueKind.NULL) {
return 0
} else {
return value.toI32()
}
`,
},
{
name: 'set yield_',
params: [new Param('value', new NamedType('i32'))],
returnType: undefined,
body: `
this.set('yield', Value.fromI32(value))
`,
},
{
name: 'get isActive',
params: [],
Expand Down
14 changes: 10 additions & 4 deletions packages/cli/src/codegen/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import debug from '../debug.js';
import Schema from '../schema.js';
import * as typesCodegen from './types/index.js';
import * as tsCodegen from './typescript.js';
import * as util from './util.js';

class IdField {
static BYTES = Symbol('Bytes');
Expand Down Expand Up @@ -308,6 +309,7 @@ export default class SchemaCodeGenerator {
_generateEntityFieldGetter(_entityDef: ObjectTypeDefinitionNode, fieldDef: FieldDefinitionNode) {
const isDerivedField = this._isDerivedField(fieldDef);
const name = fieldDef.name.value;
const safeName = util.handleReservedWord(name);

if (isDerivedField) {
schemaCodeGeneratorDebug.extend('_generateEntityFieldGetter')(
Expand Down Expand Up @@ -339,7 +341,7 @@ export default class SchemaCodeGenerator {
}`;

return tsCodegen.method(
`get ${name}`,
`get ${safeName}`,
[],
returnType,
`
Expand All @@ -351,6 +353,8 @@ export default class SchemaCodeGenerator {
_generateDerivedFieldGetter(entityDef: ObjectTypeDefinitionNode, fieldDef: FieldDefinitionNode) {
const entityName = entityDef.name.value;
const name = fieldDef.name.value;
const safeName = util.handleReservedWord(name);

schemaCodeGeneratorDebug.extend('_generateDerivedFieldGetter')(
`Generating derived field '${name}' getter for Entity '${entityName}'`,
);
Expand Down Expand Up @@ -390,7 +394,7 @@ export default class SchemaCodeGenerator {
const toValueString = idIsBytes ? '.toBytes().toHexString()' : '.toString()';

return tsCodegen.method(
`get ${name}`,
`get ${safeName}`,
[],
returnType,
`
Expand All @@ -415,6 +419,7 @@ export default class SchemaCodeGenerator {
fieldDef: FieldDefinitionNode,
) {
const name = fieldDef.name.value;
const safeName = util.handleReservedWord(name);
const gqlType = fieldDef.type;
const fieldValueType = this._valueTypeFromGraphQl(gqlType);
const returnType = this._typeFromGraphQl(gqlType);
Expand All @@ -428,7 +433,7 @@ export default class SchemaCodeGenerator {
}`;

return tsCodegen.method(
`get ${name}`,
`get ${safeName}`,
[],
returnType,
`
Expand All @@ -439,6 +444,7 @@ export default class SchemaCodeGenerator {
}
_generateEntityFieldSetter(_entityDef: ObjectTypeDefinitionNode, fieldDef: FieldDefinitionNode) {
const name = fieldDef.name.value;
const safeName = util.handleReservedWord(name);
const isDerivedField = !!fieldDef.directives?.find(
directive => directive.name.value === 'derivedFrom',
);
Expand Down Expand Up @@ -477,7 +483,7 @@ Suggestion: add an '!' to the member type of the List, change from '[${baseType}
`;

return tsCodegen.method(
`set ${name}`,
`set ${safeName}`,
[tsCodegen.param('value', paramType)],
undefined,
isNullable ? setNullable : setNonNullable,
Expand Down
50 changes: 49 additions & 1 deletion packages/cli/src/codegen/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function disambiguateNames<T>({
}) {
const collisionCounter = new Map();
return values.map((value, index) => {
const name = getName(value, index);
const name = handleReservedWord(getName(value, index));
const counter = collisionCounter.get(name);
if (counter === undefined) {
collisionCounter.set(name, 1);
Expand All @@ -20,6 +20,54 @@ export function disambiguateNames<T>({
});
}

const RESERVED_WORDS = new Set([
'await',
'break',
'case',
'catch',
'class',
'const',
'continue',
'debugger',
'delete',
'do',
'else',
'enum',
'export',
'extends',
'false',
'finally',
'function',
'if',
'implements',
'import',
'in',
'interface',
'let',
'new',
'package',
'private',
'protected',
'public',
'return',
'super',
'switch',
'static',
'this',
'throw',
'true',
'try',
'typeof',
'var',
'while',
'with',
'yield',
]);

export function handleReservedWord(name: string): string {
return RESERVED_WORDS.has(name) ? `${name}_` : name;
}

export function isTupleType(t: string) {
return t === 'tuple';
}
Expand Down
7 changes: 5 additions & 2 deletions packages/cli/src/scaffold/mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ export const generateFieldAssignment = (
value: string[],
type: string,
): { assignment: string; imports: string[] } => {
let rightSide = `event.params.${value.join('.')}`;
const safeKey = key.map(k => util.handleReservedWord(k));
const safeValue = value.map(v => util.handleReservedWord(v));

let rightSide = `event.params.${safeValue.join('.')}`;
const imports = [];

if (type in VALUE_TYPECAST_MAP) {
Expand All @@ -23,7 +26,7 @@ export const generateFieldAssignment = (
}

return {
assignment: `entity.${key.join('_')} = ${rightSide}`,
assignment: `entity.${safeKey.join('_')} = ${rightSide}`,
imports,
};
};
Expand Down

0 comments on commit 4311d0e

Please sign in to comment.