eyeling 1.7.9 → 1.7.10

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
@@ -216,10 +216,10 @@ Commonly used N3/Turtle features:
216
216
 
217
217
  - **crypto**: `crypto:md5` `crypto:sha` `crypto:sha256` `crypto:sha512`
218
218
  - **list**: `list:append` `list:first` `list:firstRest` `list:in` `list:iterate` `list:last` `list:length` `list:map` `list:member` `list:memberAt` `list:notMember` `list:remove` `list:rest` `list:reverse` `list:sort`
219
- - **log**: `log:collectAllIn` `log:content` `log:equalTo` `log:forAllIn` `log:impliedBy` `log:implies` `log:notEqualTo` `log:notIncludes` `log:semantics` `log:skolem` `log:uri`
219
+ - **log**: `log:collectAllIn` `log:content` `log:dtlit` `log:equalTo` `log:forAllIn` `log:impliedBy` `log:implies` `log:includes` `log:langlit` `log:notEqualTo` `log:notIncludes` `log:outputString` `log:parsedAsN3` `log:rawType` `log:semantics` `log:semanticsOrError` `log:skolem` `log:uri`
220
220
  - **math**: `math:absoluteValue` `math:acos` `math:asin` `math:atan` `math:cos` `math:cosh` `math:degrees` `math:difference` `math:equalTo` `math:exponentiation` `math:greaterThan` `math:integerQuotient` `math:lessThan` `math:negation` `math:notEqualTo` `math:notGreaterThan` `math:notLessThan` `math:product` `math:quotient` `math:remainder` `math:rounded` `math:sin` `math:sinh` `math:sum` `math:tan` `math:tanh`
221
221
  - **string**: `string:concatenation` `string:contains` `string:containsIgnoringCase` `string:endsWith` `string:equalIgnoringCase` `string:format` `string:greaterThan` `string:jsonPointer` `string:lessThan` `string:matches` `string:notEqualIgnoringCase` `string:notGreaterThan` `string:notLessThan` `string:notMatches` `string:replace` `string:scrape` `string:startsWith`
222
- - **time**: `time:localTime`
222
+ - **time**: `time:day` `time:localTime` `time:minute` `time:month` `time:second` `time:timeZone` `time:year`
223
223
 
224
224
  ## License
225
225
 
@@ -0,0 +1,8 @@
1
+ @prefix : <http://example.org/> .
2
+
3
+ :out :year 2023 .
4
+ :out :month 4 .
5
+ :out :day 1 .
6
+ :out :minute 6 .
7
+ :out :second 4 .
8
+ :out :tz "Z" .
@@ -0,0 +1,29 @@
1
+ # =======================
2
+ # time: builtins examples
3
+ # =======================
4
+
5
+ @prefix : <http://example.org/> .
6
+ @prefix time: <http://www.w3.org/2000/10/swap/time#> .
7
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
8
+
9
+ :Let :dt "2023-04-01T18:06:04Z"^^xsd:dateTime .
10
+
11
+ {
12
+ :Let :dt ?d .
13
+ ?d time:year ?y ;
14
+ time:month ?m ;
15
+ time:day ?day ;
16
+ time:minute ?min ;
17
+ time:second ?sec ;
18
+ time:timeZone ?tz .
19
+ }
20
+ =>
21
+ {
22
+ :out :year ?y ;
23
+ :month ?m ;
24
+ :day ?day ;
25
+ :minute ?min ;
26
+ :second ?sec ;
27
+ :tz ?tz .
28
+ } .
29
+
package/eyeling.js CHANGED
@@ -95,9 +95,7 @@ const __logConclusionCache = new WeakMap(); // GraphTerm -> GraphTerm (deductive
95
95
  // Environment detection (Node vs Browser/Worker).
96
96
  // Eyeling is primarily synchronous, so we use sync XHR in browsers for log:content/log:semantics.
97
97
  // Note: Browser fetches are subject to CORS; use CORS-enabled resources or a proxy.
98
- const __IS_NODE =
99
- typeof process !== 'undefined' &&
100
- !!(process.versions && process.versions.node);
98
+ const __IS_NODE = typeof process !== 'undefined' && !!(process.versions && process.versions.node);
101
99
 
102
100
  function __hasXmlHttpRequest() {
103
101
  return typeof XMLHttpRequest !== 'undefined';
@@ -107,10 +105,7 @@ function __resolveBrowserUrl(ref) {
107
105
  if (!ref) return ref;
108
106
  // If already absolute, keep as-is.
109
107
  if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(ref)) return ref;
110
- const base =
111
- (typeof document !== 'undefined' && document.baseURI) ||
112
- (typeof location !== 'undefined' && location.href) ||
113
- '';
108
+ const base = (typeof document !== 'undefined' && document.baseURI) || (typeof location !== 'undefined' && location.href) || '';
114
109
  try {
115
110
  return new URL(ref, base).toString();
116
111
  } catch {
@@ -124,10 +119,7 @@ function __fetchHttpTextSyncBrowser(url) {
124
119
  const xhr = new XMLHttpRequest();
125
120
  xhr.open('GET', url, false); // synchronous
126
121
  try {
127
- xhr.setRequestHeader(
128
- 'Accept',
129
- 'text/n3, text/turtle, application/n-triples, application/n-quads, text/plain;q=0.1, */*;q=0.01'
130
- );
122
+ xhr.setRequestHeader('Accept', 'text/n3, text/turtle, application/n-triples, application/n-quads, text/plain;q=0.1, */*;q=0.01');
131
123
  } catch {
132
124
  // Some environments restrict setting headers (ignore).
133
125
  }
@@ -232,7 +224,7 @@ function __fetchHttpTextViaSubprocess(url) {
232
224
  `;
233
225
  const r = cp.spawnSync(process.execPath, ['-e', script, url], {
234
226
  encoding: 'utf8',
235
- maxBuffer: 32 * 1024 * 1024
227
+ maxBuffer: 32 * 1024 * 1024,
236
228
  });
237
229
  if (r.status !== 0) return null;
238
230
  return r.stdout;
@@ -297,8 +289,8 @@ function __derefSemanticsSync(iriNoFrag) {
297
289
  return null;
298
290
  }
299
291
  try {
300
- const baseIri = (typeof key === 'string' && key) ? key : iriNoFrag;
301
- const formula = __parseSemanticsToFormula(text, baseIri);
292
+ const baseIri = typeof key === 'string' && key ? key : iriNoFrag;
293
+ const formula = __parseSemanticsToFormula(text, baseIri);
302
294
  __logSemanticsCache.set(key, formula);
303
295
  return formula;
304
296
  } catch {
@@ -387,8 +379,6 @@ function __computeConclusionFromFormula(formula) {
387
379
  return out;
388
380
  }
389
381
 
390
-
391
-
392
382
  // Controls whether human-readable proof comments are printed.
393
383
  let proofCommentsEnabled = false;
394
384
  // Super restricted mode: disable *all* builtins except => / <= (log:implies / log:impliedBy)
@@ -3489,6 +3479,33 @@ function parseXsdDatetimeTerm(t) {
3489
3479
  return d; // Date in local/UTC, we only use timestamp
3490
3480
  }
3491
3481
 
3482
+ function parseXsdDateTimeLexParts(t) {
3483
+ // Parse *lexical* components of an xsd:dateTime literal without timezone normalization.
3484
+ // Returns { yearStr, month, day, minute, second, tz } or null.
3485
+ if (!(t instanceof Literal)) return null;
3486
+ const [lex, dt] = literalParts(t.value);
3487
+ if (dt !== XSD_NS + 'dateTime') return null;
3488
+ const val = stripQuotes(lex);
3489
+
3490
+ // xsd:dateTime lexical: YYYY-MM-DDThh:mm:ss(.s+)?(Z|(+|-)hh:mm)?
3491
+ const m = /^(-?\d{4,})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(Z|[+-]\d{2}:\d{2})?$/.exec(val);
3492
+ if (!m) return null;
3493
+
3494
+ const yearStr = m[1];
3495
+ const month = parseInt(m[2], 10);
3496
+ const day = parseInt(m[3], 10);
3497
+ const minute = parseInt(m[5], 10);
3498
+ const second = parseInt(m[6], 10);
3499
+ const tz = m[7] || null;
3500
+
3501
+ if (!(month >= 1 && month <= 12)) return null;
3502
+ if (!(day >= 1 && day <= 31)) return null;
3503
+ if (!(minute >= 0 && minute <= 59)) return null;
3504
+ if (!(second >= 0 && second <= 59)) return null;
3505
+
3506
+ return { yearStr, month, day, minute, second, tz };
3507
+ }
3508
+
3492
3509
  function parseDatetimeLike(t) {
3493
3510
  const d = parseXsdDateTerm(t);
3494
3511
  if (d !== null) return d;
@@ -4579,6 +4596,162 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4579
4596
  // 4.3 time: builtins
4580
4597
  // -----------------------------------------------------------------
4581
4598
 
4599
+ // time:day
4600
+ // Gets as object the integer day component of the subject xsd:dateTime.
4601
+ // Schema: $s+ time:day $o-
4602
+ if (pv === TIME_NS + 'day') {
4603
+ const parts = parseXsdDateTimeLexParts(g.s);
4604
+ if (!parts) return [];
4605
+ const out = internLiteral(String(parts.day));
4606
+
4607
+ if (g.o instanceof Var) {
4608
+ const s2 = { ...subst };
4609
+ s2[g.o.name] = out;
4610
+ return [s2];
4611
+ }
4612
+ if (g.o instanceof Blank) return [{ ...subst }];
4613
+
4614
+ const oi = parseIntLiteral(g.o);
4615
+ if (oi !== null) {
4616
+ try {
4617
+ if (oi === BigInt(parts.day)) return [{ ...subst }];
4618
+ } catch {}
4619
+ }
4620
+
4621
+ const s2 = unifyTerm(g.o, out, subst);
4622
+ return s2 !== null ? [s2] : [];
4623
+ }
4624
+
4625
+ // time:minute
4626
+ // Gets as object the integer minutes component of the subject xsd:dateTime.
4627
+ // Schema: $s+ time:minute $o-
4628
+ if (pv === TIME_NS + 'minute') {
4629
+ const parts = parseXsdDateTimeLexParts(g.s);
4630
+ if (!parts) return [];
4631
+ const out = internLiteral(String(parts.minute));
4632
+
4633
+ if (g.o instanceof Var) {
4634
+ const s2 = { ...subst };
4635
+ s2[g.o.name] = out;
4636
+ return [s2];
4637
+ }
4638
+ if (g.o instanceof Blank) return [{ ...subst }];
4639
+
4640
+ const oi = parseIntLiteral(g.o);
4641
+ if (oi !== null) {
4642
+ try {
4643
+ if (oi === BigInt(parts.minute)) return [{ ...subst }];
4644
+ } catch {}
4645
+ }
4646
+
4647
+ const s2 = unifyTerm(g.o, out, subst);
4648
+ return s2 !== null ? [s2] : [];
4649
+ }
4650
+
4651
+ // time:month
4652
+ // Gets as object the integer month component of the subject xsd:dateTime.
4653
+ // Schema: $s+ time:month $o-
4654
+ if (pv === TIME_NS + 'month') {
4655
+ const parts = parseXsdDateTimeLexParts(g.s);
4656
+ if (!parts) return [];
4657
+ const out = internLiteral(String(parts.month));
4658
+
4659
+ if (g.o instanceof Var) {
4660
+ const s2 = { ...subst };
4661
+ s2[g.o.name] = out;
4662
+ return [s2];
4663
+ }
4664
+ if (g.o instanceof Blank) return [{ ...subst }];
4665
+
4666
+ const oi = parseIntLiteral(g.o);
4667
+ if (oi !== null) {
4668
+ try {
4669
+ if (oi === BigInt(parts.month)) return [{ ...subst }];
4670
+ } catch {}
4671
+ }
4672
+
4673
+ const s2 = unifyTerm(g.o, out, subst);
4674
+ return s2 !== null ? [s2] : [];
4675
+ }
4676
+
4677
+ // time:second
4678
+ // Gets as object the integer seconds component of the subject xsd:dateTime.
4679
+ // Schema: $s+ time:second $o-
4680
+ if (pv === TIME_NS + 'second') {
4681
+ const parts = parseXsdDateTimeLexParts(g.s);
4682
+ if (!parts) return [];
4683
+ const out = internLiteral(String(parts.second));
4684
+
4685
+ if (g.o instanceof Var) {
4686
+ const s2 = { ...subst };
4687
+ s2[g.o.name] = out;
4688
+ return [s2];
4689
+ }
4690
+ if (g.o instanceof Blank) return [{ ...subst }];
4691
+
4692
+ const oi = parseIntLiteral(g.o);
4693
+ if (oi !== null) {
4694
+ try {
4695
+ if (oi === BigInt(parts.second)) return [{ ...subst }];
4696
+ } catch {}
4697
+ }
4698
+
4699
+ const s2 = unifyTerm(g.o, out, subst);
4700
+ return s2 !== null ? [s2] : [];
4701
+ }
4702
+
4703
+ // time:timeZone
4704
+ // Gets as object the trailing timezone offset of the subject xsd:dateTime (e.g., "-05:00" or "Z").
4705
+ // Schema: $s+ time:timeZone $o-
4706
+ if (pv === TIME_NS + 'timeZone') {
4707
+ const parts = parseXsdDateTimeLexParts(g.s);
4708
+ if (!parts) return [];
4709
+ if (parts.tz === null) return [];
4710
+ const out = internLiteral(`"${parts.tz}"`);
4711
+
4712
+ if (g.o instanceof Var) {
4713
+ const s2 = { ...subst };
4714
+ s2[g.o.name] = out;
4715
+ return [s2];
4716
+ }
4717
+ if (g.o instanceof Blank) return [{ ...subst }];
4718
+
4719
+ if (termsEqual(g.o, out)) return [{ ...subst }];
4720
+
4721
+ // Also accept explicitly typed xsd:string literals.
4722
+ if (g.o instanceof Literal) {
4723
+ const [lexO, dtO] = literalParts(g.o.value);
4724
+ if (dtO === XSD_NS + 'string' && stripQuotes(lexO) === parts.tz) return [{ ...subst }];
4725
+ }
4726
+ return [];
4727
+ }
4728
+
4729
+ // time:year
4730
+ // Gets as object the integer year component of the subject xsd:dateTime.
4731
+ // Schema: $s+ time:year $o-
4732
+ if (pv === TIME_NS + 'year') {
4733
+ const parts = parseXsdDateTimeLexParts(g.s);
4734
+ if (!parts) return [];
4735
+ const out = internLiteral(String(parts.yearStr));
4736
+
4737
+ if (g.o instanceof Var) {
4738
+ const s2 = { ...subst };
4739
+ s2[g.o.name] = out;
4740
+ return [s2];
4741
+ }
4742
+ if (g.o instanceof Blank) return [{ ...subst }];
4743
+
4744
+ const oi = parseIntLiteral(g.o);
4745
+ if (oi !== null) {
4746
+ try {
4747
+ if (oi === BigInt(parts.yearStr)) return [{ ...subst }];
4748
+ } catch {}
4749
+ }
4750
+
4751
+ const s2 = unifyTerm(g.o, out, subst);
4752
+ return s2 !== null ? [s2] : [];
4753
+ }
4754
+
4582
4755
  // time:localTime
4583
4756
  // "" time:localTime ?D. binds ?D to “now” as xsd:dateTime.
4584
4757
  if (pv === TIME_NS + 'localTime') {
@@ -5021,30 +5194,29 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
5021
5194
  return s2 !== null ? [s2] : [];
5022
5195
  }
5023
5196
 
5197
+ // log:conclusion
5198
+ // Schema: $s+ log:conclusion $o?
5199
+ // $o is the deductive closure of the subject formula $s (including rule inferences).
5200
+ if (pv === LOG_NS + 'conclusion') {
5201
+ // Accept 'true' as the empty formula.
5202
+ let inFormula = null;
5203
+ if (g.s instanceof GraphTerm) inFormula = g.s;
5204
+ else if (g.s instanceof Literal && g.s.value === 'true') inFormula = new GraphTerm([]);
5205
+ else return [];
5024
5206
 
5025
- // log:conclusion
5026
- // Schema: $s+ log:conclusion $o?
5027
- // $o is the deductive closure of the subject formula $s (including rule inferences).
5028
- if (pv === LOG_NS + 'conclusion') {
5029
- // Accept 'true' as the empty formula.
5030
- let inFormula = null;
5031
- if (g.s instanceof GraphTerm) inFormula = g.s;
5032
- else if (g.s instanceof Literal && g.s.value === 'true') inFormula = new GraphTerm([]);
5033
- else return [];
5207
+ const conclusion = __computeConclusionFromFormula(inFormula);
5208
+ if (!(conclusion instanceof GraphTerm)) return [];
5034
5209
 
5035
- const conclusion = __computeConclusionFromFormula(inFormula);
5036
- if (!(conclusion instanceof GraphTerm)) return [];
5210
+ if (g.o instanceof Var) {
5211
+ const s2 = { ...subst };
5212
+ s2[g.o.name] = conclusion;
5213
+ return [s2];
5214
+ }
5215
+ if (g.o instanceof Blank) return [{ ...subst }];
5037
5216
 
5038
- if (g.o instanceof Var) {
5039
- const s2 = { ...subst };
5040
- s2[g.o.name] = conclusion;
5041
- return [s2];
5217
+ const s2 = unifyTerm(g.o, conclusion, subst);
5218
+ return s2 !== null ? [s2] : [];
5042
5219
  }
5043
- if (g.o instanceof Blank) return [{ ...subst }];
5044
-
5045
- const s2 = unifyTerm(g.o, conclusion, subst);
5046
- return s2 !== null ? [s2] : [];
5047
- }
5048
5220
 
5049
5221
  // log:content
5050
5222
  // Schema: $s+ log:content $o?
@@ -5195,8 +5367,6 @@ if (pv === LOG_NS + 'conclusion') {
5195
5367
  return s2 !== null ? [s2] : [];
5196
5368
  }
5197
5369
 
5198
-
5199
-
5200
5370
  // log:dtlit
5201
5371
  // Schema: ( $s.1? $s.2? )? log:dtlit $o?
5202
5372
  // true iff $o is a datatyped literal with string value $s.1 and datatype IRI $s.2
@@ -5436,7 +5606,6 @@ if (pv === LOG_NS + 'conclusion') {
5436
5606
  return [{ ...subst }];
5437
5607
  }
5438
5608
 
5439
-
5440
5609
  // log:collectAllIn (scoped)
5441
5610
  if (pv === LOG_NS + 'collectAllIn') {
5442
5611
  if (!(g.s instanceof ListTerm) || g.s.elems.length !== 3) return [];
@@ -6575,7 +6744,6 @@ function __collectOutputStringsFromFacts(facts, prefixes) {
6575
6744
  return pairs.map((p) => p.text).join('');
6576
6745
  }
6577
6746
 
6578
-
6579
6747
  function main() {
6580
6748
  // Drop "node" and script name; keep only user-provided args
6581
6749
  const argv = process.argv.slice(2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.7.9",
3
+ "version": "1.7.10",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [