rdflib 2.3.0-1c284ee8 → 2.3.0-344dec99

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/esm/serialize.js CHANGED
@@ -40,7 +40,8 @@ contentType, callback, options) {
40
40
  return executeCallback(null, documentString);
41
41
  case TurtleContentType:
42
42
  case TurtleLegacyContentType:
43
- sz.setFlags('si'); // Suppress = for sameAs and => for implies
43
+ // Suppress = for sameAs and => for implies; preserve any user-specified flags (e.g., 'o')
44
+ sz.setFlags('si' + (opts.flags ? ' ' + opts.flags : ''));
44
45
  documentString = sz.statementsToN3(newSts);
45
46
  return executeCallback(null, documentString);
46
47
  case NTriplesContentType:
@@ -48,7 +49,8 @@ contentType, callback, options) {
48
49
  documentString = sz.statementsToNTriples(newSts);
49
50
  return executeCallback(null, documentString);
50
51
  case JSONLDContentType:
51
- sz.setFlags('si dr'); // turtle + dr (means no default, no relative prefix)
52
+ // turtle + dr (means no default, no relative prefix); preserve user flags
53
+ sz.setFlags('si dr' + (opts.flags ? ' ' + opts.flags : ''));
52
54
  documentString = sz.statementsToJsonld(newSts); // convert via turtle
53
55
  return executeCallback(null, documentString);
54
56
  case NQuadsContentType:
package/esm/serializer.js CHANGED
@@ -20,7 +20,7 @@ export default function createSerializer(store) {
20
20
  ;
21
21
  export class Serializer {
22
22
  constructor(store) {
23
- _defineProperty(this, "_notQNameChars", '\t\r\n !"#$%&\'()*.,+/;<=>?@[\\]^`{|}~');
23
+ _defineProperty(this, "_notQNameChars", '\t\r\n !"#$%&\'()*,+/;<=>?@[\\]^`{|}~');
24
24
  // issue#228
25
25
  _defineProperty(this, "_notNameChars", this._notQNameChars + ':');
26
26
  // stringToN3: String escaping for N3
@@ -54,6 +54,13 @@ export class Serializer {
54
54
  this.base = base;
55
55
  return this;
56
56
  }
57
+
58
+ /**
59
+ * Set serializer behavior flags. Letters can be combined with spaces.
60
+ * Examples: 'si', 'deinprstux', 'si dr', 'o'.
61
+ * Notable flags:
62
+ * - 'o': do not abbreviate to a prefixed name when the local part contains a dot
63
+ */
57
64
  setFlags(flags) {
58
65
  this.flags = flags || '';
59
66
  return this;
@@ -244,6 +251,28 @@ export class Serializer {
244
251
  toN3(f) {
245
252
  return this.statementsToN3(f.statements);
246
253
  }
254
+ // Validate if a string is a valid PN_LOCAL per Turtle 1.1 spec
255
+ // Allows dots inside the local name but not as trailing character
256
+ // Also allows empty local names (for URIs ending in / or #)
257
+ isValidPNLocal(local) {
258
+ // Empty local name is valid (e.g., ex: for http://example.com/)
259
+ if (local.length === 0) return true;
260
+
261
+ // Cannot end with a dot
262
+ if (local[local.length - 1] === '.') return false;
263
+
264
+ // Check each character (allow dots mid-string)
265
+ for (var i = 0; i < local.length; i++) {
266
+ var ch = local[i];
267
+ // Dot is allowed unless it's the last character (checked above)
268
+ if (ch === '.') continue;
269
+ // Other characters must not be in the blacklist
270
+ if (this._notNameChars.indexOf(ch) >= 0) {
271
+ return false;
272
+ }
273
+ }
274
+ return true;
275
+ }
247
276
  explicitURI(uri) {
248
277
  if (this.flags.indexOf('r') < 0 && this.base) {
249
278
  uri = Uri.refTo(this.base, uri);
@@ -606,13 +635,17 @@ export class Serializer {
606
635
  if (j >= 0 && this.flags.indexOf('p') < 0 && (
607
636
  // Can split at namespace but only if http[s]: URI or file: or ws[s] (why not others?)
608
637
  uri.indexOf('http') === 0 || uri.indexOf('ws') === 0 || uri.indexOf('file') === 0)) {
609
- var canSplit = true;
610
- for (var k = j + 1; k < uri.length; k++) {
611
- if (this._notNameChars.indexOf(uri[k]) >= 0) {
612
- canSplit = false;
613
- break;
614
- }
615
- }
638
+ var localid = uri.slice(j + 1);
639
+ var namesp = uri.slice(0, j + 1);
640
+ // Don't split if namespace is just the protocol (e.g., https://)
641
+ // A valid namespace should have content after the protocol
642
+ var minNamespaceLength = uri.indexOf('://') + 4; // e.g., "http://x" minimum
643
+ // Also don't split if namespace is the base directory (would serialize as relative URI)
644
+ var baseDir = this.base ? this.base.slice(0, Math.max(this.base.lastIndexOf('/'), this.base.lastIndexOf('#')) + 1) : null;
645
+ var namespaceIsBaseDir = baseDir && namesp === baseDir;
646
+ // If flag 'o' is present, forbid dots in local part when abbreviating
647
+ var forbidDotLocal = this.flags.indexOf('o') >= 0 && localid.indexOf('.') >= 0;
648
+ var canSplit = !namespaceIsBaseDir && !forbidDotLocal && namesp.length > minNamespaceLength && this.isValidPNLocal(localid);
616
649
  /*
617
650
  if (uri.slice(0, j + 1) === this.base + '#') { // base-relative
618
651
  if (canSplit) {
@@ -623,8 +656,6 @@ export class Serializer {
623
656
  }
624
657
  */
625
658
  if (canSplit) {
626
- var localid = uri.slice(j + 1);
627
- var namesp = uri.slice(0, j + 1);
628
659
  if (this.defaultNamespace && this.defaultNamespace === namesp && this.flags.indexOf('d') < 0) {
629
660
  // d -> suppress default
630
661
  if (this.flags.indexOf('k') >= 0 && this.keyords.indexOf(localid) < 0) {
package/lib/serialize.js CHANGED
@@ -47,7 +47,8 @@ contentType, callback, options) {
47
47
  return executeCallback(null, documentString);
48
48
  case _types.TurtleContentType:
49
49
  case _types.TurtleLegacyContentType:
50
- sz.setFlags('si'); // Suppress = for sameAs and => for implies
50
+ // Suppress = for sameAs and => for implies; preserve any user-specified flags (e.g., 'o')
51
+ sz.setFlags('si' + (opts.flags ? ' ' + opts.flags : ''));
51
52
  documentString = sz.statementsToN3(newSts);
52
53
  return executeCallback(null, documentString);
53
54
  case _types.NTriplesContentType:
@@ -55,7 +56,8 @@ contentType, callback, options) {
55
56
  documentString = sz.statementsToNTriples(newSts);
56
57
  return executeCallback(null, documentString);
57
58
  case _types.JSONLDContentType:
58
- sz.setFlags('si dr'); // turtle + dr (means no default, no relative prefix)
59
+ // turtle + dr (means no default, no relative prefix); preserve user flags
60
+ sz.setFlags('si dr' + (opts.flags ? ' ' + opts.flags : ''));
59
61
  documentString = sz.statementsToJsonld(newSts); // convert via turtle
60
62
  return executeCallback(null, documentString);
61
63
  case _types.NQuadsContentType:
@@ -22,6 +22,12 @@ export class Serializer {
22
22
  string: NamedNode;
23
23
  };
24
24
  setBase(base: any): Serializer;
25
+ /**
26
+ * Set serializer behavior flags. Letters can be combined with spaces.
27
+ * Examples: 'si', 'deinprstux', 'si dr', 'o'.
28
+ * Notable flags:
29
+ * - 'o': do not abbreviate to a prefixed name when the local part contains a dot
30
+ */
25
31
  setFlags(flags: any): Serializer;
26
32
  toStr(x: any): any;
27
33
  fromStr(s: any): any;
@@ -51,6 +57,7 @@ export class Serializer {
51
57
  toN3(f: any): string;
52
58
  _notQNameChars: string;
53
59
  _notNameChars: string;
60
+ isValidPNLocal(local: any): boolean;
54
61
  explicitURI(uri: any): string;
55
62
  statementsToNTriples(sts: any): string;
56
63
  statementsToN3(sts: any): string;
package/lib/serializer.js CHANGED
@@ -30,7 +30,7 @@ function createSerializer(store) {
30
30
  ;
31
31
  class Serializer {
32
32
  constructor(store) {
33
- (0, _defineProperty2.default)(this, "_notQNameChars", '\t\r\n !"#$%&\'()*.,+/;<=>?@[\\]^`{|}~');
33
+ (0, _defineProperty2.default)(this, "_notQNameChars", '\t\r\n !"#$%&\'()*,+/;<=>?@[\\]^`{|}~');
34
34
  // issue#228
35
35
  (0, _defineProperty2.default)(this, "_notNameChars", this._notQNameChars + ':');
36
36
  // stringToN3: String escaping for N3
@@ -64,6 +64,13 @@ class Serializer {
64
64
  this.base = base;
65
65
  return this;
66
66
  }
67
+
68
+ /**
69
+ * Set serializer behavior flags. Letters can be combined with spaces.
70
+ * Examples: 'si', 'deinprstux', 'si dr', 'o'.
71
+ * Notable flags:
72
+ * - 'o': do not abbreviate to a prefixed name when the local part contains a dot
73
+ */
67
74
  setFlags(flags) {
68
75
  this.flags = flags || '';
69
76
  return this;
@@ -254,6 +261,28 @@ class Serializer {
254
261
  toN3(f) {
255
262
  return this.statementsToN3(f.statements);
256
263
  }
264
+ // Validate if a string is a valid PN_LOCAL per Turtle 1.1 spec
265
+ // Allows dots inside the local name but not as trailing character
266
+ // Also allows empty local names (for URIs ending in / or #)
267
+ isValidPNLocal(local) {
268
+ // Empty local name is valid (e.g., ex: for http://example.com/)
269
+ if (local.length === 0) return true;
270
+
271
+ // Cannot end with a dot
272
+ if (local[local.length - 1] === '.') return false;
273
+
274
+ // Check each character (allow dots mid-string)
275
+ for (var i = 0; i < local.length; i++) {
276
+ var ch = local[i];
277
+ // Dot is allowed unless it's the last character (checked above)
278
+ if (ch === '.') continue;
279
+ // Other characters must not be in the blacklist
280
+ if (this._notNameChars.indexOf(ch) >= 0) {
281
+ return false;
282
+ }
283
+ }
284
+ return true;
285
+ }
257
286
  explicitURI(uri) {
258
287
  if (this.flags.indexOf('r') < 0 && this.base) {
259
288
  uri = Uri.refTo(this.base, uri);
@@ -616,13 +645,17 @@ class Serializer {
616
645
  if (j >= 0 && this.flags.indexOf('p') < 0 && (
617
646
  // Can split at namespace but only if http[s]: URI or file: or ws[s] (why not others?)
618
647
  uri.indexOf('http') === 0 || uri.indexOf('ws') === 0 || uri.indexOf('file') === 0)) {
619
- var canSplit = true;
620
- for (var k = j + 1; k < uri.length; k++) {
621
- if (this._notNameChars.indexOf(uri[k]) >= 0) {
622
- canSplit = false;
623
- break;
624
- }
625
- }
648
+ var localid = uri.slice(j + 1);
649
+ var namesp = uri.slice(0, j + 1);
650
+ // Don't split if namespace is just the protocol (e.g., https://)
651
+ // A valid namespace should have content after the protocol
652
+ var minNamespaceLength = uri.indexOf('://') + 4; // e.g., "http://x" minimum
653
+ // Also don't split if namespace is the base directory (would serialize as relative URI)
654
+ var baseDir = this.base ? this.base.slice(0, Math.max(this.base.lastIndexOf('/'), this.base.lastIndexOf('#')) + 1) : null;
655
+ var namespaceIsBaseDir = baseDir && namesp === baseDir;
656
+ // If flag 'o' is present, forbid dots in local part when abbreviating
657
+ var forbidDotLocal = this.flags.indexOf('o') >= 0 && localid.indexOf('.') >= 0;
658
+ var canSplit = !namespaceIsBaseDir && !forbidDotLocal && namesp.length > minNamespaceLength && this.isValidPNLocal(localid);
626
659
  /*
627
660
  if (uri.slice(0, j + 1) === this.base + '#') { // base-relative
628
661
  if (canSplit) {
@@ -633,8 +666,6 @@ class Serializer {
633
666
  }
634
667
  */
635
668
  if (canSplit) {
636
- var localid = uri.slice(j + 1);
637
- var namesp = uri.slice(0, j + 1);
638
669
  if (this.defaultNamespace && this.defaultNamespace === namesp && this.flags.indexOf('d') < 0) {
639
670
  // d -> suppress default
640
671
  if (this.flags.indexOf('k') >= 0 && this.keyords.indexOf(localid) < 0) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "rdflib",
3
3
  "description": "an RDF library for node.js. Suitable for client and server side.",
4
- "version": "2.3.0-1c284ee8",
4
+ "version": "2.3.0-344dec99",
5
5
  "private": false,
6
6
  "browserslist": [
7
7
  "> 0.5%"
@@ -117,6 +117,7 @@
117
117
  "test:serialize:14": "cd ./tests/serialize && node ./data.js -in=t14.html -format=text/turtle -out=,t14.ttl && node diff ,t14.ttl t14-ref.ttl",
118
118
  "test:serialize:15": "cd ./tests/serialize && node ./data.js -in=t15.html -format=text/turtle -out=,t15.ttl && node diff ,t15.ttl t15-ref.ttl",
119
119
  "test:serialize:16": "cd ./tests/serialize && node ./data.js -in=t1.ttl -format=application/ld+json -out=,t1.jsonld && node diff ,t1.jsonld t16-ref.jsonld",
120
+ "test:serialize:17": "cd ./tests/serialize && node ./data.js -in=t17.ttl -format=application/rdf+xml -out=,t17.xml && node diff ,t17.xml t17-ref.xml",
120
121
  "test:types": "tsc --noEmit --target es2019 --moduleResolution node tests/types/*.ts",
121
122
  "test:unit": "mocha --growl --require ./tests/babel-register.js tests/unit/**-test.*",
122
123
  "test:unit:egp": "mocha --require ./tests/babel-register.js tests/unit/fetcher-egp-test.js",
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
- sz.setFlags('si') // Suppress = for sameAs and => for implies
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
- sz.setFlags('si dr') // turtle + dr (means no default, no relative prefix)
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
@@ -52,6 +52,12 @@ export class Serializer {
52
52
  return this
53
53
  }
54
54
 
55
+ /**
56
+ * Set serializer behavior flags. Letters can be combined with spaces.
57
+ * Examples: 'si', 'deinprstux', 'si dr', 'o'.
58
+ * Notable flags:
59
+ * - 'o': do not abbreviate to a prefixed name when the local part contains a dot
60
+ */
55
61
  setFlags(flags) {
56
62
  this.flags = flags || '';
57
63
  return this
@@ -251,10 +257,33 @@ export class Serializer {
251
257
  return this.statementsToN3(f.statements)
252
258
  }
253
259
 
254
- _notQNameChars = '\t\r\n !"#$%&\'()*.,+/;<=>?@[\\]^`{|}~' // issue#228
260
+ _notQNameChars = '\t\r\n !"#$%&\'()*,+/;<=>?@[\\]^`{|}~' // issue#228
255
261
  _notNameChars =
256
262
  (this._notQNameChars + ':')
257
263
 
264
+ // Validate if a string is a valid PN_LOCAL per Turtle 1.1 spec
265
+ // Allows dots inside the local name but not as trailing character
266
+ // Also allows empty local names (for URIs ending in / or #)
267
+ isValidPNLocal(local) {
268
+ // Empty local name is valid (e.g., ex: for http://example.com/)
269
+ if (local.length === 0) return true
270
+
271
+ // Cannot end with a dot
272
+ if (local[local.length - 1] === '.') return false
273
+
274
+ // Check each character (allow dots mid-string)
275
+ for (var i = 0; i < local.length; i++) {
276
+ var ch = local[i]
277
+ // Dot is allowed unless it's the last character (checked above)
278
+ if (ch === '.') continue
279
+ // Other characters must not be in the blacklist
280
+ if (this._notNameChars.indexOf(ch) >= 0) {
281
+ return false
282
+ }
283
+ }
284
+ return true
285
+ }
286
+
258
287
  explicitURI(uri) {
259
288
  if (this.flags.indexOf('r') < 0 && this.base) {
260
289
  uri = Uri.refTo(this.base, uri)
@@ -628,13 +657,17 @@ export class Serializer {
628
657
  if (j >= 0 && this.flags.indexOf('p') < 0 &&
629
658
  // Can split at namespace but only if http[s]: URI or file: or ws[s] (why not others?)
630
659
  (uri.indexOf('http') === 0 || uri.indexOf('ws') === 0 || uri.indexOf('file') === 0)) {
631
- var canSplit = true
632
- for (var k = j + 1; k < uri.length; k++) {
633
- if (this._notNameChars.indexOf(uri[k]) >= 0) {
634
- canSplit = false
635
- break
636
- }
637
- }
660
+ var localid = uri.slice(j + 1)
661
+ var namesp = uri.slice(0, j + 1)
662
+ // Don't split if namespace is just the protocol (e.g., https://)
663
+ // A valid namespace should have content after the protocol
664
+ var minNamespaceLength = uri.indexOf('://') + 4 // e.g., "http://x" minimum
665
+ // Also don't split if namespace is the base directory (would serialize as relative URI)
666
+ var baseDir = this.base ? this.base.slice(0, Math.max(this.base.lastIndexOf('/'), this.base.lastIndexOf('#')) + 1) : null
667
+ var namespaceIsBaseDir = baseDir && namesp === baseDir
668
+ // If flag 'o' is present, forbid dots in local part when abbreviating
669
+ var forbidDotLocal = this.flags.indexOf('o') >= 0 && localid.indexOf('.') >= 0
670
+ var canSplit = !namespaceIsBaseDir && !forbidDotLocal && namesp.length > minNamespaceLength && this.isValidPNLocal(localid)
638
671
  /*
639
672
  if (uri.slice(0, j + 1) === this.base + '#') { // base-relative
640
673
  if (canSplit) {
@@ -645,8 +678,6 @@ export class Serializer {
645
678
  }
646
679
  */
647
680
  if (canSplit) {
648
- var localid = uri.slice(j + 1)
649
- var namesp = uri.slice(0, j + 1)
650
681
  if (this.defaultNamespace && this.defaultNamespace === namesp &&
651
682
  this.flags.indexOf('d') < 0) { // d -> suppress default
652
683
  if (this.flags.indexOf('k') >= 0 &&