9 File format✎

How a graph is stored: the graph file, its nodes and wires, variables and modules, comments, node maps, project settings and versions.

Normative · Level 1Draft 0.1Pending review

Graphs are stored as JSON, one graph file per script. An implementation conforming at level 1 (§1.3) reads and writes these files as this chapter says. Field names are given exactly; a field marked optional MAY be left out, and one left out means what this chapter says it means.

9.1 The graph file

A graph file holds one script: the main graph and the graph of every function declared in it. It is named with the .nodescript extension, and its top level is an object:

FieldTypeHolds
schemaVersionnumberThe version of this format, 1 (§9.7).
kind"script"What the file is.
idstringThe graph's identity, which does not change when it is renamed.
namestringIts name. Where the file's own name says otherwise, the file's name wins.
targetstringThe profile it is written for (§1.2): "roblox" or "lune" in Roswaal.
scriptClassstringWhat kind of program it becomes, in the profile's terms.
runContextstring, optionalWhere it runs, where the profile distinguishes.
typecheckstringHow strictly the program is type-checked, in the profile's terms.
variablesarrayThe graph's variables (§9.3).
modulesarray, optionalThe modules the program uses (§9.3). Absent means none.
servicesarray of strings, optionalServices declared by name, where the profile has them (§9.3).
asWrittenboolean, optionalNames and types are written as the graph gives them, never renamed. Set on a graph imported from source; absent otherwise.
importedAsobject, optionalThe settings it was imported with, { "mode", "locals" }, offered again when it is imported over.
nodesarrayEvery node, in every graph of the file (§9.2).
linksarrayEvery wire (§9.2).
commentsarrayEvery comment (§9.4).

scriptClass, runContext, typecheck and services are the Luau profiles' fields, kept at the top level for Draft 0.1; §10.1 says how a profile names its own.

9.1-R1

A reader MUST keep fields it does not know when it writes a file back.

Roswaal keeps them in roswaal.json, and drops them from a graph file when it saves it.

Not yet in Roswaal

A node

FieldTypeHolds
idstringUnique in the file.
defstringWhich node it is: the id of a node definition in the profile or a pack.
x, ynumberIts top-left corner on the canvas, in canvas units.
literalsobject, optionalThe values typed into its unwired inputs, by pin id (below).
configobject, optionalIts settings, which the node definition interprets.
labelstring, optionalA title of its own, in place of the definition's.
graphstring, optionalThe id of the function declaration whose graph it is drawn in. Absent: the main graph.
innerobject, optionalFor a function declaration: where it is drawn inside its own graph, as x and y.

graph decides only where a node is drawn. What a function's body is, is decided by its wires (§7.5).

A value typed in

A literal is an object with a tag t, and a value v for every tag but nil:

tvIs
"nil"noneNo value.
"boolean"booleanTrue or false.
"number"numberA number.
"string"stringText.
"raw"stringSource code, written into the program as it is.

A link

A link is { "id", "from": { "node", "pin" }, "to": { "node", "pin" } }: from an output to an input, each named by its node's id and its pin's id. Its route is never stored; it is drawn from the two pins' positions (§5.2).

Ids are opaque strings. Roswaal makes them as random UUIDs; another implementation MAY use any scheme that keeps them unique within the file.

9.2-R1

An implementation MUST NOT read meaning into another's ids.

Roswaal meets

9.3 Variables, modules, services

A variable's fieldTypeHolds
idstringIts identity: nodes that read it refer to this.
namestringIts name in the program.
typestringIts pin type (§6.1).
defaultliteralIts value before anything sets it (§7.4).
descriptionstring, optionalWhat it is for.
constboolean, optionalWhether it can never be set.
A module's fieldTypeHolds
idstringIts identity.
namestringThe name the module is bound to in the program.
specifierstringWhat to load, written as the profile's way of loading a module takes it.
membersarray of strings, optionalNames taken off the module into names of their own.
descriptionstring, optionalWhat it is for.

Locals and functions are not listed: each is a node (§3.6, §3.7).

9.3-R1

The list of modules is the program's whole list: a compiler MUST NOT load a module the list does not name.

Roswaal meets

9.4 Comments

A comment is { "id", "x", "y", "w", "h", "text" }, with an optional color, six hexadecimal digits without the #, an optional graph, as on a node, and an optional style: lines (a -- line each), doc (a --- line each) or docBlock (a --[=[ ]=] block), how its header is written when not the default. What a comment holds is never stored: it is whatever lies inside it (§4.3).

9.5 Node maps

A node map, .nodemap, says where each compiled program goes in the place it runs from. Its top level is { "schemaVersion", "kind": "map", "id", "name", "output", "root" }, with an optional target. root is a tree of entries, each with an id, a name and children. A map, and what its entries may say, belongs to the profile: the Roblox profile's describes a place and becomes a Rojo project file (§11.7); the Lune profile's describes folders.

9.6 Project settings

A project is a folder with a roswaal.json at its root. Its fields say which profile the project uses (target), where graph files are (sourceDir), where programs are written (outDir), where node packs are (nodePaths), when to compile (compileMode, "manual" or "hot"), and how programs are laid out (format, indentStyle, indentWidth, comments). A missing field takes its default.

9.6-R1

A field of the project file a reader does not know MUST be kept.

Roswaal meets

9.7 Versions and migration

  • Every file carries schemaVersion. This draft describes version 1.
9.7-R1

A reader MUST refuse a file with a higher version than it knows, and say it was written by a newer implementation, rather than guess at it.

Roswaal meets
9.7-R2

A reader SHOULD bring an older file up to date as it reads it: fill in fields that did not exist, and rename nodes and pins that were renamed. It MUST say what it changed.

Roswaal meets
9.7-R3

A writer MUST write the version it implements.

Roswaal meets

A version that has changed shape

In Draft 0.1, version 1 has changed shape without changing number. Roswaal recognises an old file by what is in it, not by its version: a renamed node by its old id, an old field by its presence. Until 1.0, an implementation reading Roswaal's files has to do the same. From 1.0 a change of shape will change the number (§14.1).

9.8 Writing a file

9.8-R1

So that a graph saved twice is the same bytes, and a change to a graph is a small change to its file, a writer SHOULD write the canonical form: two-space indentation and a final newline; keys in the order this chapter lists them; nodes, links and comments sorted by id; the keys inside literals and config sorted; positions rounded to two decimal places; and optional fields left out when empty. Variables and modules keep the order the author gave them.

Roswaal meets
json
{
  "schemaVersion": 1,
  "kind": "script",
  "id": "demo-count-characters",
  "name": "count-characters",
  "scriptClass": "ModuleScript",
  "target": "lune",
  "typecheck": "strict",
  "variables": [],
  "modules": [{ "id": "m_fs", "name": "fs", "specifier": "@lune/fs" }],
  "nodes": [
    { "id": "n0", "def": "script.begin", "x": 0, "y": 0 },
    {
      "id": "n1",
      "def": "lune.value",
      "x": 4,
      "y": 105,
      "literals": { "a0": { "t": "string", "v": "README.md" } },
      "config": { "call": "readFile", "module": "fs" }
    }
  ],
  "links": [],
  "comments": []
}

The start of examples/lune-demo/.roswaal/scripts/count-characters.nodescript, shortened to its first two nodes and without its wires, with short objects drawn on one line.

To come: JSON Schemas

Draft 0.1 defines the format in these tables. A JSON Schema for each file, generated from Roswaal's types, is part of the plan for the first published draft (§14).

Not reviewed yet