///|
fn manifest_json(manifest : ProjectManifest) -> Json {
let root : Map[String, Json] = Map([
("schemaVersion", manifest.schema_version.to_json()),
("id", manifest.id.to_json()),
("title", manifest.title.to_json()),
("module", manifest.module_name.to_json()),
("mouiVersion", manifest.moui_version.to_json()),
("platforms", manifest.platforms.to_json()),
])
match manifest.bundle_id {
Some(value) => root["bundleId"] = value.to_json()
None => ()
}
Json::object(root)
}
///|
fn ProjectManifest::to_json_text(self : ProjectManifest) -> String {
manifest_json(self).stringify(indent=2) + "\n"
}
///|
fn required_json_string(
fields : Map[String, Json],
key : String,
) -> Result[String, String] {
match fields.get(key) {
Some(String(value)) if value != "" => Ok(value)
_ => Err("moui.project.json is missing string field: " + key)
}
}
///|
fn parse_project_manifest(text : String) -> Result[ProjectManifest, String] {
let parsed = @json.parse(text) catch {
_ => return Err("moui.project.json is invalid JSON")
}
guard parsed is Object(fields) else {
return Err("moui.project.json root must be an object")
}
guard fields.get("schemaVersion") is Some(Number(1.0, repr=_)) else {
return Err("moui.project.json schemaVersion must be 1")
}
let id = match required_json_string(fields, "id") {
Ok(value) => value
Err(message) => return Err(message)
}
let title = match required_json_string(fields, "title") {
Ok(value) => value
Err(message) => return Err(message)
}
let module_name = match required_json_string(fields, "module") {
Ok(value) => value
Err(message) => return Err(message)
}
let moui_version = match required_json_string(fields, "mouiVersion") {
Ok(value) => value
Err(message) => return Err(message)
}
let platforms = match fields.get("platforms") {
Some(Array(values)) => {
let result : Array[String] = []
for value in values {
match value {
String(name) => result.push(name)
_ => return Err("moui.project.json platforms must contain strings")
}
}
result
}
_ => return Err("moui.project.json is missing array field: platforms")
}
let bundle_id = match fields.get("bundleId") {
Some(String(value)) => Some(value)
Some(_) => return Err("moui.project.json bundleId must be a string")
None => None
}
let manifest : ProjectManifest = {
schema_version: 1,
id,
title,
module_name,
moui_version,
platforms,
bundle_id,
}
let options : ProjectOptions = {
target: ".",
id: manifest.id,
module_name: manifest.module_name,
title: manifest.title,
moui_version: manifest.moui_version,
moui_skia_renderer_version: default_moui_skia_renderer_dependency_version,
template: "counter",
platforms: manifest.platforms,
bundle_id: manifest.bundle_id,
}
match validate_project_options(options) {
Ok(_) => ()
Err(message) => return Err("moui.project.json is invalid: " + message)
}
if manifest.platforms.is_empty() {
return Err("moui.project.json platforms must not be empty")
}
let seen : Map[String, Bool] = Map([])
for platform in manifest.platforms {
if seen.contains(platform) {
return Err("moui.project.json contains duplicate platform: " + platform)
}
seen[platform] = true
}
Ok(manifest)
}
///|
fn read_project_manifest(
project_root : String,
) -> Result[ProjectManifest, String] {
let path = join_path(project_root, "moui.project.json")
if !@fs.path_exists(path) {
return Err("project manifest not found: " + path)
}
let text = @fs.read_file_to_string(path) catch {
_ => return Err("could not read project manifest: " + path)
}
parse_project_manifest(text)
}