// Portions adapted from google/go-jsonnet v0.21.0 (Apache-2.0).
// https://github.com/google/go-jsonnet/tree/67968688d9952f50662e979fab1bef889d0d3e57
// Source: internal/formatter/jsonnetfmt.go
// Source: internal/formatter/unparser.go
// Source: internal/parser/lexer.go
// Copyright 2019 Google Inc. All rights reserved.
// Copyright 2016 Google Inc. All rights reserved.
// Modifications: Implemented formatting controls and structural emission with local syntax containers and budgets.
// License and retained attribution: LICENSE and NOTICE at the module root.
///|
// Structural edits use parsed expression ranges rather than guessing operator
// precedence from adjacent tokens. The token stream retains parentheses that
// the semantic expression tree intentionally discards.
fn format_plus_edits(
root : Expr,
tokens : Array[Token],
skip : Array[Bool],
insert_plus : Array[Bool],
implicit : Bool,
) -> Unit {
let positions : Map[(Int, Int), Int] = Map([])
for i, token in tokens {
positions[(token.loc.line, token.loc.column)] = i
}
let stack = [root]
while stack.pop() is Some(e) {
if e.kind is Binary("+", left, right) &&
(right.kind is Obj(_, _, _, _) || right.kind is ObjectComp(_, _, _, _)) &&
positions.get((right.loc.line, right.loc.column)) is Some(i) &&
i > 0 &&
tokens[i].text == "{" {
if tokens[i - 1].text == "+" {
if implicit &&
right.kind is Obj(_, _, _, _) &&
(
(left.kind is Var(name) && is_name(name)) ||
left.kind is Index(_, _)
) &&
i > 1 &&
left.end == Some(tokens[i - 2].end) {
skip[i - 1] = true
}
} else if !implicit && tokens[i - 1].text != "(" {
insert_plus[i] = true
}
}
stack.append(lint_children(e))
// Lint traversal omits object assertions; formatting must retain them.
if e.kind is Obj(_, _, assertions, _) {
for (condition, message) in assertions {
stack.push(condition)
if message is Some(message) {
stack.push(message)
}
}
}
}
}