eyeling 1.30.4 → 1.30.6
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 +29 -25
- package/dist/browser/eyeling.browser.js +79 -5
- package/examples/input/{rdf-surfaces-all-values-from-reverse.ttl → rdf-surfaces-all-values-from-reverse.trig} +1 -0
- package/examples/input/{rdf-surfaces-all-values-from.ttl → rdf-surfaces-all-values-from.trig} +1 -0
- package/examples/input/{rdf-surfaces-ancestor.ttl → rdf-surfaces-ancestor.trig} +1 -0
- package/examples/input/{rdf-surfaces-city.ttl → rdf-surfaces-city.trig} +1 -0
- package/examples/input/{rdf-surfaces-disjunction-elimination.ttl → rdf-surfaces-disjunction-elimination.trig} +1 -0
- package/examples/input/{rdf-surfaces-disjunction-route-filter.ttl → rdf-surfaces-disjunction-route-filter.trig} +1 -0
- package/examples/input/{rdf-surfaces-domain.ttl → rdf-surfaces-domain.trig} +1 -0
- package/examples/input/{rdf-surfaces-explicit-disjunction.ttl → rdf-surfaces-explicit-disjunction.trig} +1 -0
- package/examples/input/{rdf-surfaces-multi-premise.ttl → rdf-surfaces-multi-premise.trig} +1 -0
- package/examples/input/{rdf-surfaces-owl-all-values-from-codex.ttl → rdf-surfaces-owl-all-values-from-codex.trig} +1 -0
- package/examples/input/{rdf-surfaces-property-chain.ttl → rdf-surfaces-property-chain.trig} +1 -0
- package/examples/input/{rdf-surfaces-range.ttl → rdf-surfaces-range.trig} +1 -0
- package/examples/input/rdf-surfaces-rdf12-graph-triple-term.trig +15 -0
- package/examples/input/rdf-surfaces-rdf12-named-graph.trig +14 -0
- package/examples/input/rdf-surfaces-rdf12-triple-term.trig +13 -0
- package/examples/input/{rdf-surfaces-rdfs-range-codex.ttl → rdf-surfaces-rdfs-range-codex.trig} +1 -0
- package/examples/input/{rdf-surfaces-rdfs-subclass-codex.ttl → rdf-surfaces-rdfs-subclass-codex.trig} +1 -0
- package/examples/input/{rdf-surfaces-strong-negation-access.ttl → rdf-surfaces-strong-negation-access.trig} +1 -0
- package/examples/output/rdf-surfaces-rdf12-graph-triple-term.n3 +3 -0
- package/examples/output/rdf-surfaces-rdf12-named-graph.n3 +3 -0
- package/examples/output/rdf-surfaces-rdf12-triple-term.n3 +3 -0
- package/examples/rdf-surfaces-rdf12-graph-triple-term.n3 +6 -0
- package/examples/rdf-surfaces-rdf12-named-graph.n3 +6 -0
- package/examples/rdf-surfaces-rdf12-triple-term.n3 +6 -0
- package/eyeling.js +79 -5
- package/lib/lexer.js +2 -2
- package/lib/rdf_surfaces.js +77 -3
- package/package.json +3 -5
- package/test/examples.test.js +1 -1
- package/test/playground.test.js +1 -1
- package/test/rdf_surfaces.test.js +16 -3
- package/test/run.js +61 -0
package/README.md
CHANGED
|
@@ -593,16 +593,17 @@ RDF 1.2 triple terms require explicit RDF compatibility mode. This protects ordi
|
|
|
593
593
|
|
|
594
594
|
### RDF Surfaces
|
|
595
595
|
|
|
596
|
-
RDF Surfaces are enabled with `--rdf-surfaces` on the CLI or `{ rdfSurfaces: true }` in the API. The option implies RDF compatibility mode. The syntax follows the BLOGIC text convention from Pat Hayes' ISWC 2009 slides: `%not[` and `%]` surface parentheses plus explicit blank-node binding graffiti at the beginning of a surface. Because
|
|
596
|
+
RDF Surfaces are enabled with `--rdf-surfaces` on the CLI or `{ rdfSurfaces: true }` in the API. The option implies RDF compatibility mode. The syntax follows the BLOGIC text convention from Pat Hayes' ISWC 2009 slides: `%not[` and `%]` surface parentheses plus explicit blank-node binding graffiti at the beginning of a surface. Because RDF Surfaces may now combine the surface extension with RDF 1.2 TriG features, the examples use `.trig` for RDF Surface input files and start with `VERSION "1.2-surfaces"`.
|
|
597
597
|
|
|
598
598
|
The examples keep RDF Surface input separate from Eyeling queries:
|
|
599
599
|
|
|
600
|
-
- `examples/input/<name>.
|
|
600
|
+
- `examples/input/<name>.trig` contains RDF 1.2 TriG input, RDF Surface rules, and the `VERSION "1.2-surfaces"` header.
|
|
601
601
|
- `examples/<name>.n3` contains only the corresponding `log:query`.
|
|
602
602
|
|
|
603
603
|
Use separate non-indented lines for triples and surface closes. Put only newly bound blank marks on the surface-opening line; marks already bound by an outer surface are reused in inner triples and are not repeated after `%not[`.
|
|
604
604
|
|
|
605
|
-
```
|
|
605
|
+
```trig
|
|
606
|
+
VERSION "1.2-surfaces"
|
|
606
607
|
@prefix ex: <http://example.org/> .
|
|
607
608
|
|
|
608
609
|
ex:Brussels a ex:City .
|
|
@@ -625,7 +626,7 @@ The slide-32 shape above is normalized as:
|
|
|
625
626
|
|
|
626
627
|
The first slide-33 abbreviation, range, is written as:
|
|
627
628
|
|
|
628
|
-
```
|
|
629
|
+
```trig
|
|
629
630
|
%not[ _:x _:y
|
|
630
631
|
_:x ex:parent _:y .
|
|
631
632
|
%not[
|
|
@@ -644,7 +645,7 @@ and behaves like:
|
|
|
644
645
|
|
|
645
646
|
Eyeling also recognizes codex-style surfaces that introduce rules from RDF/OWL vocabulary facts. For example, this `rdfs:range` codex:
|
|
646
647
|
|
|
647
|
-
```
|
|
648
|
+
```trig
|
|
648
649
|
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
649
650
|
|
|
650
651
|
%not[ _:p _:c
|
|
@@ -673,7 +674,7 @@ is normalized to the Horn rule shape:
|
|
|
673
674
|
|
|
674
675
|
The slide-33 `owl:allValuesFrom` codex is supported in both directions:
|
|
675
676
|
|
|
676
|
-
```
|
|
677
|
+
```trig
|
|
677
678
|
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
|
678
679
|
|
|
679
680
|
%not[ _:a _:b _:c
|
|
@@ -706,7 +707,7 @@ The forward part derives filler types. The reverse part is compiled into a data-
|
|
|
706
707
|
|
|
707
708
|
A top-level negative surface without a nested negative child is treated as an inference fuse:
|
|
708
709
|
|
|
709
|
-
```
|
|
710
|
+
```trig
|
|
710
711
|
%not[ _:x
|
|
711
712
|
_:x a ex:Impossible .
|
|
712
713
|
%]
|
|
@@ -723,24 +724,27 @@ The implementation is intentionally conservative: it supports the practical Horn
|
|
|
723
724
|
Run the included examples:
|
|
724
725
|
|
|
725
726
|
```bash
|
|
726
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-city.
|
|
727
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-range.
|
|
728
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-domain.
|
|
729
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-property-chain.
|
|
730
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-ancestor.
|
|
731
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-multi-premise.
|
|
732
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-all-values-from.
|
|
733
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-all-values-from-reverse.
|
|
734
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-rdfs-range-codex.
|
|
735
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-rdfs-subclass-codex.
|
|
736
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-
|
|
737
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-
|
|
738
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-
|
|
739
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-
|
|
740
|
-
eyeling --rdf-surfaces examples/input/rdf-surfaces-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
727
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-city.trig examples/rdf-surfaces-city.n3
|
|
728
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-range.trig examples/rdf-surfaces-range.n3
|
|
729
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-domain.trig examples/rdf-surfaces-domain.n3
|
|
730
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-property-chain.trig examples/rdf-surfaces-property-chain.n3
|
|
731
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-ancestor.trig examples/rdf-surfaces-ancestor.n3
|
|
732
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-multi-premise.trig examples/rdf-surfaces-multi-premise.n3
|
|
733
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-all-values-from.trig examples/rdf-surfaces-all-values-from.n3
|
|
734
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-all-values-from-reverse.trig examples/rdf-surfaces-all-values-from-reverse.n3
|
|
735
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-rdfs-range-codex.trig examples/rdf-surfaces-rdfs-range-codex.n3
|
|
736
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-rdfs-subclass-codex.trig examples/rdf-surfaces-rdfs-subclass-codex.n3
|
|
737
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-rdf12-named-graph.trig examples/rdf-surfaces-rdf12-named-graph.n3
|
|
738
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-rdf12-triple-term.trig examples/rdf-surfaces-rdf12-triple-term.n3
|
|
739
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-rdf12-graph-triple-term.trig examples/rdf-surfaces-rdf12-graph-triple-term.n3
|
|
740
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-owl-all-values-from-codex.trig examples/rdf-surfaces-owl-all-values-from-codex.n3
|
|
741
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-strong-negation-access.trig examples/rdf-surfaces-strong-negation-access.n3
|
|
742
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-disjunction-route-filter.trig examples/rdf-surfaces-disjunction-route-filter.n3
|
|
743
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-explicit-disjunction.trig examples/rdf-surfaces-explicit-disjunction.n3
|
|
744
|
+
eyeling --rdf-surfaces examples/input/rdf-surfaces-disjunction-elimination.trig examples/rdf-surfaces-disjunction-elimination.n3
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
The additional examples show ordinary Horn-style RDF Surface patterns beyond the exact slide-33 abbreviations: subject typing (`rdf-surfaces-domain`), a two-hop property chain (`rdf-surfaces-property-chain`), recursive transitive closure (`rdf-surfaces-ancestor`), a conjunctive classification rule (`rdf-surfaces-multi-premise`), codex-style RDFS/OWL rule generation (`rdf-surfaces-rdfs-range-codex`, `rdf-surfaces-rdfs-subclass-codex`, `rdf-surfaces-owl-all-values-from-codex`), and RDF 1.2 inputs with named graphs and triple terms (`rdf-surfaces-rdf12-named-graph`, `rdf-surfaces-rdf12-triple-term`, `rdf-surfaces-rdf12-graph-triple-term`). More challenging examples keep the engine unchanged and add N3 helper rules on top: `rdf-surfaces-strong-negation-access` uses a top-level negative surface as a strong-negation fuse for an access policy, `rdf-surfaces-disjunction-route-filter` represents a disjunction as explicit candidate routes and filters one with a strong-negation policy, `rdf-surfaces-explicit-disjunction` puts the disjunction directly in the RDF Surface file with one outer negative surface and two inner alternatives, and `rdf-surfaces-disjunction-elimination` uses `log:forAllIn` to derive a conclusion only when every option in a disjunction implies it.
|
|
744
748
|
|
|
745
749
|
---
|
|
746
750
|
|
|
@@ -12852,7 +12852,7 @@ function normalizeRdfCompatibility(inputText) {
|
|
|
12852
12852
|
// unless they actually contain RDF 1.2 triple terms, VERSION directives, or a
|
|
12853
12853
|
// plausible top-level TriG named graph block.
|
|
12854
12854
|
const hasTripleTerms = text.includes('<<');
|
|
12855
|
-
const hasVersionDirective = /^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic)\1\s*\.?\s*(?:#.*)?$/im.test(text);
|
|
12855
|
+
const hasVersionDirective = /^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic|1\.2-surfaces)\1\s*\.?\s*(?:#.*)?$/im.test(text);
|
|
12856
12856
|
const hasMessageVersionDirective = /^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic)-messages\1\s*\.?\s*(?:#.*)?$/im.test(text);
|
|
12857
12857
|
const hasNamedGraphCandidate = /(?:^|[.\r\n])\s*(?:GRAPH\s+)?(?:<[^>\r\n]*>|_:[A-Za-z][A-Za-z0-9_-]*|[A-Za-z][A-Za-z0-9_-]*:[^\s{};,.()[\]]*|:[^\s{};,.()[\]]+)\s*\{/m.test(text);
|
|
12858
12858
|
const hasAnnotationSyntax = /(?:^|\s)~|\{\|/.test(text);
|
|
@@ -13321,7 +13321,7 @@ function normalizeRdfCompatibility(inputText) {
|
|
|
13321
13321
|
}
|
|
13322
13322
|
|
|
13323
13323
|
function stripVersionDirectives(s) {
|
|
13324
|
-
return s.replace(/^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic)
|
|
13324
|
+
return s.replace(/^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic|1\.2-surfaces|(?:1\.1|1\.2|1\.2-basic)-messages)\1\s*\.?\s*(?:#.*)?$/gim, '');
|
|
13325
13325
|
}
|
|
13326
13326
|
|
|
13327
13327
|
function skipWsAndComments(s, at) {
|
|
@@ -16988,6 +16988,24 @@ function extractLeadingBinders(raw) {
|
|
|
16988
16988
|
const contentStart = skipWsAndComments(text, 0);
|
|
16989
16989
|
if (contentStart >= text.length) return { binders: [], text };
|
|
16990
16990
|
|
|
16991
|
+
// Preferred BLOGIC graffiti style: put newly bound marks on the `%not[`
|
|
16992
|
+
// line and put triples on following non-indented lines, e.g.
|
|
16993
|
+
// `%not[ _:x _:y\n_:x :p _:y .`. Reading that first line directly
|
|
16994
|
+
// avoids guessing from the first triple shape, which matters for RDF 1.2
|
|
16995
|
+
// formula objects and TriG named graph blocks.
|
|
16996
|
+
let lineEnd = text.indexOf('\n', contentStart);
|
|
16997
|
+
if (lineEnd < 0) lineEnd = text.length;
|
|
16998
|
+
let lineText = text.slice(contentStart, lineEnd);
|
|
16999
|
+
let newlineEnd = lineEnd < text.length ? lineEnd + 1 : lineEnd;
|
|
17000
|
+
if (lineText.endsWith('\r')) {
|
|
17001
|
+
lineText = lineText.slice(0, -1);
|
|
17002
|
+
}
|
|
17003
|
+
const lineTrim = lineText.trim();
|
|
17004
|
+
if (/^_:[A-Za-z_][A-Za-z0-9._-]*(?:\s+_:[A-Za-z_][A-Za-z0-9._-]*)*$/.test(lineTrim)) {
|
|
17005
|
+
const binders = lineTrim.split(/\s+/).map((tok) => tok.slice(2));
|
|
17006
|
+
return { binders, text: text.slice(0, contentStart) + text.slice(newlineEnd) };
|
|
17007
|
+
}
|
|
17008
|
+
|
|
16991
17009
|
const segment = readStatementSegment(text.slice(contentStart));
|
|
16992
17010
|
const toks = tokenizeLeadingSegment(segment);
|
|
16993
17011
|
let leadingBlankCount = 0;
|
|
@@ -17015,6 +17033,57 @@ function extractLeadingBinders(raw) {
|
|
|
17015
17033
|
return { binders, text: text.slice(0, contentStart) + text.slice(contentStart + cut) };
|
|
17016
17034
|
}
|
|
17017
17035
|
|
|
17036
|
+
|
|
17037
|
+
function readBalancedCurlyAt(s, at) {
|
|
17038
|
+
if (s[at] !== '{') return null;
|
|
17039
|
+
let i = at;
|
|
17040
|
+
let depth = 0;
|
|
17041
|
+
while (i < s.length) {
|
|
17042
|
+
const ch = s[i];
|
|
17043
|
+
if (ch === '"' || ch === "'") {
|
|
17044
|
+
i = readStringAt(s, i).end;
|
|
17045
|
+
continue;
|
|
17046
|
+
}
|
|
17047
|
+
if (ch === '<') {
|
|
17048
|
+
i = readIriAt(s, i).end;
|
|
17049
|
+
continue;
|
|
17050
|
+
}
|
|
17051
|
+
if (ch === '#') {
|
|
17052
|
+
while (i < s.length && s[i] !== '\n' && s[i] !== '\r') i += 1;
|
|
17053
|
+
continue;
|
|
17054
|
+
}
|
|
17055
|
+
if (ch === '{') depth += 1;
|
|
17056
|
+
else if (ch === '}') {
|
|
17057
|
+
depth -= 1;
|
|
17058
|
+
if (depth === 0) return { text: s.slice(at, i + 1), end: i + 1 };
|
|
17059
|
+
}
|
|
17060
|
+
i += 1;
|
|
17061
|
+
}
|
|
17062
|
+
throw syntaxError('Unterminated named graph block inside RDF Surface', at);
|
|
17063
|
+
}
|
|
17064
|
+
|
|
17065
|
+
function normalizeSurfaceStatement(statement) {
|
|
17066
|
+
const raw = String(statement || '').trim();
|
|
17067
|
+
if (!raw) return raw;
|
|
17068
|
+
|
|
17069
|
+
let i = 0;
|
|
17070
|
+
const first = readBareTokenAt(raw, i);
|
|
17071
|
+
if (first && /^GRAPH$/i.test(first.text)) {
|
|
17072
|
+
i = first.end;
|
|
17073
|
+
}
|
|
17074
|
+
|
|
17075
|
+
const term = readBareTokenAt(raw, i);
|
|
17076
|
+
if (!term) return raw;
|
|
17077
|
+
const afterTerm = skipWsAndComments(raw, term.end);
|
|
17078
|
+
if (raw[afterTerm] !== '{') return raw;
|
|
17079
|
+
|
|
17080
|
+
const block = readBalancedCurlyAt(raw, afterTerm);
|
|
17081
|
+
const afterBlock = skipWsAndComments(raw, block.end);
|
|
17082
|
+
if (afterBlock !== raw.length) return raw;
|
|
17083
|
+
|
|
17084
|
+
return `${term.text} ${LOG_NAME_OF_IRI} ${block.text}`;
|
|
17085
|
+
}
|
|
17086
|
+
|
|
17018
17087
|
function splitTopLevelStatements(raw, surfaceOffset = null) {
|
|
17019
17088
|
const text = String(raw || '');
|
|
17020
17089
|
const out = [];
|
|
@@ -17046,7 +17115,7 @@ function splitTopLevelStatements(raw, surfaceOffset = null) {
|
|
|
17046
17115
|
else if (ch === ')' && depthParen > 0) depthParen -= 1;
|
|
17047
17116
|
else if (ch === '.' && depthBrace === 0 && depthBracket === 0 && depthParen === 0) {
|
|
17048
17117
|
const stmt = text.slice(start, i).trim();
|
|
17049
|
-
if (stmt) out.push(stmt);
|
|
17118
|
+
if (stmt) out.push(normalizeSurfaceStatement(stmt));
|
|
17050
17119
|
start = i + 1;
|
|
17051
17120
|
}
|
|
17052
17121
|
i += 1;
|
|
@@ -17054,9 +17123,13 @@ function splitTopLevelStatements(raw, surfaceOffset = null) {
|
|
|
17054
17123
|
|
|
17055
17124
|
const tail = text.slice(start).trim();
|
|
17056
17125
|
if (tail) {
|
|
17057
|
-
// A raw binder-only segment is OK;
|
|
17126
|
+
// A raw binder-only segment is OK; RDF 1.2 TriG named graph blocks are
|
|
17127
|
+
// also OK without a trailing dot. Any other dangling text is most likely a
|
|
17058
17128
|
// missing dot in the surface body.
|
|
17059
|
-
|
|
17129
|
+
const normalizedTail = normalizeSurfaceStatement(tail);
|
|
17130
|
+
if (normalizedTail !== tail) {
|
|
17131
|
+
out.push(normalizedTail);
|
|
17132
|
+
} else if (!/^_:[A-Za-z_][A-Za-z0-9._-]*(?:\s+_:[A-Za-z_][A-Za-z0-9._-]*)*$/.test(tail)) {
|
|
17060
17133
|
throw syntaxError('RDF Surface statement is missing a terminating dot', surfaceOffset);
|
|
17061
17134
|
}
|
|
17062
17135
|
}
|
|
@@ -17126,6 +17199,7 @@ function readSurfaceAt(s, at) {
|
|
|
17126
17199
|
}
|
|
17127
17200
|
|
|
17128
17201
|
const LOG_FOR_ALL_IN_IRI = '<http://www.w3.org/2000/10/swap/log#forAllIn>';
|
|
17202
|
+
const LOG_NAME_OF_IRI = '<http://www.w3.org/2000/10/swap/log#nameOf>';
|
|
17129
17203
|
|
|
17130
17204
|
function rewriteBlankMarksWithMap(statement, labelToVarName) {
|
|
17131
17205
|
const map = labelToVarName instanceof Map ? labelToVarName : new Map();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
VERSION "1.2-surfaces"
|
|
2
|
+
# eyeling-options: --rdf-surfaces
|
|
3
|
+
@prefix ex: <http://example.org/> .
|
|
4
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
5
|
+
|
|
6
|
+
ex:auditGraph {
|
|
7
|
+
ex:obs1 rdf:reifies <<( ex:sensor17 ex:reports ex:Overheating )>> .
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
%not[ _:obs
|
|
11
|
+
ex:auditGraph { _:obs rdf:reifies <<( ex:sensor17 ex:reports ex:Overheating )>> . }
|
|
12
|
+
%not[
|
|
13
|
+
_:obs a ex:AuditedObservation .
|
|
14
|
+
%]
|
|
15
|
+
%]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
VERSION "1.2-surfaces"
|
|
2
|
+
# eyeling-options: --rdf-surfaces
|
|
3
|
+
@prefix ex: <http://example.org/> .
|
|
4
|
+
|
|
5
|
+
ex:regionalReport {
|
|
6
|
+
ex:Brussels a ex:City .
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
%not[ _:x
|
|
10
|
+
ex:regionalReport { _:x a ex:City . }
|
|
11
|
+
%not[
|
|
12
|
+
_:x a ex:ReportedCity .
|
|
13
|
+
%]
|
|
14
|
+
%]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
VERSION "1.2-surfaces"
|
|
2
|
+
# eyeling-options: --rdf-surfaces
|
|
3
|
+
@prefix ex: <http://example.org/> .
|
|
4
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
5
|
+
|
|
6
|
+
ex:claim1 rdf:reifies <<( ex:Brussels rdf:type ex:City )>> .
|
|
7
|
+
|
|
8
|
+
%not[ _:claim
|
|
9
|
+
_:claim rdf:reifies <<( ex:Brussels rdf:type ex:City )>> .
|
|
10
|
+
%not[
|
|
11
|
+
_:claim a ex:CityClaim .
|
|
12
|
+
%]
|
|
13
|
+
%]
|
package/eyeling.js
CHANGED
|
@@ -12852,7 +12852,7 @@ function normalizeRdfCompatibility(inputText) {
|
|
|
12852
12852
|
// unless they actually contain RDF 1.2 triple terms, VERSION directives, or a
|
|
12853
12853
|
// plausible top-level TriG named graph block.
|
|
12854
12854
|
const hasTripleTerms = text.includes('<<');
|
|
12855
|
-
const hasVersionDirective = /^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic)\1\s*\.?\s*(?:#.*)?$/im.test(text);
|
|
12855
|
+
const hasVersionDirective = /^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic|1\.2-surfaces)\1\s*\.?\s*(?:#.*)?$/im.test(text);
|
|
12856
12856
|
const hasMessageVersionDirective = /^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic)-messages\1\s*\.?\s*(?:#.*)?$/im.test(text);
|
|
12857
12857
|
const hasNamedGraphCandidate = /(?:^|[.\r\n])\s*(?:GRAPH\s+)?(?:<[^>\r\n]*>|_:[A-Za-z][A-Za-z0-9_-]*|[A-Za-z][A-Za-z0-9_-]*:[^\s{};,.()[\]]*|:[^\s{};,.()[\]]+)\s*\{/m.test(text);
|
|
12858
12858
|
const hasAnnotationSyntax = /(?:^|\s)~|\{\|/.test(text);
|
|
@@ -13321,7 +13321,7 @@ function normalizeRdfCompatibility(inputText) {
|
|
|
13321
13321
|
}
|
|
13322
13322
|
|
|
13323
13323
|
function stripVersionDirectives(s) {
|
|
13324
|
-
return s.replace(/^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic)
|
|
13324
|
+
return s.replace(/^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic|1\.2-surfaces|(?:1\.1|1\.2|1\.2-basic)-messages)\1\s*\.?\s*(?:#.*)?$/gim, '');
|
|
13325
13325
|
}
|
|
13326
13326
|
|
|
13327
13327
|
function skipWsAndComments(s, at) {
|
|
@@ -16988,6 +16988,24 @@ function extractLeadingBinders(raw) {
|
|
|
16988
16988
|
const contentStart = skipWsAndComments(text, 0);
|
|
16989
16989
|
if (contentStart >= text.length) return { binders: [], text };
|
|
16990
16990
|
|
|
16991
|
+
// Preferred BLOGIC graffiti style: put newly bound marks on the `%not[`
|
|
16992
|
+
// line and put triples on following non-indented lines, e.g.
|
|
16993
|
+
// `%not[ _:x _:y\n_:x :p _:y .`. Reading that first line directly
|
|
16994
|
+
// avoids guessing from the first triple shape, which matters for RDF 1.2
|
|
16995
|
+
// formula objects and TriG named graph blocks.
|
|
16996
|
+
let lineEnd = text.indexOf('\n', contentStart);
|
|
16997
|
+
if (lineEnd < 0) lineEnd = text.length;
|
|
16998
|
+
let lineText = text.slice(contentStart, lineEnd);
|
|
16999
|
+
let newlineEnd = lineEnd < text.length ? lineEnd + 1 : lineEnd;
|
|
17000
|
+
if (lineText.endsWith('\r')) {
|
|
17001
|
+
lineText = lineText.slice(0, -1);
|
|
17002
|
+
}
|
|
17003
|
+
const lineTrim = lineText.trim();
|
|
17004
|
+
if (/^_:[A-Za-z_][A-Za-z0-9._-]*(?:\s+_:[A-Za-z_][A-Za-z0-9._-]*)*$/.test(lineTrim)) {
|
|
17005
|
+
const binders = lineTrim.split(/\s+/).map((tok) => tok.slice(2));
|
|
17006
|
+
return { binders, text: text.slice(0, contentStart) + text.slice(newlineEnd) };
|
|
17007
|
+
}
|
|
17008
|
+
|
|
16991
17009
|
const segment = readStatementSegment(text.slice(contentStart));
|
|
16992
17010
|
const toks = tokenizeLeadingSegment(segment);
|
|
16993
17011
|
let leadingBlankCount = 0;
|
|
@@ -17015,6 +17033,57 @@ function extractLeadingBinders(raw) {
|
|
|
17015
17033
|
return { binders, text: text.slice(0, contentStart) + text.slice(contentStart + cut) };
|
|
17016
17034
|
}
|
|
17017
17035
|
|
|
17036
|
+
|
|
17037
|
+
function readBalancedCurlyAt(s, at) {
|
|
17038
|
+
if (s[at] !== '{') return null;
|
|
17039
|
+
let i = at;
|
|
17040
|
+
let depth = 0;
|
|
17041
|
+
while (i < s.length) {
|
|
17042
|
+
const ch = s[i];
|
|
17043
|
+
if (ch === '"' || ch === "'") {
|
|
17044
|
+
i = readStringAt(s, i).end;
|
|
17045
|
+
continue;
|
|
17046
|
+
}
|
|
17047
|
+
if (ch === '<') {
|
|
17048
|
+
i = readIriAt(s, i).end;
|
|
17049
|
+
continue;
|
|
17050
|
+
}
|
|
17051
|
+
if (ch === '#') {
|
|
17052
|
+
while (i < s.length && s[i] !== '\n' && s[i] !== '\r') i += 1;
|
|
17053
|
+
continue;
|
|
17054
|
+
}
|
|
17055
|
+
if (ch === '{') depth += 1;
|
|
17056
|
+
else if (ch === '}') {
|
|
17057
|
+
depth -= 1;
|
|
17058
|
+
if (depth === 0) return { text: s.slice(at, i + 1), end: i + 1 };
|
|
17059
|
+
}
|
|
17060
|
+
i += 1;
|
|
17061
|
+
}
|
|
17062
|
+
throw syntaxError('Unterminated named graph block inside RDF Surface', at);
|
|
17063
|
+
}
|
|
17064
|
+
|
|
17065
|
+
function normalizeSurfaceStatement(statement) {
|
|
17066
|
+
const raw = String(statement || '').trim();
|
|
17067
|
+
if (!raw) return raw;
|
|
17068
|
+
|
|
17069
|
+
let i = 0;
|
|
17070
|
+
const first = readBareTokenAt(raw, i);
|
|
17071
|
+
if (first && /^GRAPH$/i.test(first.text)) {
|
|
17072
|
+
i = first.end;
|
|
17073
|
+
}
|
|
17074
|
+
|
|
17075
|
+
const term = readBareTokenAt(raw, i);
|
|
17076
|
+
if (!term) return raw;
|
|
17077
|
+
const afterTerm = skipWsAndComments(raw, term.end);
|
|
17078
|
+
if (raw[afterTerm] !== '{') return raw;
|
|
17079
|
+
|
|
17080
|
+
const block = readBalancedCurlyAt(raw, afterTerm);
|
|
17081
|
+
const afterBlock = skipWsAndComments(raw, block.end);
|
|
17082
|
+
if (afterBlock !== raw.length) return raw;
|
|
17083
|
+
|
|
17084
|
+
return `${term.text} ${LOG_NAME_OF_IRI} ${block.text}`;
|
|
17085
|
+
}
|
|
17086
|
+
|
|
17018
17087
|
function splitTopLevelStatements(raw, surfaceOffset = null) {
|
|
17019
17088
|
const text = String(raw || '');
|
|
17020
17089
|
const out = [];
|
|
@@ -17046,7 +17115,7 @@ function splitTopLevelStatements(raw, surfaceOffset = null) {
|
|
|
17046
17115
|
else if (ch === ')' && depthParen > 0) depthParen -= 1;
|
|
17047
17116
|
else if (ch === '.' && depthBrace === 0 && depthBracket === 0 && depthParen === 0) {
|
|
17048
17117
|
const stmt = text.slice(start, i).trim();
|
|
17049
|
-
if (stmt) out.push(stmt);
|
|
17118
|
+
if (stmt) out.push(normalizeSurfaceStatement(stmt));
|
|
17050
17119
|
start = i + 1;
|
|
17051
17120
|
}
|
|
17052
17121
|
i += 1;
|
|
@@ -17054,9 +17123,13 @@ function splitTopLevelStatements(raw, surfaceOffset = null) {
|
|
|
17054
17123
|
|
|
17055
17124
|
const tail = text.slice(start).trim();
|
|
17056
17125
|
if (tail) {
|
|
17057
|
-
// A raw binder-only segment is OK;
|
|
17126
|
+
// A raw binder-only segment is OK; RDF 1.2 TriG named graph blocks are
|
|
17127
|
+
// also OK without a trailing dot. Any other dangling text is most likely a
|
|
17058
17128
|
// missing dot in the surface body.
|
|
17059
|
-
|
|
17129
|
+
const normalizedTail = normalizeSurfaceStatement(tail);
|
|
17130
|
+
if (normalizedTail !== tail) {
|
|
17131
|
+
out.push(normalizedTail);
|
|
17132
|
+
} else if (!/^_:[A-Za-z_][A-Za-z0-9._-]*(?:\s+_:[A-Za-z_][A-Za-z0-9._-]*)*$/.test(tail)) {
|
|
17060
17133
|
throw syntaxError('RDF Surface statement is missing a terminating dot', surfaceOffset);
|
|
17061
17134
|
}
|
|
17062
17135
|
}
|
|
@@ -17126,6 +17199,7 @@ function readSurfaceAt(s, at) {
|
|
|
17126
17199
|
}
|
|
17127
17200
|
|
|
17128
17201
|
const LOG_FOR_ALL_IN_IRI = '<http://www.w3.org/2000/10/swap/log#forAllIn>';
|
|
17202
|
+
const LOG_NAME_OF_IRI = '<http://www.w3.org/2000/10/swap/log#nameOf>';
|
|
17129
17203
|
|
|
17130
17204
|
function rewriteBlankMarksWithMap(statement, labelToVarName) {
|
|
17131
17205
|
const map = labelToVarName instanceof Map ? labelToVarName : new Map();
|
package/lib/lexer.js
CHANGED
|
@@ -402,7 +402,7 @@ function normalizeRdfCompatibility(inputText) {
|
|
|
402
402
|
// unless they actually contain RDF 1.2 triple terms, VERSION directives, or a
|
|
403
403
|
// plausible top-level TriG named graph block.
|
|
404
404
|
const hasTripleTerms = text.includes('<<');
|
|
405
|
-
const hasVersionDirective = /^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic)\1\s*\.?\s*(?:#.*)?$/im.test(text);
|
|
405
|
+
const hasVersionDirective = /^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic|1\.2-surfaces)\1\s*\.?\s*(?:#.*)?$/im.test(text);
|
|
406
406
|
const hasMessageVersionDirective = /^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic)-messages\1\s*\.?\s*(?:#.*)?$/im.test(text);
|
|
407
407
|
const hasNamedGraphCandidate = /(?:^|[.\r\n])\s*(?:GRAPH\s+)?(?:<[^>\r\n]*>|_:[A-Za-z][A-Za-z0-9_-]*|[A-Za-z][A-Za-z0-9_-]*:[^\s{};,.()[\]]*|:[^\s{};,.()[\]]+)\s*\{/m.test(text);
|
|
408
408
|
const hasAnnotationSyntax = /(?:^|\s)~|\{\|/.test(text);
|
|
@@ -871,7 +871,7 @@ function normalizeRdfCompatibility(inputText) {
|
|
|
871
871
|
}
|
|
872
872
|
|
|
873
873
|
function stripVersionDirectives(s) {
|
|
874
|
-
return s.replace(/^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic)
|
|
874
|
+
return s.replace(/^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic|1\.2-surfaces|(?:1\.1|1\.2|1\.2-basic)-messages)\1\s*\.?\s*(?:#.*)?$/gim, '');
|
|
875
875
|
}
|
|
876
876
|
|
|
877
877
|
function skipWsAndComments(s, at) {
|
package/lib/rdf_surfaces.js
CHANGED
|
@@ -158,6 +158,24 @@ function extractLeadingBinders(raw) {
|
|
|
158
158
|
const contentStart = skipWsAndComments(text, 0);
|
|
159
159
|
if (contentStart >= text.length) return { binders: [], text };
|
|
160
160
|
|
|
161
|
+
// Preferred BLOGIC graffiti style: put newly bound marks on the `%not[`
|
|
162
|
+
// line and put triples on following non-indented lines, e.g.
|
|
163
|
+
// `%not[ _:x _:y\n_:x :p _:y .`. Reading that first line directly
|
|
164
|
+
// avoids guessing from the first triple shape, which matters for RDF 1.2
|
|
165
|
+
// formula objects and TriG named graph blocks.
|
|
166
|
+
let lineEnd = text.indexOf('\n', contentStart);
|
|
167
|
+
if (lineEnd < 0) lineEnd = text.length;
|
|
168
|
+
let lineText = text.slice(contentStart, lineEnd);
|
|
169
|
+
let newlineEnd = lineEnd < text.length ? lineEnd + 1 : lineEnd;
|
|
170
|
+
if (lineText.endsWith('\r')) {
|
|
171
|
+
lineText = lineText.slice(0, -1);
|
|
172
|
+
}
|
|
173
|
+
const lineTrim = lineText.trim();
|
|
174
|
+
if (/^_:[A-Za-z_][A-Za-z0-9._-]*(?:\s+_:[A-Za-z_][A-Za-z0-9._-]*)*$/.test(lineTrim)) {
|
|
175
|
+
const binders = lineTrim.split(/\s+/).map((tok) => tok.slice(2));
|
|
176
|
+
return { binders, text: text.slice(0, contentStart) + text.slice(newlineEnd) };
|
|
177
|
+
}
|
|
178
|
+
|
|
161
179
|
const segment = readStatementSegment(text.slice(contentStart));
|
|
162
180
|
const toks = tokenizeLeadingSegment(segment);
|
|
163
181
|
let leadingBlankCount = 0;
|
|
@@ -185,6 +203,57 @@ function extractLeadingBinders(raw) {
|
|
|
185
203
|
return { binders, text: text.slice(0, contentStart) + text.slice(contentStart + cut) };
|
|
186
204
|
}
|
|
187
205
|
|
|
206
|
+
|
|
207
|
+
function readBalancedCurlyAt(s, at) {
|
|
208
|
+
if (s[at] !== '{') return null;
|
|
209
|
+
let i = at;
|
|
210
|
+
let depth = 0;
|
|
211
|
+
while (i < s.length) {
|
|
212
|
+
const ch = s[i];
|
|
213
|
+
if (ch === '"' || ch === "'") {
|
|
214
|
+
i = readStringAt(s, i).end;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (ch === '<') {
|
|
218
|
+
i = readIriAt(s, i).end;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (ch === '#') {
|
|
222
|
+
while (i < s.length && s[i] !== '\n' && s[i] !== '\r') i += 1;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (ch === '{') depth += 1;
|
|
226
|
+
else if (ch === '}') {
|
|
227
|
+
depth -= 1;
|
|
228
|
+
if (depth === 0) return { text: s.slice(at, i + 1), end: i + 1 };
|
|
229
|
+
}
|
|
230
|
+
i += 1;
|
|
231
|
+
}
|
|
232
|
+
throw syntaxError('Unterminated named graph block inside RDF Surface', at);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function normalizeSurfaceStatement(statement) {
|
|
236
|
+
const raw = String(statement || '').trim();
|
|
237
|
+
if (!raw) return raw;
|
|
238
|
+
|
|
239
|
+
let i = 0;
|
|
240
|
+
const first = readBareTokenAt(raw, i);
|
|
241
|
+
if (first && /^GRAPH$/i.test(first.text)) {
|
|
242
|
+
i = first.end;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const term = readBareTokenAt(raw, i);
|
|
246
|
+
if (!term) return raw;
|
|
247
|
+
const afterTerm = skipWsAndComments(raw, term.end);
|
|
248
|
+
if (raw[afterTerm] !== '{') return raw;
|
|
249
|
+
|
|
250
|
+
const block = readBalancedCurlyAt(raw, afterTerm);
|
|
251
|
+
const afterBlock = skipWsAndComments(raw, block.end);
|
|
252
|
+
if (afterBlock !== raw.length) return raw;
|
|
253
|
+
|
|
254
|
+
return `${term.text} ${LOG_NAME_OF_IRI} ${block.text}`;
|
|
255
|
+
}
|
|
256
|
+
|
|
188
257
|
function splitTopLevelStatements(raw, surfaceOffset = null) {
|
|
189
258
|
const text = String(raw || '');
|
|
190
259
|
const out = [];
|
|
@@ -216,7 +285,7 @@ function splitTopLevelStatements(raw, surfaceOffset = null) {
|
|
|
216
285
|
else if (ch === ')' && depthParen > 0) depthParen -= 1;
|
|
217
286
|
else if (ch === '.' && depthBrace === 0 && depthBracket === 0 && depthParen === 0) {
|
|
218
287
|
const stmt = text.slice(start, i).trim();
|
|
219
|
-
if (stmt) out.push(stmt);
|
|
288
|
+
if (stmt) out.push(normalizeSurfaceStatement(stmt));
|
|
220
289
|
start = i + 1;
|
|
221
290
|
}
|
|
222
291
|
i += 1;
|
|
@@ -224,9 +293,13 @@ function splitTopLevelStatements(raw, surfaceOffset = null) {
|
|
|
224
293
|
|
|
225
294
|
const tail = text.slice(start).trim();
|
|
226
295
|
if (tail) {
|
|
227
|
-
// A raw binder-only segment is OK;
|
|
296
|
+
// A raw binder-only segment is OK; RDF 1.2 TriG named graph blocks are
|
|
297
|
+
// also OK without a trailing dot. Any other dangling text is most likely a
|
|
228
298
|
// missing dot in the surface body.
|
|
229
|
-
|
|
299
|
+
const normalizedTail = normalizeSurfaceStatement(tail);
|
|
300
|
+
if (normalizedTail !== tail) {
|
|
301
|
+
out.push(normalizedTail);
|
|
302
|
+
} else if (!/^_:[A-Za-z_][A-Za-z0-9._-]*(?:\s+_:[A-Za-z_][A-Za-z0-9._-]*)*$/.test(tail)) {
|
|
230
303
|
throw syntaxError('RDF Surface statement is missing a terminating dot', surfaceOffset);
|
|
231
304
|
}
|
|
232
305
|
}
|
|
@@ -296,6 +369,7 @@ function readSurfaceAt(s, at) {
|
|
|
296
369
|
}
|
|
297
370
|
|
|
298
371
|
const LOG_FOR_ALL_IN_IRI = '<http://www.w3.org/2000/10/swap/log#forAllIn>';
|
|
372
|
+
const LOG_NAME_OF_IRI = '<http://www.w3.org/2000/10/swap/log#nameOf>';
|
|
299
373
|
|
|
300
374
|
function rewriteBlankMarksWithMap(statement, labelToVarName) {
|
|
301
375
|
const map = labelToVarName instanceof Map ? labelToVarName : new Map();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eyeling",
|
|
3
|
-
"version": "1.30.
|
|
3
|
+
"version": "1.30.6",
|
|
4
4
|
"description": "A minimal Notation3 (N3) reasoner in JavaScript.",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"keywords": [
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"lint:fix": "eslint . --fix",
|
|
43
43
|
"build": "node tools/bundle.js",
|
|
44
44
|
"test:packlist": "node test/packlist.test.js",
|
|
45
|
-
"test:api": "node test/api.test.js
|
|
45
|
+
"test:api": "node test/api.test.js",
|
|
46
46
|
"test:rdf-surfaces": "node test/rdf_surfaces.test.js",
|
|
47
47
|
"test:builtins": "node test/builtins.test.js",
|
|
48
48
|
"test:store": "node test/store.test.js",
|
|
@@ -57,9 +57,7 @@
|
|
|
57
57
|
"test:rdf12:trig": "node test/rdf12.test.js trig",
|
|
58
58
|
"test:playground": "node test/playground.test.js",
|
|
59
59
|
"test:package": "node test/package.test.js",
|
|
60
|
-
"
|
|
61
|
-
"test": "npm run test:api && npm run test:builtins && npm run test:store && npm run test:examples && npm run test:examples:proof && npm run test:manifest && npm run test:rdf12 && npm run test:playground",
|
|
62
|
-
"posttest": "npm run test:package",
|
|
60
|
+
"test": "node test/run.js",
|
|
63
61
|
"preversion": "npm test",
|
|
64
62
|
"postversion": "git push origin HEAD --follow-tags"
|
|
65
63
|
},
|
package/test/examples.test.js
CHANGED
|
@@ -154,7 +154,7 @@ function resolveExampleTrigInput(root, inputFile) {
|
|
|
154
154
|
|
|
155
155
|
function resolveExampleRdfSurfaceInput(root, inputFile) {
|
|
156
156
|
const stem = path.basename(inputFile, path.extname(inputFile));
|
|
157
|
-
const rel = path.join('input', `${stem}.
|
|
157
|
+
const rel = path.join('input', `${stem}.trig`);
|
|
158
158
|
const abs = path.join(root, 'examples', rel);
|
|
159
159
|
if (!fs.existsSync(abs)) return null;
|
|
160
160
|
const text = fs.readFileSync(abs, 'utf8');
|
package/test/playground.test.js
CHANGED
|
@@ -62,7 +62,7 @@ function guessContentType(p) {
|
|
|
62
62
|
if (ext === '.js') return 'application/javascript; charset=utf-8';
|
|
63
63
|
if (ext === '.css') return 'text/css; charset=utf-8';
|
|
64
64
|
if (ext === '.json') return 'application/json; charset=utf-8';
|
|
65
|
-
if (ext === '.ttl' || ext === '.n3') return 'text/plain; charset=utf-8';
|
|
65
|
+
if (ext === '.ttl' || ext === '.trig' || ext === '.n3') return 'text/plain; charset=utf-8';
|
|
66
66
|
if (ext === '.txt' || ext === '.md') return 'text/plain; charset=utf-8';
|
|
67
67
|
return 'application/octet-stream';
|
|
68
68
|
}
|
|
@@ -6,7 +6,7 @@ const cp = require('node:child_process');
|
|
|
6
6
|
const path = require('node:path');
|
|
7
7
|
|
|
8
8
|
const { reason } = require('../index.js');
|
|
9
|
-
const { C, failResult, pass } = require('./report');
|
|
9
|
+
const { C, failResult, formatDuration, info, pass } = require('./report');
|
|
10
10
|
|
|
11
11
|
const ROOT = path.resolve(__dirname, '..');
|
|
12
12
|
const EYELING = path.join(ROOT, 'eyeling.js');
|
|
@@ -22,7 +22,7 @@ function runCli(input, args = ['--rdf-surfaces']) {
|
|
|
22
22
|
function runExample(name) {
|
|
23
23
|
return cp.spawnSync(
|
|
24
24
|
process.execPath,
|
|
25
|
-
[EYELING, '--rdf-surfaces', path.join(ROOT, 'examples', 'input', `${name}.
|
|
25
|
+
[EYELING, '--rdf-surfaces', path.join(ROOT, 'examples', 'input', `${name}.trig`), path.join(ROOT, 'examples', `${name}.n3`)],
|
|
26
26
|
{ encoding: 'utf8', maxBuffer: 20 * 1024 * 1024 },
|
|
27
27
|
);
|
|
28
28
|
}
|
|
@@ -128,6 +128,9 @@ const exampleCases = [
|
|
|
128
128
|
['rdf-surfaces-all-values-from-reverse', '@prefix ex: <http://example.org/> .\n\nex:box a ex:AllowedContainer .'],
|
|
129
129
|
['rdf-surfaces-rdfs-range-codex', '@prefix ex: <http://example.org/> .\n\nex:bob a ex:Person .'],
|
|
130
130
|
['rdf-surfaces-rdfs-subclass-codex', '@prefix ex: <http://example.org/> .\n\nex:Brussels a ex:HumanCommunity .'],
|
|
131
|
+
['rdf-surfaces-rdf12-named-graph', '@prefix ex: <http://example.org/> .\n\nex:Brussels a ex:ReportedCity .'],
|
|
132
|
+
['rdf-surfaces-rdf12-triple-term', '@prefix ex: <http://example.org/> .\n\nex:claim1 a ex:CityClaim .'],
|
|
133
|
+
['rdf-surfaces-rdf12-graph-triple-term', '@prefix ex: <http://example.org/> .\n\nex:obs1 a ex:AuditedObservation .'],
|
|
131
134
|
[
|
|
132
135
|
'rdf-surfaces-owl-all-values-from-codex',
|
|
133
136
|
'@prefix ex: <http://example.org/> .\n\nex:item43 a ex:AllowedItem .\nex:item42 a ex:AllowedItem .\nex:box a ex:AllowedContainer .\nex:crate a ex:AllowedContainer .',
|
|
@@ -144,6 +147,10 @@ const exampleCases = [
|
|
|
144
147
|
],
|
|
145
148
|
];
|
|
146
149
|
|
|
150
|
+
const suiteStart = Date.now();
|
|
151
|
+
|
|
152
|
+
info('RDF Surfaces tests');
|
|
153
|
+
|
|
147
154
|
let seq = 0;
|
|
148
155
|
let failed = 0;
|
|
149
156
|
|
|
@@ -211,4 +218,10 @@ _:x a ex:Impossible .
|
|
|
211
218
|
}
|
|
212
219
|
}
|
|
213
220
|
|
|
214
|
-
|
|
221
|
+
const suiteMs = Date.now() - suiteStart;
|
|
222
|
+
info(`Total elapsed: ${formatDuration(suiteMs)}`);
|
|
223
|
+
if (failed) {
|
|
224
|
+
info(`Some RDF Surfaces tests failed (${seq - failed}/${seq})`);
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
227
|
+
info(`All RDF Surfaces tests passed (${seq}/${seq})`);
|
package/test/run.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const cp = require('node:child_process');
|
|
5
|
+
|
|
6
|
+
const { C, formatDuration } = require('./report');
|
|
7
|
+
|
|
8
|
+
const sections = [
|
|
9
|
+
['Build bundle', 'npm', ['run', 'build']],
|
|
10
|
+
['Packlist checks', 'npm', ['run', 'test:packlist']],
|
|
11
|
+
['API tests', 'npm', ['run', 'test:api']],
|
|
12
|
+
['Streaming RDF Messages tests', 'npm', ['run', 'test:stream-messages']],
|
|
13
|
+
['RDF Surfaces tests', 'npm', ['run', 'test:rdf-surfaces']],
|
|
14
|
+
['Builtin contract tests', 'npm', ['run', 'test:builtins']],
|
|
15
|
+
['Store tests', 'npm', ['run', 'test:store']],
|
|
16
|
+
['Examples tests', 'npm', ['run', 'test:examples']],
|
|
17
|
+
['Proof examples tests', 'npm', ['run', 'test:examples:proof']],
|
|
18
|
+
['Manifest tests', 'npm', ['run', 'test:manifest']],
|
|
19
|
+
['RDF 1.2 syntax tests', 'npm', ['run', 'test:rdf12']],
|
|
20
|
+
['Playground tests', 'npm', ['run', 'test:playground']],
|
|
21
|
+
['Package tests', 'npm', ['run', 'test:package']],
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
function sectionLine(kind, label, ms) {
|
|
25
|
+
const suffix = typeof ms === 'number' ? ` (${formatDuration(ms)})` : '';
|
|
26
|
+
console.log(`${C.y}==${C.n} ${kind} ${label}${suffix}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function runSection(label, cmd, args) {
|
|
30
|
+
console.log('');
|
|
31
|
+
sectionLine('Start', label);
|
|
32
|
+
const startedAt = Date.now();
|
|
33
|
+
const r = cp.spawnSync(cmd, args, {
|
|
34
|
+
cwd: process.cwd(),
|
|
35
|
+
env: process.env,
|
|
36
|
+
shell: process.platform === 'win32',
|
|
37
|
+
stdio: 'inherit',
|
|
38
|
+
});
|
|
39
|
+
const elapsed = Date.now() - startedAt;
|
|
40
|
+
if (r.error) {
|
|
41
|
+
console.error(`${C.r}FAIL${C.n} ${label}: ${r.error.message || String(r.error)}`);
|
|
42
|
+
sectionLine('End', `${label} failed`, elapsed);
|
|
43
|
+
console.log('');
|
|
44
|
+
return 1;
|
|
45
|
+
}
|
|
46
|
+
const status = typeof r.status === 'number' ? r.status : 1;
|
|
47
|
+
sectionLine('End', status === 0 ? `${label} passed` : `${label} failed`, elapsed);
|
|
48
|
+
console.log('');
|
|
49
|
+
return status;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let status = 0;
|
|
53
|
+
for (const [label, cmd, args] of sections) {
|
|
54
|
+
const sectionStatus = runSection(label, cmd, args);
|
|
55
|
+
if (sectionStatus !== 0) {
|
|
56
|
+
status = sectionStatus;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
process.exit(status);
|