Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions src/oold/validation/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,23 @@ def walk(node: Any) -> None:
return found


def _is_reference_term(definition: Any) -> bool:
"""True when a context term definition makes its values node references."""
if not isinstance(definition, dict):
return False
return definition.get("@type") == "@id" or "@reverse" in definition


def reference_properties(schema: dict[str, Any]) -> list[str]:
"""Properties whose value is a reference, so framing must leave it an IRI.

Three signals, per ``OOLD-EXT-68fa``: an ``x-oold-range`` on a string-typed value, an
IRI-family ``format`` (the family ``OOLD-EXT-6ea3`` recommends), or a context term mapped
``"@type": "@id"``.
Four signals, per ``OOLD-EXT-6d10``: an ``x-oold-range`` on a string-typed value, an
IRI-family ``format`` (the family ``OOLD-EXT-6ea3`` recommends), a context term mapped
``"@type": "@id"``, or one mapped with ``@reverse``.

``@reverse`` stands on its own. A reverse term's values are node references by definition
(JSON-LD 1.1 4.1.10), so ``"@type": "@id"`` beside it is redundant and authors omit it;
keying only on ``@type`` misses the idiomatic spelling and embeds the targets.

Embedding takes precedence where a property carries both: a property shaped like an object
is an embed whatever its term says.
Expand Down Expand Up @@ -189,7 +200,7 @@ def is_reference(node: Any) -> bool:
for name, prop in properties.items()
if name not in aliases
and not is_embed(prop)
and (is_reference(prop) or terms.get(name, {}).get("@type") == "@id")
and (is_reference(prop) or _is_reference_term(terms.get(name, {})))
]


Expand Down
15 changes: 15 additions & 0 deletions tests/test_validation/test_jsonld.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,21 @@ def test_embedding_wins_where_a_property_carries_both_signals():
assert reference_properties(schema) == []


def test_a_bare_reverse_term_is_reference_valued():
"""A reverse term's values are node references by definition (JSON-LD 1.1 4.1.10).

``"@type": "@id"`` beside ``@reverse`` is redundant, and the specification's own worked
example writes both, so keying only on ``@type`` passed every fixture while missing the
idiomatic spelling and embedding the targets.
"""
schema = {
"@context": {"employees": {"@reverse": "schema:worksFor"}},
"properties": {"employees": {"type": "array", "items": {"type": "string"}}},
}
assert reference_properties(schema) == ["employees"]
assert schema_to_frame(schema)["employees"] == {"@embed": "@never"}


def test_a_keyword_alias_never_gets_a_subframe():
"""``id`` is the node's name, not a predicate.

Expand Down
Loading