Skip to content

naming_conventions

Francisco Dias edited this page Aug 18, 2026 · 3 revisions

Naming Conventions

The prefix system

GML has no namespaces. The config's prefix (default: gm) generates four derived tokens that are prepended to every generated name to prevent collisions:

Token Example (gm) Used for
{prefix}_ gm_ Public functions (endpoint wrappers, cookie API, auth API)
_{prefix}_ _gm_ Private helpers (singleton getter, create_request, cookie_capture)
{Prefix} Gm Struct constructor names
{PREFIX}_ GM_ Macros and constants (reserved for future use)

With "prefix": "petstore":

  • Public: petstore_get_pet()
  • Private: _petstore_get_singleton()
  • Struct: PetstoreUser

Endpoint function names

There are two sources of endpoint names, and which one applies depends on whether the operation declares an operationId.

From operationId — the normal case

The name is the operationId, snake_cased, with the prefix in front. The tag is not involved.

operationId: "getUserById"    → gm_get_user_by_id
operationId: "createOrder"    → gm_create_order
operationId: "healthCheck"    → gm_health_check

So the full public name is {prefix}_{snake(operationId)}.

Derived from the path — the fallback

Only used for an operation with no operationId, which is an error unless "requireOperationId": false. Here the tag is used: the first entry of operation.tags becomes a group prefix (or default when there are none), followed by the verb and the literal path segments, with _by_id appended when the path ends in a parameter.

GET /users/{id}    tag: "Users"    → gm_users_get_by_id
GET /health        (no tag)        → gm_default_get_health

These names change whenever the URL is refactored, which is exactly why operationId is required by default — see CLI Reference.

Name assignment order

Author-chosen names are claimed before derived ones, so a path-derived name can never take a name that an operationId asked for, regardless of where the operations appear in the document.

Duplicate name resolution

If two operations still map to the same generated name, numeric suffixes are appended — gm_get_item, gm_get_item_2and the collision is reported as IR_SYM_001, an error by default. The suffix is positional, so reordering the spec would move it to a different operation; it exists to keep the emitted file compilable, not as a solution. Fix the operationIds.

snake_case conversion rules

The ToSnake() helper:

  1. Protects known acronyms/exceptions from being split (OAuth2, OAuth, iOS, eBay, GitHub, iPhone) — these are lowercased as a single token.
  2. Inserts _ at camelCase boundaries (userIduser_id).
  3. Inserts _ at acronym boundaries (XMLParserxml_parser).
  4. Replaces non-alphanumeric characters with _.
  5. Collapses consecutive _, trims leading/trailing _, lowercases.

Parameter names

All parameters are prefixed with _ and converted to snake_case:

"userId"      → _user_id
"max-count"   → _max_count
"OAuth2Token" → _oauth2_token

_body, _content_type and _callback are reserved for the generator. A spec parameter that snake_cases onto one of them is suffixed (_body_2), as is a second parameter that collides with an earlier one after conversion (userId and user_id in the same operation).

Struct member names

A struct member keeps the name the spec used. Only the constructor argument is snake_cased:

function GmUser(_user_id, _display_name) constructor
{
    userId = _user_id;          // member keeps the spec's casing
    displayName = _display_name;
}

A member whose name is not a legal bare GML identifier is written through the struct accessor instead. That covers three cases:

self[$ "x-rate-limit"] = _x_rate_limit;   // illegal characters
self[$ "delete"] = _delete;               // GML reserved word
self[$ "health"] = _health;               // GML global built-in variable

GML reserved words and built-ins

The full list is NameUtils.Reserved. It covers GML's keywords (if, var, end, constructor, delete, self, argument0, …) and its global built-in variables.

The global built-ins matter more than they look. A constructor assigns to self, so a member named after one resolves to the global instead:

  • read-only globals (fps, current_time, delta_time, …) are a compile error in the consuming project;
  • writable globals (health, lives, score, room, …) silently write the global, and the struct member is never created.

Instance built-ins are safe and are deliberately not reserved — inside a constructor self is the struct, so id, x, y, depth, speed, visible, sprite_index, alarm, layer and the rest become ordinary members. id in particular appears in a large share of real schemas, and escaping it would make the output much harder to read for no benefit.

Struct names

schema name: "UserProfile"   prefix: gm
→ struct constructor: GmUserProfile
→ validate function:  GmUserProfile_validate

Inline (anonymous) schemas

A schema declared inline rather than under #/components/schemas is named from its owner — the operation and the role it plays — PascalCased:

operation "uploadAvatar", request body   → GmUploadAvatarBody

Component names are reserved before any of this happens, so an inline schema can never take the name of a declared component; if the generated name is already spoken for, a counter is appended (GmUploadAvatarBody2).

Generated private names

Internal variables inside generated functions use double-underscore-wrapped identifiers, so a spec parameter (which is always single-underscore) can never shadow one:

var __base_url__       // server URL for this call
var __url__            // final request URL
var __content_type__   // content-type for this call
var __security__       // auth scheme array for this request
var __where__          // caller location, used in error messages

Extension options

The generated helpers read two GameMaker Extension options from the extension named after the struct prefix:

extension_get_option_value("Gm", "server_rest_url")   // base URL
extension_get_option_value("Gm", "debug_logging")     // bool

Create an extension with the matching name and these option keys, or replace the helper functions with a custom implementation.

If server_rest_url is empty, endpoints build a relative URL and http_request rejects it, returning -1 with no other diagnostic. Check this option first when every call fails immediately.