Skip to content

Instantly share code, notes, and snippets.

@nommiin
Last active February 4, 2026 06:19
Show Gist options
  • Select an option

  • Save nommiin/292bb3d26e1a4629bea98c6a6632d158 to your computer and use it in GitHub Desktop.

Select an option

Save nommiin/292bb3d26e1a4629bea98c6a6632d158 to your computer and use it in GitHub Desktop.
spec.ts - Convert GmlSpec.xml into JSON using bun.sh
/*
title: spec.ts
author: nommiin
description: uses HTMLRewriter to convert GmlSpec.xml file to output.json
note: reads GmlSpec.xml from runtime-2024.1400.3.948, ensure this is installed
*/
class GmlElement {
public Name: string = "";
toJSON(): Record<string, unknown> {
const { Name, ...ext } = this;
return ext;
}
}
class GmlParameter extends GmlElement {
public Type: string;
public Optional: boolean;
public Description: string = "";
constructor(_element: HTMLRewriterTypes.Element) {
super();
this.Name = (_element.getAttribute("Name") as string);
this.Type = (_element.getAttribute("Type") as string);
this.Optional = (_element.getAttribute("Optional") ?? "false") == "true";
}
override toJSON(): Record<string, unknown> {
return (this as Record<string, unknown>);
}
}
class GmlFunction extends GmlElement {
public Deprecated: boolean;
public ReturnType: string;
public Pure: boolean;
public Description: string = "";
public Parameters: GmlParameter[] = [];
constructor(_element: HTMLRewriterTypes.Element) {
super();
this.Name = (_element.getAttribute("Name") as string);
this.Deprecated = (_element.getAttribute("Deprecated") ?? "false") == "true";
this.ReturnType = _element.getAttribute("ReturnType") as string;
this.Pure = (_element.getAttribute("Pure") ?? "false") === "true";
}
}
class GmlVariable extends GmlElement {
public Type: string;
public Deprecated: boolean;
public Get: boolean;
public Set: boolean;
public Instance: boolean;
public Locale: string | undefined;
public Description: string = "";
constructor(_element: HTMLRewriterTypes.Element) {
super();
this.Name = (_element.getAttribute("Name") as string);
this.Type = (_element.getAttribute("Type") as string);
this.Deprecated = (_element.getAttribute("Deprecated") ?? "false") == "true";
this.Get = (_element.getAttribute("Get") ?? "false") == "true";
this.Set = (_element.getAttribute("Set") ?? "false") == "true";
this.Instance = (_element.getAttribute("Instance") ?? "false") == "true";
this.Locale = _element.getAttribute("Locale") ?? undefined;
}
}
class GmlConstant extends GmlElement {
public Type: string;
public Deprecated: boolean;
public Description: string = "";
constructor(_element: HTMLRewriterTypes.Element) {
super();
this.Name = (_element.getAttribute("Name") as string);
this.Type = (_element.getAttribute("Type") as string);
this.Deprecated = (_element.getAttribute("Deprecated") ?? "false") == "true";
}
}
class GmlStructure extends GmlElement {
public Fields: GmlField[] = [];
constructor(_element: HTMLRewriterTypes.Element) {
super();
this.Name = (_element.getAttribute("Name") as string);
}
}
class GmlField extends GmlVariable {
override toJSON(): Record<string, unknown> {
return (this as Record<string, unknown>);
}
}
class GmlSpec {
public Functions: Record<string, GmlFunction>;
public Variables: Record<string, GmlVariable>;
public Constants: Record<string, GmlConstant>;
public Structures: Record<string, GmlStructure>;
constructor(_content: string) {
this.Functions = this.parse_functions(_content);
this.Variables = this.parse_variables(_content);
this.Constants = this.parse_constants(_content);
this.Structures = this.parse_structures(_content);
}
private parse_functions(_content: string): Record<string, GmlFunction> {
let output: Record<string, GmlFunction> = {}, recent: GmlFunction | undefined = undefined;
new HTMLRewriter().on("Function", {
element(element) {
recent = new GmlFunction(element);
output[recent.Name] = recent;
},
}).on("Description", {
text(text) {
const inner = text.text.trim();
if (recent == undefined || inner.length == 0) return;
recent.Description = inner;
},
}).on("Parameter", {
element(element) {
if (recent == undefined) return;
recent.Parameters.push(new GmlParameter(element));
},
text(text) {
const inner = text.text.trim();
if (recent == undefined || inner.length == 0) return;
const param = recent.Parameters.at(-1);
if (param == undefined) return;
param.Description = inner;
}
}).transform(_content);
return output;
}
private parse_variables(_content: string): Record<string, GmlVariable> {
let output: Record<string, GmlVariable> = {}, recent: GmlVariable | undefined = undefined;
new HTMLRewriter().on("Variable", {
element(element) {
recent = new GmlVariable(element);
output[recent.Name] = recent;
},
text(text) {
const inner = text.text.trim();
if (recent == undefined || inner.length == 0) return;
recent.Description = inner;
}
}).transform(_content);
return output;
}
private parse_constants(_content: string): Record<string, GmlConstant> {
let output: Record<string, GmlConstant> = {}, recent: GmlConstant | undefined = undefined;
new HTMLRewriter().on("Constant", {
element(element) {
recent = new GmlConstant(element);
output[recent.Name] = recent;
},
text(text) {
const inner = text.text.trim();
if (recent == undefined || inner.length == 0) return;
recent.Description = inner;
}
}).transform(_content);
return output;
}
private parse_structures(_content: string): Record<string, GmlStructure> {
let output: Record<string, GmlStructure> = {}, recent: GmlStructure | undefined = undefined;
new HTMLRewriter().on("Structure", {
element(element) {
recent = new GmlStructure(element);
output[recent.Name] = recent;
}
}).on("Field", {
element(element) {
if (recent == undefined) return;
recent.Fields.push(new GmlField(element));
},
text(text) {
const inner = text.text.trim();
if (recent == undefined || inner.length == 0) return;
const field = recent.Fields.at(-1);
if (field == undefined) return;
field.Description = inner;
},
}).transform(_content);
return output;
}
}
const path: string = "C:\\ProgramData\\GameMakerStudio2-Beta\\Cache\\runtimes\\runtime-2024.1400.3.948\\GmlSpec.xml";
const spec = new GmlSpec(await Bun.file(path).text());
await Bun.write("output.json", JSON.stringify(spec, undefined, 4));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment