rdflib 2.3.0 → 2.3.1-07daeac2

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/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
@@ -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 NamedNode from './named-node'
9
- import BlankNode from './blank-node'
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) {
@@ -39,7 +37,7 @@ export class Serializer {
39
37
 
40
38
  this.namespacesUsed = [] // Count actually used and so needed in @prefixes
41
39
  this.keywords = ['a'] // The only one we generate at the moment
42
- this.prefixchars = 'abcdefghijklmnopqustuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
40
+ this.prefixchars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
43
41
  this.incoming = null // Array not calculated yet
44
42
  this.formulas = [] // remembering original formulae from hashes
45
43
  this.store = 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
@@ -170,7 +174,7 @@ export class Serializer {
170
174
  if (slash >= 0) p = p.slice(slash + 1)
171
175
  var i = 0
172
176
  while (i < p.length) {
173
- if (this.prefixchars.indexOf(p[i])) {
177
+ if (this.prefixchars.indexOf(p[i]) >= 0) {
174
178
  i++
175
179
  } else {
176
180
  break
@@ -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 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
- }
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.datatype.equals(this.xsd.string)
887
- ? ''
888
- : ' rdf:datatype="' + escapeForXML(st.object.datatype.uri) + '"') +
889
- (st.object.language ? ' xml:lang="' + st.object.language + '"' : '') +
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.datatype.equals(this.xsd.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.value) + '"') +
953
- (st.object.language ? ' xml:lang="' + st.object.language + '"' : '') +
954
- '>' + escapeForXML(st.object.value) +
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':
@@ -1 +0,0 @@
1
- (self.webpackChunk$rdf=self.webpackChunk$rdf||[]).push([[789],{7789:()=>{}}]);