Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Project Config

The project manifest can be used as a simple schema root or as a full build description. It can be written as SCON, TOML, YAML, JSON, or Lua; SCON is recommended and used below.

project { id = "game_config" }
groups { common { default = true } }
views {
  default {
    contract = "game_config/default"
    groups = ["common"]
  }
}
includes = ["schema/items.scon"]

parsers { scripts = ["tools/parsers.lua"] }
type_mappings { scripts = ["tools/type_mappings.lua"] }

build {
  default_source_format = "xlsx"
  data_root = "data"
  view = "default"
  schema_lock = "generated/schema.lock"
  excel_templates = "generated/excel"
  codegen = [
    { target = "rust", out = "rust/src/generated", format = "auto" },
  ]
  exports = [
    { format = "binary", out = "generated/config.sora" },
  ]
}

Run every configured output:

sora build --project project.scon

data_root and excel_templates serve different purposes. data_root is the input directory used by export and build, so it contains edited table rows. excel_templates is an output directory for generated workbook templates, so it can be deleted and regenerated after schema changes. Do not point excel_templates at your edited data directory unless replacing those workbooks is intentional.

parsers.scripts lists custom Lua cell parser scripts used by CLI commands that read the project. Paths are relative to the project file. See Cell Parsers for the script API.

type_mappings.scripts lists Lua scripts that customize generated language types. Paths are relative to the project file. Type mappings are codegen-only: the schema still uses language-neutral Sora types such as struct<Vec3>, while the mapping script can map that named type to a target-specific type.

Localization is declared at the project root with localization. Its keyed sources are independent from normal tables; see Localization.

Run one configured codegen target:

sora build --project project.scon --target rust

Target Options

Language-specific options live under [codegen.<target>]:

[codegen.rust]
runtime_format = "sora"

[codegen.typescript]
runtime_format = "json"
enum_repr = "string"

[codegen.lua]
runtime_format = "cbor"
lua_version = "5.4"

These options are consumed by the selected generator. The normalized IR stays language-neutral.

Type mapping scripts return a table with type_mappings. Each mapping targets one language and one named schema type:

return {
  type_mappings = {
    {
      target = "csharp",
      schema_type = "Vec3",
      type_name = "Vector3",
      nullable_type_name = "Vector3?",
      decode = "GameMappings.ToVector3({value})",
      value_decode = "GameMappings.ToVector3({value})",
      imports = { "UnityEngine" },
    },
  },
}

nullable_type_name is optional. Use it when optional<schema_type> needs a different target-language type expression from the backend’s default nullable wrapper.

decode wraps the normal binary runtime decode expression, and value_decode wraps JSON/CBOR/protobuf-style value decode. The {value} placeholder is replaced with the generated default expression.

The C target uses write-into decode functions, so C mappings should use decode_into instead of decode. The {target} placeholder is replaced with the output pointer expression. C mappings can also provide free, where {target} is replaced with the pointer that should be released:

{
  target = "c",
  schema_type = "Vec3",
  type_name = "game_vector3",
  decode_into = "game_vector3_decode(reader, {target})",
  free = "game_vector3_free({target});",
  imports = { "#include \"vector3.h\"" },
}

imports is target-specific and is only emitted by language generators that need it. C#, Java, Kotlin, and Scala expect an import namespace/path without the leading keyword. Go expects an import spec such as "example.com/game/vector". Python, TypeScript, JavaScript, Dart, Godot, C, C++, and Rust expect a complete import/include/use/preload line.

runtime_format can be sora, json, cbor, or sora-protobuf, but not every target supports every runtime format. See Runtime Formats for the support matrix.

Built-In Target Options

TargetOptions
rustruntime_format default sora; map_type = "std" or "fx_hash_map" default std; string_storage = "owned" or "arc" default owned; optional crate emits a standalone library crate.
kotlinruntime_format default sora.
csharpruntime_format default sora.
javaruntime_format default sora; nullable_annotation defaults to SoraNullable, set an annotation class such as org.jetbrains.annotations.Nullable, or set "" to disable annotations.
scalaruntime_format default sora; scala_version = "2.12", "2.13", or "3" default 3.
goruntime_format default sora.
dartruntime_format = "json", "cbor", or "sora-protobuf". Set this explicitly; sora is not supported for Dart.
godotruntime_format = "json". Set this explicitly; it is the only supported Godot runtime format.
cruntime_format = "sora"; c_standard = "c99", "c11", "c17", or "c23" default c11; prefix optional symbol prefix.
cppruntime_format = "sora"; cpp_standard = "c++11", "c++14", "c++17", "c++20", or "c++23" default c++17; namespace optional C++ namespace.
typescriptruntime_format default sora; enum_repr = "string" or "integer" default string.
javascriptruntime_format default sora; enum_repr = "string" or "integer" default string; emit_dts boolean default true.
erlangruntime_format default sora; enum_repr = "atom" or "integer" default atom.
luaruntime_format default sora; module optional require/import prefix; lua_version = "5.1", "5.2", "5.3", "5.4", or "luajit" default 5.4; enum_repr = "string" or "integer" default string.
pythonruntime_format default sora.
proto-schemaNo target options. Generates .proto schema files instead of a runtime loader.

Example with several language-specific options:

[codegen.rust]
runtime_format = "sora"
map_type = "fx_hash_map"
string_storage = "arc"

[codegen.cpp]
runtime_format = "sora"
cpp_standard = "c++20"
namespace = "game::config"

[codegen.javascript]
runtime_format = "json"
enum_repr = "integer"
emit_dts = true

Standalone Rust Crate

Rust normally writes a module tree directly into the configured out directory. Set codegen.rust.crate to make out the root of a complete library crate instead:

build {
  codegen = [{ target = "rust", out = "generated/game-config" }]
}

codegen {
  rust {
    runtime_format = "sora"
    crate {
      name = "game-config"
      version = "0.1.0"
      edition = "2024"
      publish = false
    }
  }
}

Sora then writes Cargo.toml, src/lib.rs, the generated models, and the runtime under generated/game-config. name is required. version, edition, and publish default to 0.1.0, 2024, and false. The manifest includes the dependencies required by the selected runtime format and Rust options. Applications can consume it with a normal path dependency:

[dependencies]
game-config = { path = "../generated/game-config" }

Without crate, the existing module layout remains unchanged and out should point to the module directory inside the consuming crate.