Adopt read-side coercion for schema-owned fields
Design-review resolutions: schema-owned display fields coerce where a sensible reading exists (wrong-type scalars read as source text, width accepts exact-integer strings/doubles) and default where none does; null reads as missing; duplicate keys last-one-wins and inline-comment re-splicing recorded in the design (engine change follows). Strict schema/order fail-fast unchanged. 85 tests green. Claude-Session: https://claude.ai/code/session_018BjQRYBR6jQja3jCRi5S3A
This commit is contained in:
@@ -345,11 +345,26 @@ struct FrontmatterLenientFieldTests {
|
||||
#expect(try document("width: 1").width == .valid(1))
|
||||
}
|
||||
|
||||
/// A scalar of the wrong YAML type still has a sensible string reading — it coerces to the
|
||||
/// source text the author typed (01-storage-format.md § Frontmatter). Only a sequence or
|
||||
/// mapping — no scalar to read at all — is malformed.
|
||||
@Test func scalarsOfTheWrongTypeCoerceToTheirSourceText() throws {
|
||||
#expect(try document("title: 2048").title == .valid("2048"))
|
||||
#expect(try document("title: true").title == .valid("true"))
|
||||
#expect(try document("background: 42").background == .valid("42"))
|
||||
#expect(try document("iconColor: true").iconColor == .valid("true"))
|
||||
#expect(try document("icon: 2026-07-26T16:41:38Z").icon == .valid("2026-07-26T16:41:38Z"))
|
||||
}
|
||||
|
||||
@Test func quotedStringLenientValuesAreUnaffectedByCoercion() throws {
|
||||
#expect(try document("title: \"2048\"").title == .valid("2048"))
|
||||
#expect(try document("title: \"true\"").title == .valid("true"))
|
||||
#expect(try document("title: My Board").title == .valid("My Board"))
|
||||
}
|
||||
|
||||
@Test func malformedLenientValuesArePreservedVerbatimAndDoNotThrow() throws {
|
||||
#expect(try document("background: [red, blue]").background == .malformed(raw: "[red, blue]"))
|
||||
#expect(try document("background: 42").background == .malformed(raw: "42"))
|
||||
#expect(try document("icon: {a: 1}").icon == .malformed(raw: "{a: 1}"))
|
||||
#expect(try document("iconColor: true").iconColor == .malformed(raw: "true"))
|
||||
#expect(try document("title: [a, b]").title == .malformed(raw: "[a, b]"))
|
||||
}
|
||||
|
||||
@@ -361,6 +376,17 @@ struct FrontmatterLenientFieldTests {
|
||||
#expect(try document("schema: 1").width == .missing)
|
||||
}
|
||||
|
||||
/// A string or double with an exact integer reading ≥ 1 coerces; a fractional reading,
|
||||
/// zero, a negative, or non-numeric text still has none.
|
||||
@Test func widthCoercesStringsAndWholeNumberDoubles() throws {
|
||||
#expect(try document("width: \"2\"").width == .valid(2))
|
||||
#expect(try document("width: 2.0").width == .valid(2))
|
||||
#expect(try document("width: 2.7").width == .malformed(raw: "2.7"))
|
||||
#expect(try document("width: 0").width == .malformed(raw: "0"))
|
||||
#expect(try document("width: -1").width == .malformed(raw: "-1"))
|
||||
#expect(try document("width: banana").width == .malformed(raw: "banana"))
|
||||
}
|
||||
|
||||
@Test func malformedLenientValuesStillRoundTrip() throws {
|
||||
let text = "---\nschema: 1\nbackground: [red, blue]\nwidth: 0\nicon: {a: 1}\n---\nbody\n"
|
||||
let document = try FrontmatterDocument.parse(text)
|
||||
@@ -378,6 +404,13 @@ struct FrontmatterLenientFieldTests {
|
||||
#expect(try document("schema: 1").deleted == .missing)
|
||||
#expect(try document("created: never").created == .malformed(raw: "never"))
|
||||
}
|
||||
|
||||
/// A quoted ISO-8601 string is not YAML's implicit timestamp type — it parses as `.string`
|
||||
/// — but still coerces to a valid date (01-storage-format.md § Frontmatter).
|
||||
@Test func quotedISO8601StringCoercesToAValidDate() throws {
|
||||
let expected = Date(timeIntervalSince1970: 1_767_323_045) // 2026-01-02T03:04:05Z
|
||||
#expect(try document("created: \"2026-01-02T03:04:05Z\"").created == .valid(expected))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Surgical edits
|
||||
|
||||
Reference in New Issue
Block a user