diff --git a/moon_config/README.mbt.md b/moon_config/README.mbt.md index f59c3b4b..f62bb1e4 100644 --- a/moon_config/README.mbt.md +++ b/moon_config/README.mbt.md @@ -11,6 +11,12 @@ post-processing the raw AST, so their diagnostics include duplicate and unexpected top-level keys. Use `validate_moon_mod`, `validate_moon_pkg`, or `validate_moon_work` only when validating an already post-processed `Ast`. +`moon.mod` accepts an optional boolean `private` field. An absent field or +`private = false` denotes public access; `private = true` denotes private access +in a registry that supports it. Both a top-level assignment and +`options(private: true)` are preserved in the JSON output. Non-boolean values +and duplicate fields produce diagnostics. + ## Examples Parse a `moon.mod` file and convert the returned `Ast` to JSON: diff --git a/moon_config/post_process.mbt b/moon_config/post_process.mbt index 03beadaa..99aea4fe 100644 --- a/moon_config/post_process.mbt +++ b/moon_config/post_process.mbt @@ -99,6 +99,10 @@ fn post_process_moon_mod(ast : Ast, diagnostics : Array[Report]) -> Ast { | "description" | "source" | "rule" => results.push(field) + "private" => { + validate_private(value, diagnostics) + results.push(field) + } "preferred_target" => results.push(("preferred-target", value)) "warnings" => match value { @@ -146,6 +150,9 @@ fn post_process_moon_mod(ast : Ast, diagnostics : Array[Report]) -> Ast { seen, diagnostics, "moon.mod", allowed_duplicate, option_key, option_value, ) + if option_key == "private" { + validate_private(option_value, diagnostics) + } results.push(option_field) } _ => { diff --git a/moon_config/private_wbtest.mbt b/moon_config/private_wbtest.mbt new file mode 100644 index 00000000..fb789da6 --- /dev/null +++ b/moon_config/private_wbtest.mbt @@ -0,0 +1,44 @@ +///| +test "moon.mod private is optional and preserves boolean values" { + let (absent, absent_reports) = parse_moon_mod("name = \"user/mod\"") + assert_true(absent_reports.is_empty()) + json_inspect(ToJson::to_json(absent), content={ "name": "user/mod" }) + let (public_mod, public_reports) = parse_moon_mod("private = false") + assert_true(public_reports.is_empty()) + json_inspect(ToJson::to_json(public_mod), content={ "private": false }) + let (private_mod, private_reports) = parse_moon_mod("private = true") + assert_true(private_reports.is_empty()) + assert_true(validate_moon_mod(private_mod).is_empty()) + json_inspect(ToJson::to_json(private_mod), content={ "private": true }) +} + +///| +test "moon.mod options preserves private" { + let (ast, reports) = parse_moon_mod("options(private: true)") + assert_true(reports.is_empty()) + json_inspect(ToJson::to_json(ast), content={ "private": true }) +} + +///| +test "moon.mod rejects non-boolean private" { + let (_, reports) = parse_moon_mod("private = \"true\"") + assert_eq(reports.map(report => report.msg), [ + "Invalid moon.mod config: `private` must be a boolean.", + ]) + let (_, reports) = parse_moon_mod("options(private: 1)") + assert_eq(reports.map(report => report.msg), [ + "Invalid moon.mod config: `private` must be a boolean.", + ]) + let (ast, _) = parse_moon_mod("private = []") + assert_eq(validate_moon_mod(ast).map(report => report.msg), [ + "Invalid moon.mod config: `private` must be a boolean.", + ]) +} + +///| +test "moon.mod rejects duplicate private across options" { + let (_, reports) = parse_moon_mod("private = true\noptions(private: false)") + assert_eq(reports.map(report => report.msg), [ + "Duplicate key `private` found in moon.mod.", + ]) +} diff --git a/moon_config/validate.mbt b/moon_config/validate.mbt index e8967b3a..6818a0a1 100644 --- a/moon_config/validate.mbt +++ b/moon_config/validate.mbt @@ -51,6 +51,16 @@ fn validate_pkgtype_kind(value : Ast, diagnostics : Array[Report]) -> Unit { } } +///| +fn validate_private(value : Ast, diagnostics : Array[Report]) -> Unit { + if !(value is Bool(_, ..)) { + diagnostics.push({ + loc: value.loc(), + msg: "Invalid moon.mod config: `private` must be a boolean.", + }) + } +} + ///| fn _validate_moon_pkg(ast : Ast, diagnostics : Array[Report]) -> Unit { match ast { @@ -88,6 +98,7 @@ fn _validate_moon_mod(ast : Ast, diagnostics : Array[Report]) -> Unit { seen, diagnostics, "moon.mod", allowed_duplicate, key, value, ) match key { + "private" => validate_private(value, diagnostics) "warnings" | "supported_targets" | "preferred_target"