eyeling 1.6.9 → 1.6.11

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.
Files changed (2) hide show
  1. package/eyeling.js +67 -5
  2. package/package.json +1 -1
package/eyeling.js CHANGED
@@ -36,6 +36,12 @@ const STRING_NS = 'http://www.w3.org/2000/10/swap/string#';
36
36
  const SKOLEM_NS = 'https://eyereasoner.github.io/.well-known/genid/';
37
37
  const RDF_JSON_DT = RDF_NS + 'JSON';
38
38
 
39
+ function resolveIriRef(ref, base) {
40
+ if (!base) return ref;
41
+ if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(ref)) return ref; // already absolute
42
+ try { return new URL(ref, base).toString(); } catch { return ref; }
43
+ }
44
+
39
45
  function isRdfJsonDatatype(dt) {
40
46
  // dt comes from literalParts() and may be expanded or prefixed depending on parsing/printing.
41
47
  return dt === null || dt === RDF_JSON_DT || dt === 'rdf:JSON';
@@ -864,9 +870,9 @@ class Parser {
864
870
  }
865
871
 
866
872
  if (typ === 'IriRef') {
867
- return new Iri(val || '');
873
+ const base = this.prefixes.map[''] || '';
874
+ return new Iri(resolveIriRef(val || '', base));
868
875
  }
869
-
870
876
  if (typ === 'Ident') {
871
877
  const name = val || '';
872
878
  if (name === 'a') {
@@ -4065,6 +4071,61 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4065
4071
  return [{ ...subst }];
4066
4072
  }
4067
4073
 
4074
+ // log:dtlit
4075
+ // Schema: ( $s.1? $s.2? )? log:dtlit $o?
4076
+ // true iff $o is a datatyped literal with string value $s.1 and datatype IRI $s.2
4077
+ if (g.p instanceof Iri && g.p.value === LOG_NS + 'dtlit') {
4078
+ // Fully unbound (both arguments '?'-mode): treat as satisfiable, succeed once.
4079
+ // Required by notation3tests "success-fullUnbound-*".
4080
+ if (g.s instanceof Var && g.o instanceof Var) return [{ ...subst }];
4081
+
4082
+ const results = [];
4083
+
4084
+ // Direction 1: object literal -> subject list (string, datatype)
4085
+ if (g.o instanceof Literal) {
4086
+ const [oLex, oDt0] = literalParts(g.o.value);
4087
+ let oDt = oDt0;
4088
+
4089
+ // literalParts() strips @lang into the lexical part and leaves dt null,
4090
+ // but RDF 1.1 language-tagged strings have datatype rdf:langString.
4091
+ if (oDt === null) {
4092
+ if (literalHasLangTag(g.o.value)) oDt = RDF_NS + 'langString';
4093
+ else if (isPlainStringLiteralValue(g.o.value)) oDt = XSD_NS + 'string';
4094
+ }
4095
+
4096
+ if (oDt !== null) {
4097
+ const strLit = isQuotedLexical(oLex) ? new Literal(oLex) : makeStringLiteral(String(oLex));
4098
+ const subjList = new ListTerm([strLit, new Iri(oDt)]);
4099
+ const s2 = unifyTerm(goal.s, subjList, subst);
4100
+ if (s2 !== null) results.push(s2);
4101
+ }
4102
+ }
4103
+
4104
+ // Direction 2: subject list -> object literal
4105
+ if (g.s instanceof ListTerm && g.s.elems.length === 2) {
4106
+ const a = g.s.elems[0];
4107
+ const b = g.s.elems[1];
4108
+
4109
+ if (a instanceof Literal && b instanceof Iri) {
4110
+ const [sLex, sDt0] = literalParts(a.value);
4111
+
4112
+ // $s.1 must be xsd:string (plain or ^^xsd:string), not language-tagged.
4113
+ const okString =
4114
+ (sDt0 === null && isPlainStringLiteralValue(a.value)) || sDt0 === XSD_NS + 'string';
4115
+ if (okString) {
4116
+ const dtIri = b.value;
4117
+ // For xsd:string, prefer the plain string literal form.
4118
+ const outLit =
4119
+ dtIri === XSD_NS + 'string' ? new Literal(sLex) : new Literal(`${sLex}^^<${dtIri}>`);
4120
+ const s2 = unifyTerm(goal.o, outLit, subst);
4121
+ if (s2 !== null) results.push(s2);
4122
+ }
4123
+ }
4124
+ }
4125
+
4126
+ return results;
4127
+ }
4128
+
4068
4129
  // log:implies — expose internal forward rules as data
4069
4130
  if (g.p instanceof Iri && g.p.value === LOG_NS + 'implies') {
4070
4131
  const allFw = backRules.__allForwardRules || [];
@@ -4241,9 +4302,10 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4241
4302
  return s2 !== null ? [s2] : [];
4242
4303
  }
4243
4304
 
4244
- // If neither side is sufficiently instantiated (both vars, or wrong types),
4245
- // we don't enumerate URIs; the builtin just fails.
4246
- return [];
4305
+ const sOk = (g.s instanceof Var) || (g.s instanceof Blank) || (g.s instanceof Iri);
4306
+ const oOk = (g.o instanceof Var) || (g.o instanceof Blank) || (g.o instanceof Literal);
4307
+ if (!sOk || !oOk) return [];
4308
+ return [{ ...subst }];
4247
4309
  }
4248
4310
 
4249
4311
  // -----------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.6.9",
3
+ "version": "1.6.11",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [