rdflib 2.3.0 → 2.3.1-0007ffed
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 +30 -0
- package/dist/rdflib.min.js +1 -1
- package/dist/rdflib.min.js.map +1 -1
- package/esm/n3parser.js +45 -9
- package/esm/serialize.js +4 -2
- package/esm/serializer.js +47 -17
- package/lib/n3parser.js +45 -9
- package/lib/serialize.js +4 -2
- package/lib/serializer.d.ts +14 -8
- package/lib/serializer.js +47 -17
- package/package.json +4 -2
- package/src/n3parser.js +46 -17
- package/src/serialize.ts +4 -2
- package/src/serializer.js +52 -22
package/src/n3parser.js
CHANGED
|
@@ -212,10 +212,20 @@ var signed_integer = new RegExp("^[-+]?[0-9]+", 'g');
|
|
|
212
212
|
var number_syntax = new RegExp("^([-+]?[0-9]+)(\\.[0-9]+)?([eE][-+]?[0-9]+)?", 'g');
|
|
213
213
|
var datetime_syntax = new RegExp('^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9](T[0-9][0-9]:[0-9][0-9](:[0-9][0-9](\\.[0-9]*)?)?)?Z?');
|
|
214
214
|
|
|
215
|
+
// Reused in tight loops to detect whitespace or comment after a dot
|
|
216
|
+
var wsOrHash = new RegExp("[\\s#]");
|
|
217
|
+
|
|
215
218
|
var digitstring = new RegExp("^[0-9]+", 'g');
|
|
216
219
|
var interesting = new RegExp("[\\\\\\r\\n\\\"]", 'g');
|
|
217
220
|
var langcode = new RegExp("^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*", 'g');
|
|
218
221
|
|
|
222
|
+
// Returns true when a dot at position i should terminate a name,
|
|
223
|
+
// i.e., when the next character is whitespace, a comment start, or EOF
|
|
224
|
+
function dotTerminatesName(str, i) {
|
|
225
|
+
var next = str.charAt(i + 1);
|
|
226
|
+
return next === '' || wsOrHash.test(next);
|
|
227
|
+
}
|
|
228
|
+
|
|
219
229
|
function createSinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why) {
|
|
220
230
|
return new SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why);
|
|
221
231
|
}
|
|
@@ -554,7 +564,7 @@ export class SinkParser {
|
|
|
554
564
|
<- prop -<
|
|
555
565
|
_operator_*/
|
|
556
566
|
|
|
557
|
-
|
|
567
|
+
var j = this.skipSpace(str, i);
|
|
558
568
|
if ((j < 0)) {
|
|
559
569
|
return j;
|
|
560
570
|
}
|
|
@@ -703,22 +713,17 @@ export class SinkParser {
|
|
|
703
713
|
if ((j >= 0)) {
|
|
704
714
|
var subj = objs[0];
|
|
705
715
|
if ((pyjslib_len(objs) > 1)) {
|
|
706
|
-
|
|
707
716
|
var __obj = new pyjslib_Iterator(objs);
|
|
708
717
|
try {
|
|
709
718
|
while (true) {
|
|
710
719
|
var obj = __obj.next();
|
|
711
|
-
|
|
712
|
-
|
|
713
720
|
this.makeStatement(new pyjslib_Tuple([this._context, this._store.sym(DAML_sameAs_URI), subj, obj]));
|
|
714
|
-
|
|
715
721
|
}
|
|
716
722
|
} catch (e) {
|
|
717
723
|
if (e != StopIteration) {
|
|
718
724
|
throw e;
|
|
719
725
|
}
|
|
720
726
|
}
|
|
721
|
-
|
|
722
727
|
}
|
|
723
728
|
var j = this.skipSpace(str, j);
|
|
724
729
|
if ((j < 0)) {
|
|
@@ -743,6 +748,16 @@ export class SinkParser {
|
|
|
743
748
|
if ((j < 0)) {
|
|
744
749
|
throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF when ']' expected after [ <propertyList>");
|
|
745
750
|
}
|
|
751
|
+
if ((str.slice( j, ( j + 1 ) ) == ".")) {
|
|
752
|
+
// If a dot is found after a blank node, treat it as a statement terminator.
|
|
753
|
+
// Do NOT consume the '.' here: statement terminators are handled centrally by
|
|
754
|
+
// checkDot() (called by directiveOrStatement after statement()). Consuming the dot
|
|
755
|
+
// locally would bypass that unified logic and could cause inconsistencies.
|
|
756
|
+
// We do consume ']' below because it is a structural closer of the blank node,
|
|
757
|
+
// not a statement terminator.
|
|
758
|
+
res.push(subj);
|
|
759
|
+
return j; // leave '.' for checkDot()
|
|
760
|
+
}
|
|
746
761
|
if ((str.slice( j, ( j + 1 ) ) != "]")) {
|
|
747
762
|
throw BadSyntax(this._thisDoc, this.lines, str, j, "']' expected");
|
|
748
763
|
}
|
|
@@ -1208,7 +1223,17 @@ export class SinkParser {
|
|
|
1208
1223
|
return -1;
|
|
1209
1224
|
}
|
|
1210
1225
|
var i = j;
|
|
1211
|
-
while ((i < pyjslib_len(str))
|
|
1226
|
+
while ((i < pyjslib_len(str))) {
|
|
1227
|
+
var c = str.charAt(i);
|
|
1228
|
+
if (c === '.') {
|
|
1229
|
+
if (dotTerminatesName(str, i)) {
|
|
1230
|
+
break; // treat as statement terminator, not part of name
|
|
1231
|
+
}
|
|
1232
|
+
// else: accept '.' as part of name
|
|
1233
|
+
} else if (_notNameChars.indexOf(c) >= 0) {
|
|
1234
|
+
// Other invalid characters terminate the name
|
|
1235
|
+
break;
|
|
1236
|
+
}
|
|
1212
1237
|
var i = ( i + 1 ) ;
|
|
1213
1238
|
}
|
|
1214
1239
|
res.push(str.slice( j, i));
|
|
@@ -1235,13 +1260,15 @@ export class SinkParser {
|
|
|
1235
1260
|
var i = ( i + 1 ) ;
|
|
1236
1261
|
while ((i < pyjslib_len(str))) {
|
|
1237
1262
|
var c = str.charAt(i);
|
|
1238
|
-
if (
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
else {
|
|
1263
|
+
if (c === '.') {
|
|
1264
|
+
if (dotTerminatesName(str, i)) {
|
|
1265
|
+
break; // dot ends the name here
|
|
1266
|
+
}
|
|
1267
|
+
} else if (_notNameChars.indexOf(c) >= 0) {
|
|
1243
1268
|
break;
|
|
1244
1269
|
}
|
|
1270
|
+
var ln = ( ln + c ) ;
|
|
1271
|
+
var i = ( i + 1 ) ;
|
|
1245
1272
|
}
|
|
1246
1273
|
}
|
|
1247
1274
|
else {
|
|
@@ -1253,13 +1280,15 @@ export class SinkParser {
|
|
|
1253
1280
|
var ln = "";
|
|
1254
1281
|
while ((i < pyjslib_len(str))) {
|
|
1255
1282
|
var c = str.charAt(i);
|
|
1256
|
-
if (
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
else {
|
|
1283
|
+
if (c === '.') {
|
|
1284
|
+
if (dotTerminatesName(str, i)) {
|
|
1285
|
+
break; // dot ends the name here
|
|
1286
|
+
}
|
|
1287
|
+
} else if (_notNameChars.indexOf(c) >= 0) {
|
|
1261
1288
|
break;
|
|
1262
1289
|
}
|
|
1290
|
+
var ln = ( ln + c ) ;
|
|
1291
|
+
var i = ( i + 1 ) ;
|
|
1263
1292
|
}
|
|
1264
1293
|
res.push(new pyjslib_Tuple([pfx, ln]));
|
|
1265
1294
|
return i;
|
package/src/serialize.ts
CHANGED
|
@@ -72,7 +72,8 @@ export default function serialize (
|
|
|
72
72
|
return executeCallback(null, documentString)
|
|
73
73
|
case TurtleContentType:
|
|
74
74
|
case TurtleLegacyContentType:
|
|
75
|
-
|
|
75
|
+
// Suppress = for sameAs and => for implies; preserve any user-specified flags (e.g., 'o')
|
|
76
|
+
sz.setFlags('si' + (opts.flags ? (' ' + opts.flags) : ''))
|
|
76
77
|
documentString = sz.statementsToN3(newSts)
|
|
77
78
|
return executeCallback(null, documentString)
|
|
78
79
|
case NTriplesContentType:
|
|
@@ -80,7 +81,8 @@ export default function serialize (
|
|
|
80
81
|
documentString = sz.statementsToNTriples(newSts)
|
|
81
82
|
return executeCallback(null, documentString)
|
|
82
83
|
case JSONLDContentType:
|
|
83
|
-
|
|
84
|
+
// turtle + dr (means no default, no relative prefix); preserve user flags
|
|
85
|
+
sz.setFlags('si dr' + (opts.flags ? (' ' + opts.flags) : ''))
|
|
84
86
|
documentString = sz.statementsToJsonld(newSts) // convert via turtle
|
|
85
87
|
return executeCallback(null, documentString)
|
|
86
88
|
case NQuadsContentType:
|
package/src/serializer.js
CHANGED
|
@@ -5,14 +5,12 @@
|
|
|
5
5
|
** This is or was https://github.com/linkeddata/rdflib.js/blob/main/src/serializer.js
|
|
6
6
|
** Licence: MIT
|
|
7
7
|
*/
|
|
8
|
-
import
|
|
9
|
-
import
|
|
8
|
+
import * as ttl2jsonld from '@frogcat/ttl2jsonld'
|
|
9
|
+
import solidNs from 'solid-namespace'
|
|
10
|
+
import CanonicalDataFactory from './factories/canonical-data-factory'
|
|
10
11
|
import * as Uri from './uri'
|
|
11
12
|
import * as Util from './utils-js'
|
|
12
|
-
import CanonicalDataFactory from './factories/canonical-data-factory'
|
|
13
13
|
import { createXSD } from './xsd'
|
|
14
|
-
import solidNs from 'solid-namespace'
|
|
15
|
-
import * as ttl2jsonld from '@frogcat/ttl2jsonld'
|
|
16
14
|
|
|
17
15
|
|
|
18
16
|
export default function createSerializer(store) {
|
|
@@ -52,6 +50,12 @@ export class Serializer {
|
|
|
52
50
|
return this
|
|
53
51
|
}
|
|
54
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Set serializer behavior flags. Letters can be combined with spaces.
|
|
55
|
+
* Examples: 'si', 'deinprstux', 'si dr', 'o'.
|
|
56
|
+
* Notable flags:
|
|
57
|
+
* - 'o': do not abbreviate to a prefixed name when the local part contains a dot
|
|
58
|
+
*/
|
|
55
59
|
setFlags(flags) {
|
|
56
60
|
this.flags = flags || '';
|
|
57
61
|
return this
|
|
@@ -251,10 +255,33 @@ export class Serializer {
|
|
|
251
255
|
return this.statementsToN3(f.statements)
|
|
252
256
|
}
|
|
253
257
|
|
|
254
|
-
_notQNameChars = '\t\r\n !"#$%&\'()
|
|
258
|
+
_notQNameChars = '\t\r\n !"#$%&\'()*,+/;<=>?@[\\]^`{|}~' // issue#228
|
|
255
259
|
_notNameChars =
|
|
256
260
|
(this._notQNameChars + ':')
|
|
257
261
|
|
|
262
|
+
// Validate if a string is a valid PN_LOCAL per Turtle 1.1 spec
|
|
263
|
+
// Allows dots inside the local name but not as trailing character
|
|
264
|
+
// Also allows empty local names (for URIs ending in / or #)
|
|
265
|
+
isValidPNLocal(local) {
|
|
266
|
+
// Empty local name is valid (e.g., ex: for http://example.com/)
|
|
267
|
+
if (local.length === 0) return true
|
|
268
|
+
|
|
269
|
+
// Cannot end with a dot
|
|
270
|
+
if (local[local.length - 1] === '.') return false
|
|
271
|
+
|
|
272
|
+
// Check each character (allow dots mid-string)
|
|
273
|
+
for (var i = 0; i < local.length; i++) {
|
|
274
|
+
var ch = local[i]
|
|
275
|
+
// Dot is allowed unless it's the last character (checked above)
|
|
276
|
+
if (ch === '.') continue
|
|
277
|
+
// Other characters must not be in the blacklist
|
|
278
|
+
if (this._notNameChars.indexOf(ch) >= 0) {
|
|
279
|
+
return false
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return true
|
|
283
|
+
}
|
|
284
|
+
|
|
258
285
|
explicitURI(uri) {
|
|
259
286
|
if (this.flags.indexOf('r') < 0 && this.base) {
|
|
260
287
|
uri = Uri.refTo(this.base, uri)
|
|
@@ -628,13 +655,17 @@ export class Serializer {
|
|
|
628
655
|
if (j >= 0 && this.flags.indexOf('p') < 0 &&
|
|
629
656
|
// Can split at namespace but only if http[s]: URI or file: or ws[s] (why not others?)
|
|
630
657
|
(uri.indexOf('http') === 0 || uri.indexOf('ws') === 0 || uri.indexOf('file') === 0)) {
|
|
631
|
-
var
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
658
|
+
var localid = uri.slice(j + 1)
|
|
659
|
+
var namesp = uri.slice(0, j + 1)
|
|
660
|
+
// Don't split if namespace is just the protocol (e.g., https://)
|
|
661
|
+
// A valid namespace should have content after the protocol
|
|
662
|
+
var minNamespaceLength = uri.indexOf('://') + 4 // e.g., "http://x" minimum
|
|
663
|
+
// Also don't split if namespace is the base directory (would serialize as relative URI)
|
|
664
|
+
var baseDir = this.base ? this.base.slice(0, Math.max(this.base.lastIndexOf('/'), this.base.lastIndexOf('#')) + 1) : null
|
|
665
|
+
var namespaceIsBaseDir = baseDir && namesp === baseDir
|
|
666
|
+
// If flag 'o' is present, forbid dots in local part when abbreviating
|
|
667
|
+
var forbidDotLocal = this.flags.indexOf('o') >= 0 && localid.indexOf('.') >= 0
|
|
668
|
+
var canSplit = !namespaceIsBaseDir && !forbidDotLocal && namesp.length > minNamespaceLength && this.isValidPNLocal(localid)
|
|
638
669
|
/*
|
|
639
670
|
if (uri.slice(0, j + 1) === this.base + '#') { // base-relative
|
|
640
671
|
if (canSplit) {
|
|
@@ -645,8 +676,6 @@ export class Serializer {
|
|
|
645
676
|
}
|
|
646
677
|
*/
|
|
647
678
|
if (canSplit) {
|
|
648
|
-
var localid = uri.slice(j + 1)
|
|
649
|
-
var namesp = uri.slice(0, j + 1)
|
|
650
679
|
if (this.defaultNamespace && this.defaultNamespace === namesp &&
|
|
651
680
|
this.flags.indexOf('d') < 0) { // d -> suppress default
|
|
652
681
|
if (this.flags.indexOf('k') >= 0 &&
|
|
@@ -883,10 +912,10 @@ export class Serializer {
|
|
|
883
912
|
break
|
|
884
913
|
case 'Literal':
|
|
885
914
|
results = results.concat(['<' + t +
|
|
886
|
-
(st.object.
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
915
|
+
(st.object.language ? ' xml:lang="' + st.object.language + '"' :
|
|
916
|
+
(st.object.datatype.equals(this.xsd.string)
|
|
917
|
+
? ''
|
|
918
|
+
: ' rdf:datatype="' + escapeForXML(st.object.datatype.uri) + '"')) +
|
|
890
919
|
'>' + escapeForXML(st.object.value) +
|
|
891
920
|
'</' + t + '>'])
|
|
892
921
|
break
|
|
@@ -949,9 +978,10 @@ export class Serializer {
|
|
|
949
978
|
break
|
|
950
979
|
case 'Literal':
|
|
951
980
|
results = results.concat(['<' + qname(st.predicate) +
|
|
952
|
-
(st.object.
|
|
953
|
-
|
|
954
|
-
|
|
981
|
+
(st.object.language ?
|
|
982
|
+
' xml:lang="' + st.object.language + '"' :
|
|
983
|
+
(st.object.datatype.equals(this.xsd.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.value) + '"'))
|
|
984
|
+
+ '>' + escapeForXML(st.object.value) +
|
|
955
985
|
'</' + qname(st.predicate) + '>'])
|
|
956
986
|
break
|
|
957
987
|
case 'Collection':
|