Skip to content

Constrain GameMaker JSON at the deserialization boundary #797

Description

@Infiland

Follow-up to #612.

Problem

src/conversion/type_defs.py currently defines JsonDict as dict[str, Any], JsonList as list[Any], and JsonValue as Any. Those aliases flow through project manifests and resource converters, so strict Pyright cannot prove what values are read from .yyp and .yy files. Downstream code compensates with repeated casts after indexing unknown nested data.

This preserves forward compatibility, but it allows non-JSON and incorrectly shaped values to cross the parsing boundary without a typed contract.

Proposed scope

Validate raw deserialized values once, represent legal JSON recursively, and expose typed accessors/models for known GameMaker structures while retaining unknown fields needed for forward compatibility.

Acceptance criteria

  • Replace the unbounded JSON aliases with a recursive legal-JSON value model or an equivalently strict validated representation.
  • Add one shared deserialization/narrowing boundary that verifies object keys and recursively accepted value types before returning typed data.
  • Provide typed accessors for required/optional string, number, boolean, list, and object fields with consistent diagnostics and source-path context.
  • Use TypedDict, dataclasses, or existing resource models for known .yyp/.yy shapes instead of propagating raw dictionaries through conversion logic.
  • Retain unknown fields only in an explicitly typed raw/extra-field representation where forward compatibility requires them.
  • Remove redundant cast(JsonDict, ...) and cast(JsonList, ...) calls from migrated paths; do not replace them with broad Any, object, or ignore comments downstream.
  • Add malformed and deeply nested fixtures covering wrong field types, arrays/objects in unexpected positions, nulls, and forward-compatible unknown fields.
  • Preserve existing lenient JSON preprocessing and user-facing diagnostics unless a malformed value was previously accepted only because it bypassed validation.
  • Keep strict Pyright clean throughout the migration.

Verification

  • Run ./venv/bin/pyright --warnings and Ruff.
  • Run focused manifest/resource-model tests and the full unit suite because these aliases are shared broadly.
  • Run representative golden conversion and Godot validation tests to prove generated output remains stable.

Non-goals

  • Do not require schemas for every undocumented GameMaker extension field before accepting a project.
  • Do not force dynamic GML runtime values into the static JSON model.

Metadata

Metadata

Assignees

No one assigned

    Labels

    architectureInternal architecture and maintainabilityassetsGameMaker asset and project importtestingTests, fixtures, CI, validation, and coverage

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions