SIGN IN SIGN UP

gnd: Fix `add` and unify subgraph scaffolding generators (#6660)

* gnd: Unify subgraph scaffolding generators

Collapse the duplicated code generation so init and add share one path,
removing the forked add mapping generator that had drifted from the
scaffold one:

- a single sanitize_field_name in scaffold/naming.rs (three copies removed)
- a single generate_event_handlers driven by a new ResolvedEvent model
  (passthrough for now); add's copy is deleted
- shared SPEC_VERSION / MAPPING_API_VERSION constants and one to_kebab_case

No behavior change: init output is byte-identical and add is unchanged.

* gnd: Write schema entities and add guards in `add`

`gnd add` generated mappings and manifest entries that referenced entity
types it never declared, so codegen and build failed. Declare them, and
tighten two edges:

- append an entity type per new event to schema.graphql
- error when the data source name already exists
- only update networks.json when the file is present

* gnd: Resolve event-name collisions and merges in `add`

Decide each event's entity name once in a resolution pass, then feed the
schema, mapping and manifest generators from it:

- disambiguate events overloaded within one ABI (Transfer, Transfer1)
- on collision with an existing entity, rename with the contract prefix by
  default, or under --merge-entities reuse the entity without redeclaring
  it while still generating the handler, so the new contract's events are
  indexed instead of silently dropped

Wires up the previously-dead --merge-entities flag.

* gnd: Map small integer types to GraphQL Int

Solidity integers narrow enough to fit an i32 (signed up to 32 bits,
unsigned up to 24 bits) now map to GraphQL Int, matching the generated
AssemblyScript event params; wider integers stay BigInt. Previously every
int/uint became BigInt, which mismatched the bindings.

* gnd: Escape reserved-word event parameter names

A parameter named `new`, `class`, etc. produced an entity field the
generated AssemblyScript cannot declare. Suffix reserved words with `_`.
gnd's existing field-name conventions (camelCase, eventId/eventType) are
kept intentionally.

* gnd: Test overloaded-event disambiguation in `add`

End-to-end check that two events sharing a name in one ABI produce
distinct entities (Ping, Ping1) and handlers (handlePing, handlePing1)
through the add path.

* gnd: Disambiguate overloaded events in init scaffolding

Move overloaded-event name disambiguation into a shared disambiguate_events
helper used by both init's generators and add's resolve_events. init
previously emitted duplicate entity types and handlers for an ABI with two
same-named events; it now suffixes repeats (Ping, Ping1) the way add does.

* gnd: Match event.params accessor to the generated getter names

The mapping wrote `entity.<field> = event.params.<raw-name>`, but the ABI
codegen escapes reserved-word getters (`new` -> `new_`) and names unnamed
params `param<index>`. So a parameter named `new`, or an unnamed parameter,
produced a mapping referencing a getter that does not exist (or an empty
accessor that did not compile). Mirror the binding's getter naming on the
right-hand side via a shared event_param_accessors helper.

* gnd: Detect collisions against schema-declared entity types

resolve_events treated only the manifest's mapping.entities as existing, so
a type hand-written in schema.graphql but not listed in any mapping was not
seen as a collision: add appended a duplicate `type` and codegen failed on
the redeclaration. Union the @entity types parsed from schema.graphql into
the collision set, since the schema is the real source of truth for declared
types. Falls back to manifest-only if the schema is missing or unparseable.

* gnd: Use the shared reserved-word list for field names

sanitize_field_name shipped its own RESERVED_WORDS list, a subset missing
default/for/instanceof/null/void. A param named e.g. `void` was left
unescaped as the entity field, while the schema/ABI codegen escaped the
member to `void_` via the shared list, so the mapping referenced a member
that did not exist. Escape via crate::shared::handle_reserved_word so both
sides use one list.

* gnd: Detect collisions on the resolved entity name

resolve_events checked the raw event name, so a disambiguated overload alias
(e.g. Transfer1) that collides with an existing entity was neither renamed
nor merged and silently redeclared the type. Check entity_name (the name we
actually declare) instead.
K
Krishnanand V P committed
e1295f834b3b0c379a91950e4dae394ad9218916
Parent: 77d0e06
Committed by GitHub <noreply@github.com> on 7/15/2026, 9:36:30 AM