From f568886d5dceacf485deffa1244fae515318868c Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Mon, 3 Aug 2026 09:28:18 -0300 Subject: [PATCH] Add some more JSON-LD related custom linter rules Signed-off-by: Juan Cruz Viotti --- jsonschema.json | 5 + rules/jsonld-bare-override.json | 6 + rules/jsonld-constants-iri-literal.json | 60 ++++++++++ rules/jsonld-constants-lexical.json | 133 ++++++++++++++++++++++ rules/jsonld-constants-reserved-type.json | 42 +++++++ rules/jsonld-datatype-reserved.json | 15 +++ rules/jsonld-unmarked-null.json | 16 +++ rules/jsonld-value-rdf-type.json | 12 ++ 8 files changed, 289 insertions(+) create mode 100644 rules/jsonld-constants-iri-literal.json create mode 100644 rules/jsonld-constants-lexical.json create mode 100644 rules/jsonld-constants-reserved-type.json create mode 100644 rules/jsonld-datatype-reserved.json create mode 100644 rules/jsonld-value-rdf-type.json diff --git a/jsonschema.json b/jsonschema.json index 29aeb15a..0a3d2a78 100644 --- a/jsonschema.json +++ b/jsonschema.json @@ -13,7 +13,12 @@ "./rules/dialect.json", "./rules/identifiers.json", "./rules/jsonld-bare-override.json", + "./rules/jsonld-constants-iri-literal.json", + "./rules/jsonld-constants-lexical.json", + "./rules/jsonld-constants-reserved-type.json", + "./rules/jsonld-datatype-reserved.json", "./rules/jsonld-unmarked-null.json", + "./rules/jsonld-value-rdf-type.json", "./rules/license.json", "./rules/links.json", "./rules/single-line-text.json", diff --git a/rules/jsonld-bare-override.json b/rules/jsonld-bare-override.json index 6493fc3d..57b971c7 100644 --- a/rules/jsonld-bare-override.json +++ b/rules/jsonld-bare-override.json @@ -36,6 +36,12 @@ }, { "required": [ "x-jsonld-self" ] + }, + { + "required": [ "x-jsonld-value" ] + }, + { + "required": [ "x-jsonld-constants" ] } ] } diff --git a/rules/jsonld-constants-iri-literal.json b/rules/jsonld-constants-iri-literal.json new file mode 100644 index 00000000..c3c7194b --- /dev/null +++ b/rules/jsonld-constants-iri-literal.json @@ -0,0 +1,60 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "std/jsonld_constants_iri_literal", + "description": "A bare string in a constants fragment is always a string literal, so a string that looks like an IRI is almost certainly a node reference missing its id member", + "properties": { + "x-jsonld-constants": { + "additionalProperties": { + "allOf": [ + { + "$ref": "#/$defs/term" + }, + { + "if": { + "type": "array" + }, + "then": { + "items": { + "$ref": "#/$defs/term" + } + } + } + ] + } + } + }, + "$defs": { + "term": { + "allOf": [ + { + "not": { + "type": "string", + "pattern": "^([A-Za-z][A-Za-z0-9+.-]*://|urn:|mailto:|did:|tag:)" + } + }, + { + "not": { + "type": "object", + "not": { + "anyOf": [ + { + "required": [ "@type" ] + }, + { + "required": [ "@language" ] + } + ] + }, + "required": [ "@value" ], + "properties": { + "@value": { + "type": "string", + "pattern": "^([A-Za-z][A-Za-z0-9+.-]*://|urn:|mailto:|did:|tag:)" + } + } + } + } + ] + } + } +} diff --git a/rules/jsonld-constants-lexical.json b/rules/jsonld-constants-lexical.json new file mode 100644 index 00000000..6d27bb91 --- /dev/null +++ b/rules/jsonld-constants-lexical.json @@ -0,0 +1,133 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "std/jsonld_constants_lexical", + "description": "A constant typed literal whose value sits outside the lexical space of its datatype converts to an ill-typed literal that RDF implementations must accept, so this is the only place to catch it", + "properties": { + "x-jsonld-constants": { + "additionalProperties": { + "allOf": [ + { + "$ref": "#/$defs/term" + }, + { + "if": { + "type": "array" + }, + "then": { + "items": { + "$ref": "#/$defs/term" + } + } + } + ] + } + } + }, + "$defs": { + "term": { + "allOf": [ + { + "if": { + "type": "object", + "required": [ "@value", "@type" ], + "properties": { + "@value": { + "type": "number" + }, + "@type": { + "$ref": "#/$defs/integer-datatypes" + } + } + }, + "then": { + "properties": { + "@value": { + "multipleOf": 1 + } + } + } + }, + { + "if": { + "type": "object", + "required": [ "@value", "@type" ], + "properties": { + "@value": { + "type": "string" + }, + "@type": { + "$ref": "#/$defs/integer-datatypes" + } + } + }, + "then": { + "properties": { + "@value": { + "pattern": "^[+-]?[0-9]+$" + } + } + } + }, + { + "if": { + "type": "object", + "required": [ "@value", "@type" ], + "properties": { + "@value": { + "type": "string" + }, + "@type": { + "const": "http://www.w3.org/2001/XMLSchema#decimal" + } + } + }, + "then": { + "properties": { + "@value": { + "pattern": "^[+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)$" + } + } + } + }, + { + "if": { + "type": "object", + "required": [ "@value", "@type" ], + "properties": { + "@value": { + "type": "string" + }, + "@type": { + "const": "http://www.w3.org/2001/XMLSchema#boolean" + } + } + }, + "then": { + "properties": { + "@value": { + "enum": [ "true", "false", "1", "0" ] + } + } + } + } + ] + }, + "integer-datatypes": { + "enum": [ + "http://www.w3.org/2001/XMLSchema#integer", + "http://www.w3.org/2001/XMLSchema#long", + "http://www.w3.org/2001/XMLSchema#int", + "http://www.w3.org/2001/XMLSchema#short", + "http://www.w3.org/2001/XMLSchema#byte", + "http://www.w3.org/2001/XMLSchema#nonNegativeInteger", + "http://www.w3.org/2001/XMLSchema#nonPositiveInteger", + "http://www.w3.org/2001/XMLSchema#negativeInteger", + "http://www.w3.org/2001/XMLSchema#positiveInteger", + "http://www.w3.org/2001/XMLSchema#unsignedLong", + "http://www.w3.org/2001/XMLSchema#unsignedInt", + "http://www.w3.org/2001/XMLSchema#unsignedShort", + "http://www.w3.org/2001/XMLSchema#unsignedByte" + ] + } + } +} diff --git a/rules/jsonld-constants-reserved-type.json b/rules/jsonld-constants-reserved-type.json new file mode 100644 index 00000000..196d9758 --- /dev/null +++ b/rules/jsonld-constants-reserved-type.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "std/jsonld_constants_reserved_type", + "description": "A langString literal requires a language tag that only the language member can provide, and a JSON literal cannot be a constant, so neither IRI is a usable value object type", + "properties": { + "x-jsonld-constants": { + "additionalProperties": { + "allOf": [ + { + "$ref": "#/$defs/term" + }, + { + "if": { + "type": "array" + }, + "then": { + "items": { + "$ref": "#/$defs/term" + } + } + } + ] + } + } + }, + "$defs": { + "term": { + "not": { + "type": "object", + "required": [ "@type" ], + "properties": { + "@type": { + "enum": [ + "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString", + "http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON" + ] + } + } + } + } + } +} diff --git a/rules/jsonld-datatype-reserved.json b/rules/jsonld-datatype-reserved.json new file mode 100644 index 00000000..ecc73e1f --- /dev/null +++ b/rules/jsonld-datatype-reserved.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "std/jsonld_datatype_reserved", + "description": "A langString literal requires a language tag that only x-jsonld-language can provide, and a JSON literal is declared with x-jsonld-json, so neither IRI is a usable datatype", + "properties": { + "x-jsonld-datatype": { + "not": { + "enum": [ + "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString", + "http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON" + ] + } + } + } +} diff --git a/rules/jsonld-unmarked-null.json b/rules/jsonld-unmarked-null.json index 77f1b468..119c154c 100644 --- a/rules/jsonld-unmarked-null.json +++ b/rules/jsonld-unmarked-null.json @@ -83,6 +83,22 @@ "type": "null" } } + }, + { + "required": [ "x-jsonld-value" ], + "properties": { + "x-jsonld-value": { + "type": "null" + } + } + }, + { + "required": [ "x-jsonld-constants" ], + "properties": { + "x-jsonld-constants": { + "type": "null" + } + } } ] }, diff --git a/rules/jsonld-value-rdf-type.json b/rules/jsonld-value-rdf-type.json new file mode 100644 index 00000000..a47c0f7c --- /dev/null +++ b/rules/jsonld-value-rdf-type.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "std/jsonld_value_rdf_type", + "description": "The rdf:type predicate as a value predicate would mint type edges to literals, and node types are declared with x-jsonld-type", + "properties": { + "x-jsonld-value": { + "not": { + "const": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" + } + } + } +}