eyeling 1.6.21 → 1.6.22
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/eyeling.js +73 -8
- package/package.json +1 -1
package/eyeling.js
CHANGED
|
@@ -759,8 +759,9 @@ function lex(inputText) {
|
|
|
759
759
|
// ===========================================================================
|
|
760
760
|
|
|
761
761
|
class PrefixEnv {
|
|
762
|
-
constructor(map) {
|
|
763
|
-
this.map = map || {}; // prefix -> IRI
|
|
762
|
+
constructor(map, baseIri) {
|
|
763
|
+
this.map = map || {}; // prefix -> IRI (including "" for @prefix :)
|
|
764
|
+
this.baseIri = baseIri || ''; // base IRI for resolving <relative>
|
|
764
765
|
}
|
|
765
766
|
|
|
766
767
|
static newDefault() {
|
|
@@ -774,14 +775,18 @@ class PrefixEnv {
|
|
|
774
775
|
m['list'] = LIST_NS;
|
|
775
776
|
m['time'] = TIME_NS;
|
|
776
777
|
m['genid'] = SKOLEM_NS;
|
|
777
|
-
m[''] = '';
|
|
778
|
-
return new PrefixEnv(m);
|
|
778
|
+
m[''] = ''; // empty prefix default namespace
|
|
779
|
+
return new PrefixEnv(m, ''); // base IRI starts empty
|
|
779
780
|
}
|
|
780
781
|
|
|
781
782
|
set(pref, base) {
|
|
782
783
|
this.map[pref] = base;
|
|
783
784
|
}
|
|
784
785
|
|
|
786
|
+
setBase(baseIri) {
|
|
787
|
+
this.baseIri = baseIri || '';
|
|
788
|
+
}
|
|
789
|
+
|
|
785
790
|
expandQName(q) {
|
|
786
791
|
if (q.includes(':')) {
|
|
787
792
|
const [p, local] = q.split(':', 2);
|
|
@@ -1020,7 +1025,7 @@ class Parser {
|
|
|
1020
1025
|
const tok2 = this.next();
|
|
1021
1026
|
let iri;
|
|
1022
1027
|
if (tok2.typ === 'IriRef') {
|
|
1023
|
-
iri = tok2.value || '';
|
|
1028
|
+
iri = resolveIriRef(tok2.value || '', this.prefixes.baseIri || '');
|
|
1024
1029
|
} else if (tok2.typ === 'Ident') {
|
|
1025
1030
|
iri = this.prefixes.expandQName(tok2.value || '');
|
|
1026
1031
|
} else {
|
|
@@ -1034,14 +1039,14 @@ class Parser {
|
|
|
1034
1039
|
const tok = this.next();
|
|
1035
1040
|
let iri;
|
|
1036
1041
|
if (tok.typ === 'IriRef') {
|
|
1037
|
-
iri = tok.value || '';
|
|
1042
|
+
iri = resolveIriRef(tok.value || '', this.prefixes.baseIri || '');
|
|
1038
1043
|
} else if (tok.typ === 'Ident') {
|
|
1039
1044
|
iri = tok.value || '';
|
|
1040
1045
|
} else {
|
|
1041
1046
|
throw new Error(`Expected IRI after @base, got ${tok.toString()}`);
|
|
1042
1047
|
}
|
|
1043
1048
|
this.expectDot();
|
|
1044
|
-
this.prefixes.
|
|
1049
|
+
this.prefixes.setBase(iri);
|
|
1045
1050
|
}
|
|
1046
1051
|
|
|
1047
1052
|
parseTerm() {
|
|
@@ -1072,7 +1077,7 @@ class Parser {
|
|
|
1072
1077
|
}
|
|
1073
1078
|
|
|
1074
1079
|
if (typ === 'IriRef') {
|
|
1075
|
-
const base = this.prefixes.
|
|
1080
|
+
const base = this.prefixes.baseIri || '';
|
|
1076
1081
|
return internIri(resolveIriRef(val || '', base));
|
|
1077
1082
|
}
|
|
1078
1083
|
if (typ === 'Ident') {
|
|
@@ -1150,6 +1155,66 @@ class Parser {
|
|
|
1150
1155
|
return new Blank(`_:b${this.blankCounter}`);
|
|
1151
1156
|
}
|
|
1152
1157
|
|
|
1158
|
+
// IRI property list: [ id <IRI> predicateObjectList? ]
|
|
1159
|
+
// Lets you embed descriptions of an IRI directly in object position.
|
|
1160
|
+
if (this.peek().typ === 'Ident' && (this.peek().value || '') === 'id') {
|
|
1161
|
+
this.next(); // consume 'id'
|
|
1162
|
+
const iriTerm = this.parseTerm();
|
|
1163
|
+
|
|
1164
|
+
// N3 note: 'id' form is not meant to be used with blank node identifiers.
|
|
1165
|
+
if (iriTerm instanceof Blank && iriTerm.label.startsWith('_:')) {
|
|
1166
|
+
throw new Error("Cannot use 'id' keyword with a blank node identifier inside [...]");
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// Optional ';' right after the id IRI (tolerated).
|
|
1170
|
+
if (this.peek().typ === 'Semicolon') this.next();
|
|
1171
|
+
|
|
1172
|
+
// Empty IRI property list: [ id :iri ]
|
|
1173
|
+
if (this.peek().typ === 'RBracket') {
|
|
1174
|
+
this.next();
|
|
1175
|
+
return iriTerm;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
const subj = iriTerm;
|
|
1179
|
+
while (true) {
|
|
1180
|
+
let pred;
|
|
1181
|
+
let invert = false;
|
|
1182
|
+
if (this.peek().typ === 'Ident' && (this.peek().value || '') === 'a') {
|
|
1183
|
+
this.next();
|
|
1184
|
+
pred = internIri(RDF_NS + 'type');
|
|
1185
|
+
} else if (this.peek().typ === 'OpPredInvert') {
|
|
1186
|
+
this.next(); // "<-"
|
|
1187
|
+
pred = this.parseTerm();
|
|
1188
|
+
invert = true;
|
|
1189
|
+
} else {
|
|
1190
|
+
pred = this.parseTerm();
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
const objs = [this.parseTerm()];
|
|
1194
|
+
while (this.peek().typ === 'Comma') {
|
|
1195
|
+
this.next();
|
|
1196
|
+
objs.push(this.parseTerm());
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
for (const o of objs) {
|
|
1200
|
+
this.pendingTriples.push(invert ? new Triple(o, pred, subj) : new Triple(subj, pred, o));
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
if (this.peek().typ === 'Semicolon') {
|
|
1204
|
+
this.next();
|
|
1205
|
+
if (this.peek().typ === 'RBracket') break;
|
|
1206
|
+
continue;
|
|
1207
|
+
}
|
|
1208
|
+
break;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
if (this.peek().typ !== 'RBracket') {
|
|
1212
|
+
throw new Error(`Expected ']' at end of IRI property list, got ${JSON.stringify(this.peek())}`);
|
|
1213
|
+
}
|
|
1214
|
+
this.next();
|
|
1215
|
+
return iriTerm;
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1153
1218
|
// [ predicateObjectList ]
|
|
1154
1219
|
this.blankCounter += 1;
|
|
1155
1220
|
const id = `_:b${this.blankCounter}`;
|