From 4311d0e177b37a7698d5befae9b6e9cafa6b37c9 Mon Sep 17 00:00:00 2001 From: Yaro Shkvorets Date: Wed, 29 Jan 2025 17:25:47 -0500 Subject: [PATCH] `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 --- .changeset/giant-eyes-play.md | 5 +++ packages/cli/src/codegen/schema.test.ts | 23 ++++++++++++ packages/cli/src/codegen/schema.ts | 14 +++++-- packages/cli/src/codegen/util.ts | 50 ++++++++++++++++++++++++- packages/cli/src/scaffold/mapping.ts | 7 +++- 5 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 .changeset/giant-eyes-play.md diff --git a/.changeset/giant-eyes-play.md b/.changeset/giant-eyes-play.md new file mode 100644 index 000000000..40e558213 --- /dev/null +++ b/.changeset/giant-eyes-play.md @@ -0,0 +1,5 @@ +--- +'@graphprotocol/graph-cli': minor +--- + +`graph codegen`: handle events with fields with reserved names #1896 diff --git a/packages/cli/src/codegen/schema.test.ts b/packages/cli/src/codegen/schema.test.ts index 6f549d01e..cbf3002c7 100644 --- a/packages/cli/src/codegen/schema.test.ts +++ b/packages/cli/src/codegen/schema.test.ts @@ -72,6 +72,9 @@ describe('Schema code generator', { concurrent: true }, () => { count: Int! isActive: Boolean + # reserved word + yield: Int! + # derivedFrom wallets: [Wallet!] @derivedFrom(field: "account") @@ -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: [], diff --git a/packages/cli/src/codegen/schema.ts b/packages/cli/src/codegen/schema.ts index 2788b29db..ef98482a5 100644 --- a/packages/cli/src/codegen/schema.ts +++ b/packages/cli/src/codegen/schema.ts @@ -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'); @@ -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')( @@ -339,7 +341,7 @@ export default class SchemaCodeGenerator { }`; return tsCodegen.method( - `get ${name}`, + `get ${safeName}`, [], returnType, ` @@ -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}'`, ); @@ -390,7 +394,7 @@ export default class SchemaCodeGenerator { const toValueString = idIsBytes ? '.toBytes().toHexString()' : '.toString()'; return tsCodegen.method( - `get ${name}`, + `get ${safeName}`, [], returnType, ` @@ -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); @@ -428,7 +433,7 @@ export default class SchemaCodeGenerator { }`; return tsCodegen.method( - `get ${name}`, + `get ${safeName}`, [], returnType, ` @@ -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', ); @@ -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, diff --git a/packages/cli/src/codegen/util.ts b/packages/cli/src/codegen/util.ts index c675ad241..29a72c301 100644 --- a/packages/cli/src/codegen/util.ts +++ b/packages/cli/src/codegen/util.ts @@ -9,7 +9,7 @@ export function disambiguateNames({ }) { 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); @@ -20,6 +20,54 @@ export function disambiguateNames({ }); } +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'; } diff --git a/packages/cli/src/scaffold/mapping.ts b/packages/cli/src/scaffold/mapping.ts index 818f967b2..a363f21ca 100644 --- a/packages/cli/src/scaffold/mapping.ts +++ b/packages/cli/src/scaffold/mapping.ts @@ -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) { @@ -23,7 +26,7 @@ export const generateFieldAssignment = ( } return { - assignment: `entity.${key.join('_')} = ${rightSide}`, + assignment: `entity.${safeKey.join('_')} = ${rightSide}`, imports, }; };