Build BoardWriter — atomic, minimal-touch writes
The single point through which every mutation becomes a filesystem
operation: read fresh from disk (strict byte-faithful UTF-8), refuse
readable-but-uneditable frontmatter shapes, apply the edit through the
span engine, stamp modified / clear modified-by, then temp-file+rename
atomically. Renumber-visible-children is the sole minimal-touch
exception, tombstones untouched. Structured BoardWriteError carries
operation + path + reason for the future banner surface.
Alongside, three edges the card surfaced:
- The loader now decodes byte-faithfully too, so a BOM'd or non-UTF-8
index.md is rejected at load per the encoding contract, instead of
loading via NSString's silent BOM strip and then refusing every write.
- An appended frontmatter line adopts the file's prevailing line ending
(a CRLF file stays uniformly CRLF when a stamp first lands in it).
- Empty-but-not-blank frontmatter ({}, null, ~) is detected as
uneditable — appending after it would be unparseable YAML.
30 new unit tests; 176 total green.
Claude-Session: https://claude.ai/code/session_018BjQRYBR6jQja3jCRi5S3A
This commit is contained in:
@@ -962,3 +962,37 @@ struct FrontmatterEmissionTests {
|
||||
== .mapping([YAMLValue.Pair(key: .string("order"), value: .int(7))]))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Appended lines and empty-but-not-blank blocks
|
||||
|
||||
struct FrontmatterAppendedLineTests {
|
||||
@Test func appendedKeyAdoptsCRLFInACRLFFile() throws {
|
||||
var document = try FrontmatterDocument.parse("---\r\nschema: 1\r\n---\r\nbody\r\n")
|
||||
document.set("title", to: .string("x"))
|
||||
#expect(document.serialized() == "---\r\nschema: 1\r\ntitle: x\r\n---\r\nbody\r\n")
|
||||
}
|
||||
|
||||
@Test func appendedKeyStaysLFInAnLFFile() throws {
|
||||
var document = try FrontmatterDocument.parse("---\nschema: 1\n---\nbody\n")
|
||||
document.set("title", to: .string("x"))
|
||||
#expect(document.serialized() == "---\nschema: 1\ntitle: x\n---\nbody\n")
|
||||
}
|
||||
|
||||
/// `{}`, `null`, `~` resolve to an empty mapping yet leave text no key owns — appending
|
||||
/// after it would be unparseable YAML, so the shape refuses edits (readable-but-uneditable).
|
||||
@Test(arguments: ["---\n{}\n---\nbody\n", "---\nnull\n---\nbody\n", "---\n~\n---\nbody\n"])
|
||||
func emptyButNotBlankFrontmatterIsUneditable(text: String) throws {
|
||||
#expect(try FrontmatterDocument.parse(text).uneditableShape == .keyWithoutOwnLine)
|
||||
}
|
||||
|
||||
/// Truly blank or comment-only frontmatter stays editable — appending after it is exactly
|
||||
/// what `set` is for, and the result must reparse.
|
||||
@Test(arguments: ["---\n---\nbody\n", "---\n\n---\nbody\n", "---\n# just a comment\n---\nbody\n"])
|
||||
func blankOrCommentOnlyFrontmatterStaysEditable(text: String) throws {
|
||||
var document = try FrontmatterDocument.parse(text)
|
||||
#expect(document.uneditableShape == nil)
|
||||
document.set("schema", to: .int(1))
|
||||
let reparsed = try FrontmatterDocument.parse(document.serialized())
|
||||
#expect(reparsed.schema == .valid(1))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user