rdflib 2.3.0 → 2.3.1

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/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 !"#$%&\'()*.,+/;<=>?@[\\]^`{|}~'
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 &&