Command line
blinkblox [CONFIG] [OPTIONS]CONFIG is the schema to compile. The compiler reads it, follows its imports, and writes the
server and client modules to the paths the schema names in
ServerOutput and ClientOutput.
Both options are required.
Compiling
Section titled “Compiling”blinkblox netThe schema’s path is looked up in this order, and the first file that exists is used:
- the path exactly as given –
net - with
.txtappended –net.txt - with
.blinkappended –net.blink
So blinkblox net and blinkblox net.blink compile the same file. A path into another
directory works the same way: blinkblox schemas/net.
Output paths are relative to the schema, not to where you run the command. option ServerOutput = "src/server/Net.luau" in schemas/net.blink writes schemas/src/server/Net.luau. Absolute paths
are used as they are. Whatever extension the path has, the module is written as .luau:
"out/Server.lua" and "out/Server" both write out/Server.luau.
What gets written:
- the server module and the client module, always;
- a shared types module, when
TypesOutputis set; - a
.d.tsdeclaration next to each module, whenTypescriptis set. A module namedinitgetsindex.d.ts.
On success it prints its progress and stops:
BlinkBlox 0.33.0Reading source from net.blink...Parsing source into AST...Generating output files...Network files generated!A missing output directory
Section titled “A missing output directory”If an output path points into a directory that does not exist, the compiler asks whether to create it. Answering no stops the compile. Two cases skip the question and create the directory:
--yesis passed.- No terminal is attached – the compiler runs from a script, a git hook, a build task or CI. There is nobody to answer, and naming the path in the schema is taken as the answer.
A build therefore never hangs waiting on a prompt nobody can see, with or without --yes.
Flags may come before or after the schema, in any order. The schema is the first argument that is
not a flag – blinkblox --yes net and blinkblox net --yes are the same command.
| Flag | What it does |
|---|---|
-h, --help |
Prints the usage and the list of flags. Running blinkblox with no schema does the same. |
-v, --version |
Prints BlinkBlox and the version, then exits without compiling. |
-w, --watch |
Compiles, then keeps watching the schema and everything it imports, recompiling on every change. See watch mode. |
-q, --quiet |
Prints nothing on success: no banner, no progress. Errors and warnings are still printed, --version still prints the version, and watch mode still says what it is watching. |
-c, --compact |
Prints each diagnostic as a single line instead of the full rendering. See diagnostics. |
-y, --yes |
Accepts every prompt. The only prompt is creating a missing output directory. |
--check |
Parses and generates everything, and writes nothing – no modules, no output directories. Reports the same diagnostics and exits with the same code as a real compile. See checking without writing. |
--json |
Prints the result as one JSON document on standard output instead of rendering diagnostics, and prints nothing else. See JSON output. |
-p, --profile |
Compiles under a profile: dev, debug, test or release. Takes a value: --profile dev. Without it the build is release. |
Flags are matched whole, so short flags do not combine: write -q -y, not -qy. An argument the
compiler does not recognise as a flag is taken for the schema’s path, so a mistyped flag in front of
the schema shows up as a missing file named after it.
--profile is the only flag that takes a value, and its value is never mistaken for the schema:
blinkblox --profile dev net compiles net under dev. A missing or misspelt profile stops the
compiler before it reads anything:
Expected a profile after "--profile": dev, debug, test or releaseDiagnostics
Section titled “Diagnostics”When a schema is wrong the compiler prints a diagnostic, writes nothing, and exits. Each diagnostic has a code, a message, the offending line with the span underlined, and often a note on how to fix it. For this schema:
option ServerOutput = "src/server/Net.luau"option ClientOutput = "src/shared/Net.luau"option RequireRates = true
event Chat { From: Client, Type: Reliable, Call: SingleSync, Data: string(1..200)}the compiler prints:
BlinkBlox 0.33.0Reading source from net.blink...Parsing source into AST...[E3020] Error: Inbound "Chat" has no rate limit ╭─[net.blink:1:11] │005 │ event Chat { ┆ ──┬── ┆ │ ┆ ╰── Add a Rate, in events per second │ = note: option RequireRates is set, so every inbound event and function must declare one. │────╯The file is named by the path it was compiled from, normalised: blinkblox schemas/net reports
schemas/net.blink, and an error inside an import names the imported file’s own path, not the string
the import wrote. The bracket after the file name is the range of lines in the file – line 1 to line 11 here – not
the position of the error. The line number on the left of the source is the one to look at.
With --compact, the same diagnostic is one line, in the form
[code] [Lfirst:Llast] [file] Error: message:
[E3020] [L005:L005] [net.blink] Error: Inbound "Chat" has no rate limitIt carries no column, labels or notes. A program that needs those should use
--json instead.
Warnings (codes starting with W) use the same layout in yellow. They do not stop the compile:
the modules are written, and the warning is printed alongside. Diagnostics go to standard error;
the banner and progress lines go to standard output.
Every code, and what to do about it, is listed in the diagnostics reference.
Exit codes
Section titled “Exit codes”| Code | When |
|---|---|
0 |
The modules were written (or, with --check, would have been), or --help or --version was asked for. Warnings do not change it. |
1 |
Anything else: a diagnostic error in the schema, an unknown --profile, a schema file that does not exist, a schema without ServerOutput or ClientOutput, a refused directory prompt, or --json combined with --watch. |
Only diagnostics are rendered as above. A missing schema file or a refused prompt is reported as a
plain error message followed by a stack trace. Under --json every one of these is
reported in the document instead.
Checking without writing
Section titled “Checking without writing”blinkblox net --check--check runs the whole compile – the parse, every analysis, and the generator – and stops short
of the disk: no module is written and no output directory is created, so it never prompts. The
diagnostics and the exit code are the ones a real compile would give, and on success it ends with
Schema checked, nothing written. instead of Network files generated!.
Use it wherever the modules on disk should not change: a pre-commit hook, a CI step that only has to
say whether the schema is valid, or an editor task run on save. It combines with --watch, which
then reports each change without writing anything.
JSON output
Section titled “JSON output”blinkblox net --check --json--json prints one JSON document on standard output and nothing else: no banner, no progress, and
no rendered diagnostics on standard error. It is meant for programs – an editor task, a CI step, a
coding assistant – that need to know exactly where a diagnostic is without parsing the rendered
form. The exit code is unchanged: 1 when success is false, 0 otherwise.
For the schema in Diagnostics above, it prints (formatted here; the real output is one line):
{ "version": 1, "success": false, "diagnostics": [ { "severity": "error", "code": "E3020", "name": "AnalyzeMissingRateLimit", "message": "Inbound \"Chat\" has no rate limit", "file": "net.blink", "range": { "start": { "line": 5, "column": 7, "offset": 122 }, "end": { "line": 5, "column": 11, "offset": 126 } }, "labels": [ { "primary": true, "message": "Add a Rate, in events per second", "range": { "start": { "line": 5, "column": 7, "offset": 122 }, "end": { "line": 5, "column": 11, "offset": 126 } } } ], "notes": [ "option RequireRates is set, so every inbound event and function must declare one." ] } ], "outputs": []}| Field | Meaning |
|---|---|
version |
The format’s version, 1. It changes when a field is removed or changes meaning; a new field does not change it. |
success |
false if the compile failed, for any reason. Warnings do not make it false. |
diagnostics |
Every error and warning, in the order they were raised. A compile stops at its first error, so there is at most one error, after any warnings. |
outputs |
The paths written, normalised. Empty under --check, and empty when the compile failed. |
Each diagnostic has:
| Field | Meaning |
|---|---|
severity |
"error" or "warning". |
code |
The code as the rendered form prints it – "E3020", "W3019" – listed in the diagnostics reference. null for a failure that is not a diagnostic. |
name |
The code’s name in the compiler, such as "AnalyzeMissingRateLimit". null when code is. |
message |
The headline, without colour codes. |
file |
The file it is in, named as in the rendered form. |
range |
Where the primary label points, or null when there is none. |
labels |
Every underlined span: the primary one and any secondary ones, each with its message and range. |
notes |
The = note: lines, which say what to do about it. |
A range’s start is inclusive and its end exclusive. line and column count from 1, as the
rendered form’s line numbers do, and offset is the byte offset into the file, counting from 0. A
column counts bytes, so a tab is one column.
A failure that is not a diagnostic – a schema file that does not exist, a schema without
ServerOutput – is reported the same way, with code, name and range set to null and the
error in message. Standard output is a JSON document on every run, including the ones that fail
before the schema is read.
--json cannot be combined with --watch: watch mode never finishes, so its document would never
be complete. The compiler refuses the pair and exits with 1.
Watch mode
Section titled “Watch mode”blinkblox net --watchWatch mode compiles the schema once, then keeps running and recompiles whenever the schema or any file it imports changes – imports of imports included. It prints what it is watching when it starts, and again whenever an edit changes how many imports there are:
BlinkBlox 0.33.0BlinkBlox is watching for changes: Entry: net.blink Imports: 2While it runs:
- It checks for changes once a second, by comparing each file’s modification time. Saving a file with no change still counts as a change.
- A successful compile prints nothing. Silence means the modules on disk are current.
- A failed compile prints its diagnostic and keeps watching. Fix the schema and save; the next compile replaces the error with silence. The modules from the last good compile stay on disk until then.
- Missing output directories are created without asking, as if
--yeswere passed. --profileapplies to every recompile.--compactdoes not; watch mode always renders diagnostics in full.- It runs until you stop it with Ctrl+C.
Watch mode finds imports by reading import "..." lines as text. An import that is commented out,
or marked with a profile the build leaves out, is still watched.
That costs nothing, but a missing file named there has the effect described above.
