eyeling 1.33.0 → 1.33.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -791,7 +791,7 @@ Eyeling provides datatype built-ins in the namespace `https://eyereasoner.github
791
791
 
792
792
  Supported operations include:
793
793
 
794
- - `dt:datatype`, `dt:lexicalForm`, and `dt:language` for literal inspection;
794
+ - `dt:datatype`, `dt:lexicalForm`, and `dt:language` for literal inspection. `dt:datatype` returns the literal's actual datatype IRI only, so RDF string literals return `xsd:string`; it does not return `rdfs:Literal`, which is a class of literals rather than a datatype IRI;
795
795
  - `dt:validForDatatype` and `dt:invalidForDatatype` for lexical validity and datatype membership checks, either as `?literal dt:validForDatatype ?datatype` tests or as tuple-to-boolean checks like `(?literal ?datatype) dt:validForDatatype true`;
796
796
  - `dt:sameValueAs` and `dt:differentValueFrom` for value-space equality and inequality;
797
797
  - `dt:canonicalLiteral` for canonical literal production.
@@ -1888,17 +1888,7 @@ function evalDatatypeInspectionBuiltin(g, subst, kind) {
1888
1888
  const dt = literalDatatypeIri(g.s);
1889
1889
  if (dt === null) return [];
1890
1890
  valueTerm = internIri(dt);
1891
- const out = evalBindBuiltinObject(g.o, valueTerm, subst);
1892
-
1893
- // OWL 2 RL datatype rules often need common string literals to also
1894
- // participate in generic literal comparisons, while application rules still
1895
- // ask for their precise datatype explicitly. When the datatype output is
1896
- // unbound, expose rdfs:Literal as an additional super-datatype answer for
1897
- // xsd:string and rdf:langString; bound-object calls remain strictly exact.
1898
- if (g.o instanceof Var && (dt === XSD_STRING_DT || dt === RDF_LANGSTRING_DT)) {
1899
- out.push(...evalBindBuiltinObject(g.o, internIri(RDFS_LITERAL_DT), subst));
1900
- }
1901
- return out;
1891
+ return evalBindBuiltinObject(g.o, valueTerm, subst);
1902
1892
  } else if (kind === 'lexicalForm') {
1903
1893
  valueTerm = makeStringLiteral(literalLexicalValue(g.s.value));
1904
1894
  } else if (kind === 'language') {
@@ -45,7 +45,7 @@ ex:aliasOf a rdf:Property .
45
45
  # --- dt: datatype ---------------------------------------------------
46
46
 
47
47
  dt:datatype a ex:Builtin ; ex:kind ex:Function ;
48
- rdfs:comment "Extracts the datatype IRI of a literal. Plain RDF string literals return xsd:string; language-tagged strings return rdf:langString; shorthand numeric/boolean literals return their inferred XSD datatype." .
48
+ rdfs:comment "Extracts the datatype IRI of a literal. Plain RDF string literals return xsd:string; language-tagged strings return rdf:langString; shorthand numeric/boolean literals return their inferred XSD datatype. It returns the literal's actual datatype IRI only; rdfs:Literal is a class and is not returned by dt:datatype." .
49
49
 
50
50
  dt:lexicalForm a ex:Builtin ; ex:kind ex:Function ;
51
51
  rdfs:comment "Extracts the literal lexical form as an xsd:string/plain string value, preserving the original lexical spelling such as leading zeroes." .
package/eyeling.js CHANGED
@@ -1888,17 +1888,7 @@ function evalDatatypeInspectionBuiltin(g, subst, kind) {
1888
1888
  const dt = literalDatatypeIri(g.s);
1889
1889
  if (dt === null) return [];
1890
1890
  valueTerm = internIri(dt);
1891
- const out = evalBindBuiltinObject(g.o, valueTerm, subst);
1892
-
1893
- // OWL 2 RL datatype rules often need common string literals to also
1894
- // participate in generic literal comparisons, while application rules still
1895
- // ask for their precise datatype explicitly. When the datatype output is
1896
- // unbound, expose rdfs:Literal as an additional super-datatype answer for
1897
- // xsd:string and rdf:langString; bound-object calls remain strictly exact.
1898
- if (g.o instanceof Var && (dt === XSD_STRING_DT || dt === RDF_LANGSTRING_DT)) {
1899
- out.push(...evalBindBuiltinObject(g.o, internIri(RDFS_LITERAL_DT), subst));
1900
- }
1901
- return out;
1891
+ return evalBindBuiltinObject(g.o, valueTerm, subst);
1902
1892
  } else if (kind === 'lexicalForm') {
1903
1893
  valueTerm = makeStringLiteral(literalLexicalValue(g.s.value));
1904
1894
  } else if (kind === 'language') {
package/lib/builtins.js CHANGED
@@ -1877,17 +1877,7 @@ function evalDatatypeInspectionBuiltin(g, subst, kind) {
1877
1877
  const dt = literalDatatypeIri(g.s);
1878
1878
  if (dt === null) return [];
1879
1879
  valueTerm = internIri(dt);
1880
- const out = evalBindBuiltinObject(g.o, valueTerm, subst);
1881
-
1882
- // OWL 2 RL datatype rules often need common string literals to also
1883
- // participate in generic literal comparisons, while application rules still
1884
- // ask for their precise datatype explicitly. When the datatype output is
1885
- // unbound, expose rdfs:Literal as an additional super-datatype answer for
1886
- // xsd:string and rdf:langString; bound-object calls remain strictly exact.
1887
- if (g.o instanceof Var && (dt === XSD_STRING_DT || dt === RDF_LANGSTRING_DT)) {
1888
- out.push(...evalBindBuiltinObject(g.o, internIri(RDFS_LITERAL_DT), subst));
1889
- }
1890
- return out;
1880
+ return evalBindBuiltinObject(g.o, valueTerm, subst);
1891
1881
  } else if (kind === 'lexicalForm') {
1892
1882
  valueTerm = makeStringLiteral(literalLexicalValue(g.s.value));
1893
1883
  } else if (kind === 'language') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.33.0",
3
+ "version": "1.33.1",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [
@@ -199,7 +199,6 @@ const cases = [
199
199
  { "11"^^xsd:integer dt:differentValueFrom "12"^^xsd:integer . } => { :different :numeric true } .
200
200
  { "hello@en"^^rdf:PlainLiteral dt:differentValueFrom "bye@en"^^rdf:PlainLiteral . } => { :different :plainLiteral true } .
201
201
  { "a" dt:differentValueFrom "b" . } => { :different :string true } .
202
- { "a" dt:datatype ?sd . ?sd <http://www.w3.org/2000/10/swap/log#notEqualTo> xsd:string . } => { :string :comparisonDatatype ?sd } .
203
202
  { "<a/>"^^rdf:XMLLiteral dt:differentValueFrom "<b/>"^^rdf:XMLLiteral . } => { :different :xmlLiteral true } .
204
203
 
205
204
  { ("1"^^xsd:integer xsd:integer) dt:validForDatatype true . } => { :tuple :valid true } .
@@ -252,7 +251,6 @@ const cases = [
252
251
  assert.match(out, /:different :numeric true \./);
253
252
  assert.match(out, /:different :plainLiteral true \./);
254
253
  assert.match(out, /:different :string true \./);
255
- assert.match(out, /:string :comparisonDatatype rdfs:Literal \./);
256
254
  assert.match(out, /:different :xmlLiteral true \./);
257
255
  assert.match(out, /:tuple :valid true \./);
258
256
  assert.match(out, /:tuple :invalidBoolean true \./);
@@ -265,6 +263,21 @@ const cases = [
265
263
  assert.match(out, /:canonical :dateTime "2026-06-10T12:00:00Z"\^\^xsd:dateTime \./);
266
264
  assert.match(out, /:canonical :midnightRollover "2027-01-01T00:00:00Z"\^\^xsd:dateTime \./);
267
265
  assert.match(out, /:sameAs :reflexive true \./);
266
+
267
+ const datatypeOut = runReason(`
268
+ @prefix : <http://example.org/datatype-tests#> .
269
+ @prefix dt: <https://eyereasoner.github.io/eyeling/datatype#> .
270
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
271
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
272
+ :s :plainName "Alice" .
273
+ :s :typedName "Alice"^^xsd:string .
274
+ { :s :plainName ?value . ?value dt:datatype ?datatype . } => { :plain :detectedDatatype ?datatype } .
275
+ { :s :typedName ?value . ?value dt:datatype ?datatype . } => { :typed :detectedDatatype ?datatype } .
276
+ `);
277
+ assert.match(datatypeOut, /:plain :detectedDatatype xsd:string \./);
278
+ assert.match(datatypeOut, /:typed :detectedDatatype xsd:string \./);
279
+ assert.doesNotMatch(datatypeOut, /:plain :detectedDatatype rdfs:Literal \./);
280
+ assert.doesNotMatch(datatypeOut, /:typed :detectedDatatype rdfs:Literal \./);
268
281
  },
269
282
  },
270
283
  {