rdflib 2.2.20 → 2.2.21-23b2ead1

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.
Files changed (123) hide show
  1. package/dist/rdflib.min.js +1 -1
  2. package/dist/rdflib.min.js.LICENSE.txt +9 -1
  3. package/dist/rdflib.min.js.map +1 -1
  4. package/esm/blank-node.js +61 -114
  5. package/esm/class-order.js +1 -1
  6. package/esm/collection.js +70 -126
  7. package/esm/default-graph.js +14 -48
  8. package/esm/empty.js +8 -39
  9. package/esm/factories/canonical-data-factory.js +33 -65
  10. package/esm/factories/extended-term-factory.js +18 -25
  11. package/esm/factories/factory-types.js +3 -2
  12. package/esm/factories/rdflib-data-factory.js +9 -19
  13. package/esm/fetcher.js +1341 -1854
  14. package/esm/formula.js +639 -846
  15. package/esm/index.js +40 -77
  16. package/esm/jsonldparser.js +34 -50
  17. package/esm/jsonparser.js +1 -8
  18. package/esm/lists.js +105 -0
  19. package/esm/literal.js +120 -189
  20. package/esm/log.js +7 -7
  21. package/esm/n3parser.js +1015 -1412
  22. package/esm/named-node.js +70 -119
  23. package/esm/namespace.js +2 -5
  24. package/esm/node-internal.js +73 -110
  25. package/esm/node.js +2 -7
  26. package/esm/parse.js +12 -19
  27. package/esm/patch-parser.js +10 -30
  28. package/esm/query-to-sparql.js +0 -18
  29. package/esm/query.js +63 -147
  30. package/esm/rdfaparser.js +794 -997
  31. package/esm/rdfxmlparser.js +347 -461
  32. package/esm/serialize.js +7 -33
  33. package/esm/serializer.js +886 -1036
  34. package/esm/sparql-to-query.js +44 -134
  35. package/esm/statement.js +54 -78
  36. package/esm/store.js +831 -1102
  37. package/esm/types.js +22 -21
  38. package/esm/update-manager.js +869 -1104
  39. package/esm/updates-via.js +104 -161
  40. package/esm/uri.js +9 -53
  41. package/esm/utils/default-graph-uri.js +3 -2
  42. package/esm/utils/termValue.js +0 -1
  43. package/esm/utils/terms.js +28 -19
  44. package/esm/utils-js.js +20 -61
  45. package/esm/utils.js +10 -21
  46. package/esm/variable.js +32 -78
  47. package/esm/xsd.js +2 -2
  48. package/lib/blank-node.js +60 -113
  49. package/lib/class-order.js +1 -2
  50. package/lib/collection.js +69 -129
  51. package/lib/default-graph.js +13 -52
  52. package/lib/empty.js +8 -43
  53. package/lib/factories/canonical-data-factory.js +35 -79
  54. package/lib/factories/extended-term-factory.js +18 -32
  55. package/lib/factories/factory-types.d.ts +6 -6
  56. package/lib/factories/factory-types.js +1 -4
  57. package/lib/factories/rdflib-data-factory.js +9 -23
  58. package/lib/fetcher.d.ts +6 -6
  59. package/lib/fetcher.js +1370 -1843
  60. package/lib/formula.d.ts +1 -1
  61. package/lib/formula.js +640 -855
  62. package/lib/index.d.ts +1 -2
  63. package/lib/index.js +67 -156
  64. package/lib/jsonldparser.js +33 -54
  65. package/lib/jsonparser.js +1 -10
  66. package/lib/lists.d.ts +13 -0
  67. package/lib/lists.js +113 -0
  68. package/lib/literal.js +120 -195
  69. package/lib/log.d.ts +0 -6
  70. package/lib/log.js +7 -8
  71. package/lib/n3parser.js +1030 -1436
  72. package/lib/named-node.js +69 -126
  73. package/lib/namespace.js +2 -7
  74. package/lib/node-internal.js +74 -107
  75. package/lib/node.js +2 -12
  76. package/lib/parse.d.ts +1 -1
  77. package/lib/parse.js +12 -32
  78. package/lib/patch-parser.js +11 -34
  79. package/lib/query-to-sparql.js +0 -23
  80. package/lib/query.js +62 -167
  81. package/lib/rdfaparser.js +796 -1009
  82. package/lib/rdfxmlparser.js +349 -466
  83. package/lib/serialize.d.ts +1 -1
  84. package/lib/serialize.js +7 -43
  85. package/lib/serializer.d.ts +1 -0
  86. package/lib/serializer.js +889 -1051
  87. package/lib/sparql-to-query.js +42 -167
  88. package/lib/statement.js +55 -84
  89. package/lib/store.d.ts +2 -2
  90. package/lib/store.js +850 -1112
  91. package/lib/tf-types.d.ts +4 -4
  92. package/lib/types.d.ts +8 -8
  93. package/lib/types.js +23 -23
  94. package/lib/update-manager.d.ts +1 -1
  95. package/lib/update-manager.js +865 -1101
  96. package/lib/updates-via.js +105 -164
  97. package/lib/uri.js +8 -61
  98. package/lib/utils/default-graph-uri.js +3 -5
  99. package/lib/utils/termValue.js +0 -2
  100. package/lib/utils/terms.d.ts +6 -1
  101. package/lib/utils/terms.js +29 -35
  102. package/lib/utils-js.js +23 -88
  103. package/lib/utils.js +10 -27
  104. package/lib/variable.js +34 -85
  105. package/lib/xsd-internal.js +0 -3
  106. package/lib/xsd.js +2 -6
  107. package/package.json +38 -40
  108. package/src/collection.ts +2 -0
  109. package/src/fetcher.ts +2 -2
  110. package/src/index.ts +0 -2
  111. package/src/jsonldparser.js +13 -4
  112. package/src/lists.ts +121 -0
  113. package/src/serialize.ts +2 -10
  114. package/src/serializer.js +78 -0
  115. package/src/statement.ts +7 -0
  116. package/src/store.ts +7 -7
  117. package/src/update-manager.ts +15 -9
  118. package/src/utils/terms.ts +23 -1
  119. package/changes.txt +0 -59
  120. package/esm/convert.js +0 -61
  121. package/lib/convert.d.ts +0 -2
  122. package/lib/convert.js +0 -77
  123. package/src/convert.js +0 -70
package/lib/serializer.js CHANGED
@@ -1,39 +1,22 @@
1
1
  "use strict";
2
2
 
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
-
5
- var _typeof = require("@babel/runtime/helpers/typeof");
6
-
7
4
  Object.defineProperty(exports, "__esModule", {
8
5
  value: true
9
6
  });
10
7
  exports.Serializer = void 0;
11
8
  exports.default = createSerializer;
12
-
13
- var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
14
-
15
- var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
16
-
17
9
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
18
-
19
10
  var _namedNode = _interopRequireDefault(require("./named-node"));
20
-
21
11
  var _blankNode = _interopRequireDefault(require("./blank-node"));
22
-
23
12
  var Uri = _interopRequireWildcard(require("./uri"));
24
-
25
13
  var Util = _interopRequireWildcard(require("./utils-js"));
26
-
27
14
  var _canonicalDataFactory = _interopRequireDefault(require("./factories/canonical-data-factory"));
28
-
29
15
  var _xsd = require("./xsd");
30
-
31
16
  var _solidNamespace = _interopRequireDefault(require("solid-namespace"));
32
-
33
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
34
-
35
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
36
-
17
+ var jsonld = _interopRequireWildcard(require("jsonld"));
18
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
19
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
37
20
  /* Serialization of RDF Graphs
38
21
  **
39
22
  ** Tim Berners-Lee 2006
@@ -41,15 +24,13 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
41
24
  ** This is or was https://github.com/linkeddata/rdflib.js/blob/main/src/serializer.js
42
25
  ** Licence: MIT
43
26
  */
27
+
44
28
  function createSerializer(store) {
45
29
  return new Serializer(store);
46
30
  }
47
-
48
31
  ;
49
-
50
- var Serializer = /*#__PURE__*/function () {
51
- function Serializer(store) {
52
- (0, _classCallCheck2.default)(this, Serializer);
32
+ class Serializer {
33
+ constructor(store) {
53
34
  (0, _defineProperty2.default)(this, "_notQNameChars", '\t\r\n !"#$%&\'()*.,+/;<=>?@[\\]^`{|}~');
54
35
  (0, _defineProperty2.default)(this, "_notNameChars", this._notQNameChars + ':');
55
36
  (0, _defineProperty2.default)(this, "validPrefix", new RegExp(/^[a-zA-Z][a-zA-Z0-9]*$/));
@@ -58,1182 +39,1039 @@ var Serializer = /*#__PURE__*/function () {
58
39
  this.flags = '';
59
40
  this.base = null;
60
41
  this.prefixes = []; // suggested prefixes
61
-
62
42
  this.namespaces = []; // complementary
63
-
64
- var nsKeys = Object.keys((0, _solidNamespace.default)());
65
-
66
- for (var i in nsKeys) {
67
- var uri = (0, _solidNamespace.default)()[nsKeys[i]]('');
68
- var prefix = nsKeys[i];
43
+ const nsKeys = Object.keys((0, _solidNamespace.default)());
44
+ for (const i in nsKeys) {
45
+ const uri = (0, _solidNamespace.default)()[nsKeys[i]]('');
46
+ const prefix = nsKeys[i];
69
47
  this.prefixes[uri] = prefix;
70
48
  this.namespaces[prefix] = uri;
71
49
  }
72
-
73
50
  this.suggestPrefix('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'); // XML code assumes this!
74
-
75
51
  this.suggestPrefix('xml', 'reserved:reservedForFutureUse'); // XML reserves xml: in the spec.
76
52
 
77
53
  this.namespacesUsed = []; // Count actually used and so needed in @prefixes
78
-
79
54
  this.keywords = ['a']; // The only one we generate at the moment
80
-
81
55
  this.prefixchars = 'abcdefghijklmnopqustuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
82
56
  this.incoming = null; // Array not calculated yet
83
-
84
57
  this.formulas = []; // remembering original formulae from hashes
85
-
86
58
  this.store = store;
87
59
  this.rdfFactory = store.rdfFactory || _canonicalDataFactory.default;
88
60
  this.xsd = (0, _xsd.createXSD)(this.rdfFactory);
89
61
  }
62
+ setBase(base) {
63
+ this.base = base;
64
+ return this;
65
+ }
66
+ setFlags(flags) {
67
+ this.flags = flags || '';
68
+ return this;
69
+ }
70
+ toStr(x) {
71
+ var s = x.toNT();
72
+ if (x.termType === 'Graph') {
73
+ this.formulas[s] = x; // remember as reverse does not work
74
+ }
90
75
 
91
- (0, _createClass2.default)(Serializer, [{
92
- key: "setBase",
93
- value: function setBase(base) {
94
- this.base = base;
95
- return this;
76
+ return s;
77
+ }
78
+ fromStr(s) {
79
+ if (s[0] === '{') {
80
+ var x = this.formulas[s];
81
+ if (!x) console.log('No formula object for ' + s);
82
+ return x;
96
83
  }
97
- }, {
98
- key: "setFlags",
99
- value: function setFlags(flags) {
100
- this.flags = flags || '';
101
- return this;
84
+ return this.store.fromNT(s);
85
+ }
86
+
87
+ /**
88
+ * Defines a set of [prefix, namespace] pairs to be used by this Serializer instance.
89
+ * Overrides previous prefixes if any
90
+ * @param namespaces
91
+ * @return {Serializer}
92
+ */
93
+ setNamespaces(namespaces) {
94
+ for (var px in namespaces) {
95
+ this.setPrefix(px, namespaces[px]);
102
96
  }
103
- }, {
104
- key: "toStr",
105
- value: function toStr(x) {
106
- var s = x.toNT();
97
+ return this;
98
+ }
107
99
 
108
- if (x.termType === 'Graph') {
109
- this.formulas[s] = x; // remember as reverse does not work
110
- }
100
+ /**
101
+ * Defines a namespace prefix, overriding any existing prefix for that URI
102
+ * @param prefix
103
+ * @param uri
104
+ */
105
+ setPrefix(prefix, uri) {
106
+ if (prefix.slice(0, 7) === 'default') return; // Try to weed these out
107
+ if (prefix.slice(0, 2) === 'ns') return; // From others inferior algos
108
+ if (!prefix || !uri) return; // empty strings not suitable
109
+
110
+ // remove any existing prefix targeting this uri
111
+ // for (let existingPrefix in this.namespaces) {
112
+ // if (this.namespaces[existingPrefix] == uri)
113
+ // delete this.namespaces[existingPrefix];
114
+ // }
115
+
116
+ // remove any existing mapping for this prefix
117
+ for (let existingNs in this.prefixes) {
118
+ if (this.prefixes[existingNs] == prefix) delete this.prefixes[existingNs];
119
+ }
120
+ this.prefixes[uri] = prefix;
121
+ this.namespaces[prefix] = uri;
122
+ }
111
123
 
112
- return s;
124
+ /* Accumulate Namespaces
125
+ **
126
+ ** These are only hints. If two overlap, only one gets used
127
+ ** There is therefore no guarantee in general.
128
+ */
129
+ suggestPrefix(prefix, uri) {
130
+ if (prefix.slice(0, 7) === 'default') return; // Try to weed these out
131
+ if (prefix.slice(0, 2) === 'ns') return; // From others inferior algos
132
+ if (!prefix || !uri) return; // empty strings not suitable
133
+ if (prefix in this.namespaces || uri in this.prefixes) return; // already used
134
+ this.prefixes[uri] = prefix;
135
+ this.namespaces[prefix] = uri;
136
+ }
137
+
138
+ // Takes a namespace -> prefix map
139
+ suggestNamespaces(namespaces) {
140
+ for (var px in namespaces) {
141
+ this.suggestPrefix(px, namespaces[px]);
113
142
  }
114
- }, {
115
- key: "fromStr",
116
- value: function fromStr(s) {
117
- if (s[0] === '{') {
118
- var x = this.formulas[s];
119
- if (!x) console.log('No formula object for ' + s);
120
- return x;
143
+ return this;
144
+ }
145
+ checkIntegrity() {
146
+ var p, ns;
147
+ for (p in this.namespaces) {
148
+ if (this.prefixes[this.namespaces[p]] !== p) {
149
+ throw new Error('Serializer integity error 1: ' + p + ', ' + this.namespaces[p] + ', ' + this.prefixes[this.namespaces[p]] + '!');
121
150
  }
122
-
123
- return this.store.fromNT(s);
124
151
  }
125
- /**
126
- * Defines a set of [prefix, namespace] pairs to be used by this Serializer instance.
127
- * Overrides previous prefixes if any
128
- * @param namespaces
129
- * @return {Serializer}
130
- */
131
-
132
- }, {
133
- key: "setNamespaces",
134
- value: function setNamespaces(namespaces) {
135
- for (var px in namespaces) {
136
- this.setPrefix(px, namespaces[px]);
152
+ for (ns in this.prefixes) {
153
+ if (this.namespaces[this.prefixes[ns]] !== ns) {
154
+ throw new Error('Serializer integity error 2: ' + ns + ', ' + this.prefixs[ns] + ', ' + this.namespaces[this.prefixes[ns]] + '!');
137
155
  }
138
-
139
- return this;
140
156
  }
141
- /**
142
- * Defines a namespace prefix, overriding any existing prefix for that URI
143
- * @param prefix
144
- * @param uri
145
- */
146
-
147
- }, {
148
- key: "setPrefix",
149
- value: function setPrefix(prefix, uri) {
150
- if (prefix.slice(0, 7) === 'default') return; // Try to weed these out
151
-
152
- if (prefix.slice(0, 2) === 'ns') return; // From others inferior algos
153
-
154
- if (!prefix || !uri) return; // empty strings not suitable
155
- // remove any existing prefix targeting this uri
156
- // for (let existingPrefix in this.namespaces) {
157
- // if (this.namespaces[existingPrefix] == uri)
158
- // delete this.namespaces[existingPrefix];
159
- // }
160
- // remove any existing mapping for this prefix
157
+ }
161
158
 
162
- for (var existingNs in this.prefixes) {
163
- if (this.prefixes[existingNs] == prefix) delete this.prefixes[existingNs];
159
+ // Make up an unused prefix for a random namespace
160
+ makeUpPrefix(uri) {
161
+ var p = uri;
162
+ function canUseMethod(pp) {
163
+ if (!this.validPrefix.test(pp)) return false; // bad format
164
+ if (pp === 'ns') return false; // boring
165
+ if (pp in this.namespaces) return false; // already used
166
+ this.prefixes[uri] = pp;
167
+ this.namespaces[pp] = uri;
168
+ return pp;
169
+ }
170
+ var canUse = canUseMethod.bind(this);
171
+ if ('#/'.indexOf(p[p.length - 1]) >= 0) p = p.slice(0, -1);
172
+ var slash = p.lastIndexOf('/');
173
+ if (slash >= 0) p = p.slice(slash + 1);
174
+ var i = 0;
175
+ while (i < p.length) {
176
+ if (this.prefixchars.indexOf(p[i])) {
177
+ i++;
178
+ } else {
179
+ break;
164
180
  }
165
-
166
- this.prefixes[uri] = prefix;
167
- this.namespaces[prefix] = uri;
168
181
  }
169
- /* Accumulate Namespaces
170
- **
171
- ** These are only hints. If two overlap, only one gets used
172
- ** There is therefore no guarantee in general.
173
- */
174
-
175
- }, {
176
- key: "suggestPrefix",
177
- value: function suggestPrefix(prefix, uri) {
178
- if (prefix.slice(0, 7) === 'default') return; // Try to weed these out
179
-
180
- if (prefix.slice(0, 2) === 'ns') return; // From others inferior algos
182
+ p = p.slice(0, i);
183
+ if (p.length < 6 && canUse(p)) return p; // exact is best
184
+ if (canUse(p.slice(0, 3))) return p.slice(0, 3);
185
+ if (canUse(p.slice(0, 2))) return p.slice(0, 2);
186
+ if (canUse(p.slice(0, 4))) return p.slice(0, 4);
187
+ if (canUse(p.slice(0, 1))) return p.slice(0, 1);
188
+ if (canUse(p.slice(0, 5))) return p.slice(0, 5);
189
+ if (!this.validPrefix.test(p)) {
190
+ p = 'n'; // Otherwise the loop below may never termimnate
191
+ }
181
192
 
182
- if (!prefix || !uri) return; // empty strings not suitable
193
+ for (var j = 0;; j++) if (canUse(p.slice(0, 3) + j)) return p.slice(0, 3) + j;
194
+ }
195
+ rootSubjects(sts) {
196
+ var incoming = {};
197
+ var subjects = {};
198
+ var allBnodes = {};
199
+
200
+ /* This scan is to find out which nodes will have to be the roots of trees
201
+ ** in the serialized form. This will be any symbols, and any bnodes
202
+ ** which hve more or less than one incoming arc, and any bnodes which have
203
+ ** one incoming arc but it is an uninterrupted loop of such nodes back to itself.
204
+ ** This should be kept linear time with repect to the number of statements.
205
+ ** Note it does not use any indexing of the store.
206
+ */
207
+ for (var i = 0; i < sts.length; i++) {
208
+ var st = sts[i];
209
+ var checkMentions = function (x) {
210
+ if (!incoming.hasOwnProperty(x)) incoming[x] = [];
211
+ incoming[x].push(st.subject); // List of things which will cause this to be printed
212
+ };
183
213
 
184
- if (prefix in this.namespaces || uri in this.prefixes) return; // already used
214
+ var st2 = [st.subject, st.predicate, st.object];
215
+ st2.map(function (y) {
216
+ if (y.termType === 'BlankNode') {
217
+ allBnodes[y.toNT()] = true;
218
+ } else if (y.termType === 'Collection') {
219
+ y.elements.forEach(function (z) {
220
+ checkMentions(z); // bnodes in collections important
221
+ });
222
+ }
223
+ });
185
224
 
186
- this.prefixes[uri] = prefix;
187
- this.namespaces[prefix] = uri;
188
- } // Takes a namespace -> prefix map
225
+ checkMentions(sts[i].object);
226
+ var ss = subjects[this.toStr(st.subject)]; // Statements with this as subject
227
+ if (!ss) ss = [];
228
+ ss.push(st);
229
+ subjects[this.toStr(st.subject)] = ss; // Make hash. @@ too slow for formula?
230
+ }
189
231
 
190
- }, {
191
- key: "suggestNamespaces",
192
- value: function suggestNamespaces(namespaces) {
193
- for (var px in namespaces) {
194
- this.suggestPrefix(px, namespaces[px]);
232
+ var roots = [];
233
+ for (var xNT in subjects) {
234
+ if (!subjects.hasOwnProperty(xNT)) continue;
235
+ var y = this.fromStr(xNT);
236
+ if (y.termType !== 'BlankNode' || !incoming[y] || incoming[y].length !== 1) {
237
+ roots.push(y);
238
+ continue;
195
239
  }
240
+ }
241
+ this.incoming = incoming; // Keep for serializing @@ Bug for nested formulas
196
242
 
197
- return this;
243
+ // Now do the scan using existing roots
244
+ var rootsHash = {};
245
+ for (var k = 0; k < roots.length; k++) {
246
+ rootsHash[roots[k].toNT()] = true;
198
247
  }
199
- }, {
200
- key: "checkIntegrity",
201
- value: function checkIntegrity() {
202
- var p, ns;
248
+ return {
249
+ 'roots': roots,
250
+ 'subjects': subjects,
251
+ 'rootsHash': rootsHash,
252
+ 'incoming': incoming
253
+ };
254
+ }
203
255
 
204
- for (p in this.namespaces) {
205
- if (this.prefixes[this.namespaces[p]] !== p) {
206
- throw new Error('Serializer integity error 1: ' + p + ', ' + this.namespaces[p] + ', ' + this.prefixes[this.namespaces[p]] + '!');
207
- }
208
- }
256
+ // //////////////////////////////////////////////////////
209
257
 
210
- for (ns in this.prefixes) {
211
- if (this.namespaces[this.prefixes[ns]] !== ns) {
212
- throw new Error('Serializer integity error 2: ' + ns + ', ' + this.prefixs[ns] + ', ' + this.namespaces[this.prefixes[ns]] + '!');
213
- }
258
+ toN3(f) {
259
+ return this.statementsToN3(f.statements);
260
+ }
261
+ explicitURI(uri) {
262
+ if (this.flags.indexOf('r') < 0 && this.base) {
263
+ uri = Uri.refTo(this.base, uri);
264
+ } else if (this.flags.indexOf('u') >= 0) {
265
+ // Unicode encoding NTriples style
266
+ uri = backslashUify(uri);
267
+ } else {
268
+ uri = hexify(uri);
269
+ }
270
+ return '<' + uri + '>';
271
+ }
272
+ statementsToNTriples(sts) {
273
+ var sorted = sts.slice();
274
+ sorted.sort();
275
+ var str = '';
276
+ var rdfns = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
277
+ var self = this;
278
+ var kb = this.store;
279
+ var factory = this.rdfFactory;
280
+ var termToNT = function (x) {
281
+ if (x.termType !== 'Collection') {
282
+ return self.atomicTermToN3(x);
214
283
  }
215
- } // Make up an unused prefix for a random namespace
216
-
217
- }, {
218
- key: "makeUpPrefix",
219
- value: function makeUpPrefix(uri) {
220
- var p = uri;
221
-
222
- function canUseMethod(pp) {
223
- if (!this.validPrefix.test(pp)) return false; // bad format
224
-
225
- if (pp === 'ns') return false; // boring
284
+ var list = x.elements;
285
+ var rest = kb.sym(rdfns + 'nill');
286
+ for (var i = list.length - 1; i >= 0; i--) {
287
+ var bnode = factory.blankNode();
288
+ str += termToNT(bnode) + ' ' + termToNT(kb.sym(rdfns + 'first')) + ' ' + termToNT(list[i]) + '.\n';
289
+ str += termToNT(bnode) + ' ' + termToNT(kb.sym(rdfns + 'rest')) + ' ' + termToNT(rest) + '.\n';
290
+ rest = bnode;
291
+ }
292
+ return self.atomicTermToN3(rest);
293
+ };
294
+ for (var i = 0; i < sorted.length; i++) {
295
+ var st = sorted[i];
296
+ var s = '';
297
+ s += termToNT(st.subject) + ' ';
298
+ s += termToNT(st.predicate) + ' ';
299
+ s += termToNT(st.object) + ' ';
300
+ if (this.flags.indexOf('q') >= 0) {
301
+ // Do quads not nrtiples
302
+ s += termToNT(st.why) + ' ';
303
+ }
304
+ s += '.\n';
305
+ str += s;
306
+ }
307
+ return str;
308
+ }
309
+ statementsToN3(sts) {
310
+ var indent = 4;
311
+ var width = 80;
312
+ var kb = this.store;
313
+ // A URI Map alows us to put the type statemnts at the top.
314
+ var uriMap = {
315
+ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type': 'aaa:00'
316
+ };
317
+ var SPO = function (x, y) {
318
+ // Do limited canonicalization of bnodes
319
+ return Util.heavyCompareSPO(x, y, kb, uriMap);
320
+ };
321
+ sts.sort(SPO);
322
+ if (this.base && !this.defaultNamespace) {
323
+ this.defaultNamespace = this.base + '#';
324
+ }
325
+ var predMap = {};
326
+ if (this.flags.indexOf('s') < 0) {
327
+ predMap['http://www.w3.org/2002/07/owl#sameAs'] = '=';
328
+ }
329
+ if (this.flags.indexOf('t') < 0) {
330
+ predMap['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'] = 'a';
331
+ }
332
+ if (this.flags.indexOf('i') < 0) {
333
+ predMap['http://www.w3.org/2000/10/swap/log#implies'] = '=>';
334
+ }
335
+ // //////////////////////// Arrange the bits of text
226
336
 
227
- if (pp in this.namespaces) return false; // already used
337
+ var spaces = function (n) {
338
+ var s = '';
339
+ for (var i = 0; i < n; i++) s += ' ';
340
+ return s;
341
+ };
342
+ var treeToLine = function (tree) {
343
+ var str = '';
344
+ for (var i = 0; i < tree.length; i++) {
345
+ var branch = tree[i];
346
+ var s2 = typeof branch === 'string' ? branch : treeToLine(branch);
347
+ // Note the space before the dot in case statement ends with 123 or colon. which is in fact allowed but be conservative.
348
+ if (i !== 0) {
349
+ var ch = str.slice(-1) || ' ';
350
+ if (s2 === ',' || s2 === ';') {
351
+ // no gap
352
+ } else if (s2 === '.' && !'0123456789.:'.includes(ch)) {// no gap except after number and colon
353
+ // no gap
354
+ } else {
355
+ str += ' '; // separate from previous token
356
+ }
357
+ }
228
358
 
229
- this.prefixes[uri] = pp;
230
- this.namespaces[pp] = uri;
231
- return pp;
359
+ str += s2;
232
360
  }
361
+ return str;
362
+ };
233
363
 
234
- var canUse = canUseMethod.bind(this);
235
- if ('#/'.indexOf(p[p.length - 1]) >= 0) p = p.slice(0, -1);
236
- var slash = p.lastIndexOf('/');
237
- if (slash >= 0) p = p.slice(slash + 1);
238
- var i = 0;
239
-
240
- while (i < p.length) {
241
- if (this.prefixchars.indexOf(p[i])) {
242
- i++;
243
- } else {
244
- break;
364
+ // Convert a nested tree of lists and strings to a string
365
+ var treeToString = function (tree, level) {
366
+ var str = '';
367
+ var lastLength = 100000;
368
+ if (level === undefined) level = -1;
369
+ for (var i = 0; i < tree.length; i++) {
370
+ var branch = tree[i];
371
+ if (typeof branch !== 'string') {
372
+ var substr = treeToString(branch, level + 1);
373
+ if (substr.length < 10 * (width - indent * level) && substr.indexOf('"""') < 0) {
374
+ // Don't mess up multiline strings
375
+ var line = treeToLine(branch);
376
+ if (line.length < width - indent * level) {
377
+ branch = line; // Note! treat as string below
378
+ substr = '';
379
+ }
380
+ }
381
+ if (substr) lastLength = 10000;
382
+ str += substr;
383
+ }
384
+ if (typeof branch === 'string') {
385
+ if (branch.length === 1 && str.slice(-1) === '\n') {
386
+ if (',.;'.indexOf(branch) >= 0) {
387
+ str = str.slice(0, -1);
388
+ // be conservative and ensure a whitespace between some chars and a final dot, as in treeToLine above
389
+ if (branch == '.' && '0123456789.:'.includes(str.charAt(str.length - 1))) {
390
+ str += ' ';
391
+ lastLength += 1;
392
+ }
393
+ str += branch + '\n'; // slip punct'n on end
394
+ lastLength += 1;
395
+ continue;
396
+ }
397
+ }
398
+ if (lastLength < indent * level + 4 ||
399
+ // if new line not necessary
400
+ lastLength + branch.length + 1 < width && ';.'.indexOf(str[str.length - 2]) < 0) {
401
+ // or the string fits on last line
402
+ str = str.slice(0, -1) + ' ' + branch + '\n'; // then continue on this line
403
+ lastLength += branch.length + 1;
404
+ } else {
405
+ let line = spaces(indent * level) + branch;
406
+ str += line + '\n';
407
+ lastLength = line.length;
408
+ if (level < 0) {
409
+ str += '\n'; // extra blank line
410
+ lastLength = 100000; // don't touch
411
+ }
412
+ }
245
413
  }
246
414
  }
247
415
 
248
- p = p.slice(0, i);
249
- if (p.length < 6 && canUse(p)) return p; // exact is best
250
-
251
- if (canUse(p.slice(0, 3))) return p.slice(0, 3);
252
- if (canUse(p.slice(0, 2))) return p.slice(0, 2);
253
- if (canUse(p.slice(0, 4))) return p.slice(0, 4);
254
- if (canUse(p.slice(0, 1))) return p.slice(0, 1);
255
- if (canUse(p.slice(0, 5))) return p.slice(0, 5);
256
-
257
- if (!this.validPrefix.test(p)) {
258
- p = 'n'; // Otherwise the loop below may never termimnate
416
+ return str;
417
+ };
418
+
419
+ // //////////////////////////////////////////// Structure for N3
420
+ // Convert a set of statements into a nested tree of lists and strings
421
+ function statementListToTreeMethod(statements) {
422
+ var stats = this.rootSubjects(statements);
423
+ var roots = stats.roots;
424
+ var results = [];
425
+ for (var i = 0; i < roots.length; i++) {
426
+ var root = roots[i];
427
+ results.push(subjectTree(root, stats));
259
428
  }
429
+ return results;
430
+ }
431
+ var statementListToTree = statementListToTreeMethod.bind(this);
260
432
 
261
- for (var j = 0;; j++) {
262
- if (canUse(p.slice(0, 3) + j)) return p.slice(0, 3) + j;
433
+ // The tree for a subject
434
+ function subjectTree(subject, stats) {
435
+ if (subject.termType === 'BlankNode' && !stats.incoming[subject]) {
436
+ return objectTree(subject, stats, true).concat(['.']); // Anonymous bnode subject
263
437
  }
264
- }
265
- }, {
266
- key: "rootSubjects",
267
- value: function rootSubjects(sts) {
268
- var incoming = {};
269
- var subjects = {};
270
- var allBnodes = {};
271
- /* This scan is to find out which nodes will have to be the roots of trees
272
- ** in the serialized form. This will be any symbols, and any bnodes
273
- ** which hve more or less than one incoming arc, and any bnodes which have
274
- ** one incoming arc but it is an uninterrupted loop of such nodes back to itself.
275
- ** This should be kept linear time with repect to the number of statements.
276
- ** Note it does not use any indexing of the store.
277
- */
278
438
 
439
+ return [termToN3(subject, stats)].concat([propertyTree(subject, stats)]).concat(['.']);
440
+ }
441
+ // The property tree for a single subject or anonymous node
442
+ function propertyTreeMethod(subject, stats) {
443
+ var results = [];
444
+ var lastPred = null;
445
+ var sts = stats.subjects[this.toStr(subject)] || []; // relevant statements
446
+ if (typeof sts === 'undefined') {
447
+ throw new Error('Cant find statements for ' + subject);
448
+ }
449
+ var objects = [];
279
450
  for (var i = 0; i < sts.length; i++) {
280
451
  var st = sts[i];
281
-
282
- var checkMentions = function checkMentions(x) {
283
- if (!incoming.hasOwnProperty(x)) incoming[x] = [];
284
- incoming[x].push(st.subject); // List of things which will cause this to be printed
285
- };
286
-
287
- var st2 = [st.subject, st.predicate, st.object];
288
- st2.map(function (y) {
289
- if (y.termType === 'BlankNode') {
290
- allBnodes[y.toNT()] = true;
291
- } else if (y.termType === 'Collection') {
292
- y.elements.forEach(function (z) {
293
- checkMentions(z); // bnodes in collections important
294
- });
452
+ if (st.predicate.uri === lastPred) {
453
+ objects.push(',');
454
+ } else {
455
+ if (lastPred) {
456
+ results = results.concat([objects]).concat([';']);
457
+ objects = [];
295
458
  }
296
- });
297
- checkMentions(sts[i].object);
298
- var ss = subjects[this.toStr(st.subject)]; // Statements with this as subject
299
-
300
- if (!ss) ss = [];
301
- ss.push(st);
302
- subjects[this.toStr(st.subject)] = ss; // Make hash. @@ too slow for formula?
303
- }
304
-
305
- var roots = [];
306
-
307
- for (var xNT in subjects) {
308
- if (!subjects.hasOwnProperty(xNT)) continue;
309
- var y = this.fromStr(xNT);
310
-
311
- if (y.termType !== 'BlankNode' || !incoming[y] || incoming[y].length !== 1) {
312
- roots.push(y);
313
- continue;
459
+ results.push(predMap[st.predicate.uri] ? predMap[st.predicate.uri] : termToN3(st.predicate, stats));
314
460
  }
461
+ lastPred = st.predicate.uri;
462
+ objects.push(objectTree(st.object, stats));
315
463
  }
316
-
317
- this.incoming = incoming; // Keep for serializing @@ Bug for nested formulas
318
- // Now do the scan using existing roots
319
-
320
- var rootsHash = {};
321
-
322
- for (var k = 0; k < roots.length; k++) {
323
- rootsHash[roots[k].toNT()] = true;
464
+ results = results.concat([objects]);
465
+ return results;
466
+ }
467
+ var propertyTree = propertyTreeMethod.bind(this);
468
+ function objectTreeMethod(obj, stats, force) {
469
+ if (obj.termType === 'BlankNode' && (force || stats.rootsHash[obj.toNT()] === undefined)) {
470
+ // if not a root
471
+ if (stats.subjects[this.toStr(obj)]) {
472
+ return ['[', propertyTree(obj, stats), ']'];
473
+ } else {
474
+ return '[]';
475
+ }
324
476
  }
325
-
326
- return {
327
- 'roots': roots,
328
- 'subjects': subjects,
329
- 'rootsHash': rootsHash,
330
- 'incoming': incoming
331
- };
332
- } // //////////////////////////////////////////////////////
333
-
334
- }, {
335
- key: "toN3",
336
- value: function toN3(f) {
337
- return this.statementsToN3(f.statements);
477
+ return termToN3(obj, stats);
338
478
  }
339
- }, {
340
- key: "explicitURI",
341
- value: function explicitURI(uri) {
342
- if (this.flags.indexOf('r') < 0 && this.base) {
343
- uri = Uri.refTo(this.base, uri);
344
- } else if (this.flags.indexOf('u') >= 0) {
345
- // Unicode encoding NTriples style
346
- uri = backslashUify(uri);
347
- } else {
348
- uri = hexify(uri);
479
+ var objectTree = objectTreeMethod.bind(this);
480
+ function termToN3Method(expr, stats) {
481
+ //
482
+ var i, res;
483
+ switch (expr.termType) {
484
+ case 'Graph':
485
+ res = ['{'];
486
+ res = res.concat(statementListToTree(expr.statements));
487
+ return res.concat(['}']);
488
+ case 'Collection':
489
+ res = ['('];
490
+ for (i = 0; i < expr.elements.length; i++) {
491
+ res.push([objectTree(expr.elements[i], stats)]);
492
+ }
493
+ res.push(')');
494
+ return res;
495
+ default:
496
+ return this.atomicTermToN3(expr);
349
497
  }
350
-
351
- return '<' + uri + '>';
352
498
  }
353
- }, {
354
- key: "statementsToNTriples",
355
- value: function statementsToNTriples(sts) {
356
- var sorted = sts.slice();
357
- sorted.sort();
499
+ Serializer.prototype.termToN3 = termToN3;
500
+ var termToN3 = termToN3Method.bind(this);
501
+ function prefixDirectivesMethod() {
358
502
  var str = '';
359
- var rdfns = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
360
- var self = this;
361
- var kb = this.store;
362
- var factory = this.rdfFactory;
363
-
364
- var termToNT = function termToNT(x) {
365
- if (x.termType !== 'Collection') {
366
- return self.atomicTermToN3(x);
503
+ if (this.defaultNamespace) {
504
+ str += '@prefix : ' + this.explicitURI(this.defaultNamespace) + '.\n';
505
+ }
506
+ for (var ns in this.prefixes) {
507
+ if (!this.prefixes.hasOwnProperty(ns)) continue;
508
+ if (!this.namespacesUsed[ns]) continue;
509
+ str += '@prefix ' + this.prefixes[ns] + ': ' + this.explicitURI(ns) + '.\n';
510
+ }
511
+ return str + '\n';
512
+ }
513
+ var prefixDirectives = prefixDirectivesMethod.bind(this);
514
+ // Body of statementsToN3:
515
+ var tree = statementListToTree(sts);
516
+ return prefixDirectives() + treeToString(tree);
517
+ }
518
+ // //////////////////////////////////////////// Atomic Terms
519
+
520
+ // Deal with term level things and nesting with no bnode structure
521
+ atomicTermToN3(expr, stats) {
522
+ switch (expr.termType) {
523
+ case 'BlankNode':
524
+ case 'Variable':
525
+ return expr.toNT();
526
+ case 'Literal':
527
+ var val = expr.value;
528
+ if (typeof val !== 'string') {
529
+ throw new TypeError('Value of RDF literal node must be a string');
367
530
  }
368
-
369
- var list = x.elements;
370
- var rest = kb.sym(rdfns + 'nill');
371
-
372
- for (var i = list.length - 1; i >= 0; i--) {
373
- var bnode = factory.blankNode();
374
- str += termToNT(bnode) + ' ' + termToNT(kb.sym(rdfns + 'first')) + ' ' + termToNT(list[i]) + '.\n';
375
- str += termToNT(bnode) + ' ' + termToNT(kb.sym(rdfns + 'rest')) + ' ' + termToNT(rest) + '.\n';
376
- rest = bnode;
531
+ // var val = expr.value.toString() // should be a string already
532
+ if (expr.datatype && this.flags.indexOf('x') < 0) {
533
+ // Supress native numbers
534
+ switch (expr.datatype.uri) {
535
+ case 'http://www.w3.org/2001/XMLSchema#integer':
536
+ return val;
537
+ case 'http://www.w3.org/2001/XMLSchema#decimal':
538
+ // In Turtle, must have dot
539
+ if (val.indexOf('.') < 0) val += '.0';
540
+ return val;
541
+ case 'http://www.w3.org/2001/XMLSchema#double':
542
+ {
543
+ // Must force use of 'e'
544
+ const eNotation = val.toLowerCase().indexOf('e') > 0;
545
+ if (val.indexOf('.') < 0 && !eNotation) val += '.0';
546
+ if (!eNotation) val += 'e0';
547
+ return val;
548
+ }
549
+ case 'http://www.w3.org/2001/XMLSchema#boolean':
550
+ return expr.value === '1' ? 'true' : 'false';
551
+ }
377
552
  }
378
-
379
- return self.atomicTermToN3(rest);
380
- };
381
-
382
- for (var i = 0; i < sorted.length; i++) {
383
- var st = sorted[i];
384
- var s = '';
385
- s += termToNT(st.subject) + ' ';
386
- s += termToNT(st.predicate) + ' ';
387
- s += termToNT(st.object) + ' ';
388
-
389
- if (this.flags.indexOf('q') >= 0) {
390
- // Do quads not nrtiples
391
- s += termToNT(st.why) + ' ';
553
+ var str = this.stringToN3(expr.value);
554
+ if (expr.language) {
555
+ str += '@' + expr.language;
556
+ } else if (!expr.datatype.equals(this.xsd.string)) {
557
+ str += '^^' + this.atomicTermToN3(expr.datatype, stats);
392
558
  }
393
-
394
- s += '.\n';
395
- str += s;
396
- }
397
-
398
- return str;
559
+ return str;
560
+ case 'NamedNode':
561
+ return this.symbolToN3(expr);
562
+ case 'DefaultGraph':
563
+ return '';
564
+ default:
565
+ throw new Error('Internal: atomicTermToN3 cannot handle ' + expr + ' of termType: ' + expr.termType);
399
566
  }
400
- }, {
401
- key: "statementsToN3",
402
- value: function statementsToN3(sts) {
403
- var indent = 4;
404
- var width = 80;
405
- var kb = this.store; // A URI Map alows us to put the type statemnts at the top.
406
-
407
- var uriMap = {
408
- 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type': 'aaa:00'
409
- };
410
-
411
- var SPO = function SPO(x, y) {
412
- // Do limited canonicalization of bnodes
413
- return Util.heavyCompareSPO(x, y, kb, uriMap);
414
- };
415
-
416
- sts.sort(SPO);
417
-
418
- if (this.base && !this.defaultNamespace) {
419
- this.defaultNamespace = this.base + '#';
420
- }
421
-
422
- var predMap = {};
423
-
424
- if (this.flags.indexOf('s') < 0) {
425
- predMap['http://www.w3.org/2002/07/owl#sameAs'] = '=';
426
- }
567
+ }
427
568
 
428
- if (this.flags.indexOf('t') < 0) {
429
- predMap['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'] = 'a';
569
+ // stringToN3: String escaping for N3
570
+
571
+ stringToN3(str, flags) {
572
+ if (!flags) flags = 'e';
573
+ var res = '';
574
+ var i, j, k;
575
+ var delim;
576
+ var forbidden;
577
+ if (str.length > 20 &&
578
+ // Long enough to make sense
579
+ str.slice(-1) !== '"' &&
580
+ // corner case'
581
+ flags.indexOf('n') < 0 && (
582
+ // Force single line
583
+ str.indexOf('\n') > 0 || str.indexOf('"') > 0)) {
584
+ delim = '"""';
585
+ forbidden = this.forbidden3;
586
+ } else {
587
+ delim = '"';
588
+ forbidden = this.forbidden1;
589
+ }
590
+ for (i = 0; i < str.length;) {
591
+ forbidden.lastIndex = 0;
592
+ var m = forbidden.exec(str.slice(i));
593
+ if (m == null) break;
594
+ j = i + forbidden.lastIndex - 1;
595
+ res += str.slice(i, j);
596
+ var ch = str[j];
597
+ if (ch === '"' && delim === '"""' && str.slice(j, j + 3) !== '"""') {
598
+ res += ch;
599
+ } else {
600
+ k = '\b\f\r\t\v\n\\"'.indexOf(ch); // No escaping of bell (7)?
601
+ if (k >= 0) {
602
+ res += '\\' + 'bfrtvn\\"'[k];
603
+ } else {
604
+ if (flags.indexOf('e') >= 0) {
605
+ // Unicode escaping in strings not unix style
606
+ res += '\\u' + ('000' + ch.charCodeAt(0).toString(16).toLowerCase()).slice(-4);
607
+ } else {
608
+ // no 'e' flag
609
+ res += ch;
610
+ }
611
+ }
430
612
  }
431
-
432
- if (this.flags.indexOf('i') < 0) {
433
- predMap['http://www.w3.org/2000/10/swap/log#implies'] = '=>';
434
- } // //////////////////////// Arrange the bits of text
435
-
436
-
437
- var spaces = function spaces(n) {
438
- var s = '';
439
-
440
- for (var i = 0; i < n; i++) {
441
- s += ' ';
613
+ i = j + 1;
614
+ }
615
+ return delim + res + str.slice(i) + delim;
616
+ }
617
+ // A single symbol, either in <> or namespace notation
618
+
619
+ symbolToN3(x) {
620
+ // c.f. symbolString() in notation3.py
621
+ var uri = x.uri;
622
+ var j = uri.indexOf('#');
623
+ if (j < 0 && this.flags.indexOf('/') < 0) {
624
+ j = uri.lastIndexOf('/');
625
+ }
626
+ if (j >= 0 && this.flags.indexOf('p') < 0 && (
627
+ // Can split at namespace but only if http[s]: URI or file: or ws[s] (why not others?)
628
+ uri.indexOf('http') === 0 || uri.indexOf('ws') === 0 || uri.indexOf('file') === 0)) {
629
+ var canSplit = true;
630
+ for (var k = j + 1; k < uri.length; k++) {
631
+ if (this._notNameChars.indexOf(uri[k]) >= 0) {
632
+ canSplit = false;
633
+ break;
442
634
  }
443
-
444
- return s;
445
- };
446
-
447
- var treeToLine = function treeToLine(tree) {
448
- var str = '';
449
-
450
- for (var i = 0; i < tree.length; i++) {
451
- var branch = tree[i];
452
- var s2 = typeof branch === 'string' ? branch : treeToLine(branch); // Note the space before the dot in case statement ends with 123 or colon. which is in fact allowed but be conservative.
453
-
454
- if (i !== 0) {
455
- var ch = str.slice(-1) || ' ';
456
-
457
- if (s2 === ',' || s2 === ';') {// no gap
458
- } else if (s2 === '.' && !'0123456789.:'.includes(ch)) {// no gap except after number and colon
459
- // no gap
460
- } else {
461
- str += ' '; // separate from previous token
635
+ }
636
+ /*
637
+ if (uri.slice(0, j + 1) === this.base + '#') { // base-relative
638
+ if (canSplit) {
639
+ return ':' + uri.slice(j + 1) // assume deafult ns is local
640
+ } else {
641
+ return '<#' + uri.slice(j + 1) + '>'
642
+ }
462
643
  }
644
+ */
645
+ if (canSplit) {
646
+ var localid = uri.slice(j + 1);
647
+ var namesp = uri.slice(0, j + 1);
648
+ if (this.defaultNamespace && this.defaultNamespace === namesp && this.flags.indexOf('d') < 0) {
649
+ // d -> suppress default
650
+ if (this.flags.indexOf('k') >= 0 && this.keyords.indexOf(localid) < 0) {
651
+ return localid;
463
652
  }
464
-
465
- str += s2;
653
+ return ':' + localid;
466
654
  }
655
+ // this.checkIntegrity() // @@@ Remove when not testing
656
+ var prefix = this.prefixes[namesp];
657
+ if (!prefix) prefix = this.makeUpPrefix(namesp);
658
+ if (prefix) {
659
+ this.namespacesUsed[namesp] = true;
660
+ return prefix + ':' + localid;
661
+ }
662
+ // Fall though if can't do qname
663
+ }
664
+ }
467
665
 
468
- return str;
469
- }; // Convert a nested tree of lists and strings to a string
470
-
471
-
472
- var treeToString = function treeToString(tree, level) {
473
- var str = '';
474
- var lastLength = 100000;
475
- if (level === undefined) level = -1;
476
-
477
- for (var i = 0; i < tree.length; i++) {
478
- var branch = tree[i];
479
-
480
- if (typeof branch !== 'string') {
481
- var substr = treeToString(branch, level + 1);
666
+ return this.explicitURI(uri);
667
+ }
482
668
 
483
- if (substr.length < 10 * (width - indent * level) && substr.indexOf('"""') < 0) {
484
- // Don't mess up multiline strings
485
- var line = treeToLine(branch);
669
+ // /////////////////////////// Quad store serialization
486
670
 
487
- if (line.length < width - indent * level) {
488
- branch = line; // Note! treat as string below
671
+ // @para. write - a function taking a single string to be output
672
+ //
673
+ writeStore(write) {
674
+ var kb = this.store;
675
+ var fetcher = kb.fetcher;
676
+ var session = fetcher && fetcher.appNode;
489
677
 
490
- substr = '';
491
- }
492
- }
678
+ // The core data
493
679
 
494
- if (substr) lastLength = 10000;
495
- str += substr;
496
- }
680
+ var sources = this.store.index[3];
681
+ for (var s in sources) {
682
+ // -> assume we can use -> as short for log:semantics
683
+ var source = kb.fromNT(s);
684
+ if (session && source.equals(session)) continue;
685
+ write('\n' + this.atomicTermToN3(source) + ' ' + this.atomicTermToN3(kb.sym('http://www.w3.org/2000/10/swap/log#semantics')) + ' { ' + this.statementsToN3(kb.statementsMatching(undefined, undefined, undefined, source)) + ' }.\n');
686
+ }
497
687
 
498
- if (typeof branch === 'string') {
499
- if (branch.length === 1 && str.slice(-1) === '\n') {
500
- if (',.;'.indexOf(branch) >= 0) {
501
- str = str.slice(0, -1); // be conservative and ensure a whitespace between some chars and a final dot, as in treeToLine above
688
+ // The metadata from HTTP interactions:
502
689
 
503
- if (branch == '.' && '0123456789.:'.includes(str.charAt(str.length - 1))) {
504
- str += ' ';
505
- lastLength += 1;
506
- }
690
+ kb.statementsMatching(undefined, kb.sym('http://www.w3.org/2007/ont/link#requestedURI')).map(function (st) {
691
+ write('\n<' + st.object.value + '> log:metadata {\n');
692
+ var sts = kb.statementsMatching(undefined, undefined, undefined, st.subject);
693
+ write(this.statementsToN3(this.statementsToN3(sts)));
694
+ write('}.\n');
695
+ });
507
696
 
508
- str += branch + '\n'; // slip punct'n on end
697
+ // Inferences we have made ourselves not attributable to anyone else
509
698
 
510
- lastLength += 1;
511
- continue;
512
- }
513
- }
699
+ var metaSources = [];
700
+ if (session) metaSources.push(session);
701
+ var metadata = [];
702
+ metaSources.map(function (source) {
703
+ metadata = metadata.concat(kb.statementsMatching(undefined, undefined, undefined, source));
704
+ });
705
+ write(this.statementsToN3(metadata));
706
+ }
514
707
 
515
- if (lastLength < indent * level + 4 || // if new line not necessary
516
- lastLength + branch.length + 1 < width && ';.'.indexOf(str[str.length - 2]) < 0) {
517
- // or the string fits on last line
518
- str = str.slice(0, -1) + ' ' + branch + '\n'; // then continue on this line
708
+ // ////////////////////////////////////////////// XML serialization
519
709
 
520
- lastLength += branch.length + 1;
521
- } else {
522
- var _line = spaces(indent * level) + branch;
710
+ statementsToXML(sts) {
711
+ var indent = 4;
712
+ var width = 80;
713
+ var namespaceCounts = []; // which have been used
714
+ namespaceCounts['http://www.w3.org/1999/02/22-rdf-syntax-ns#'] = true;
715
+ var liPrefix = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_'; // prefix for ordered list items
523
716
 
524
- str += _line + '\n';
525
- lastLength = _line.length;
717
+ // //////////////////////// Arrange the bits of XML text
526
718
 
527
- if (level < 0) {
528
- str += '\n'; // extra blank line
719
+ var spaces = function (n) {
720
+ var s = '';
721
+ for (var i = 0; i < n; i++) s += ' ';
722
+ return s;
723
+ };
724
+ var XMLtreeToLine = function (tree) {
725
+ var str = '';
726
+ for (var i = 0; i < tree.length; i++) {
727
+ var branch = tree[i];
728
+ var s2 = typeof branch === 'string' ? branch : XMLtreeToLine(branch);
729
+ str += s2;
730
+ }
731
+ return str;
732
+ };
529
733
 
530
- lastLength = 100000; // don't touch
531
- }
734
+ // Convert a nested tree of lists and strings to a string
735
+ var XMLtreeToString = function (tree, level) {
736
+ var str = '';
737
+ var line;
738
+ var lastLength = 100000;
739
+ if (!level) level = 0;
740
+ for (var i = 0; i < tree.length; i++) {
741
+ var branch = tree[i];
742
+ if (typeof branch !== 'string') {
743
+ var substr = XMLtreeToString(branch, level + 1);
744
+ if (substr.length < 10 * (width - indent * level) && substr.indexOf('"""') < 0) {
745
+ // Don't mess up multiline strings
746
+ line = XMLtreeToLine(branch);
747
+ if (line.length < width - indent * level) {
748
+ branch = ' ' + line; // @@ Hack: treat as string below
749
+ substr = '';
532
750
  }
533
751
  }
752
+ if (substr) lastLength = 10000;
753
+ str += substr;
534
754
  }
535
-
536
- return str;
537
- }; // //////////////////////////////////////////// Structure for N3
538
- // Convert a set of statements into a nested tree of lists and strings
539
-
540
-
541
- function statementListToTreeMethod(statements) {
542
- var stats = this.rootSubjects(statements);
543
- var roots = stats.roots;
544
- var results = [];
545
-
546
- for (var i = 0; i < roots.length; i++) {
547
- var root = roots[i];
548
- results.push(subjectTree(root, stats));
755
+ if (typeof branch === 'string') {
756
+ if (lastLength < indent * level + 4) {
757
+ // continue
758
+ str = str.slice(0, -1) + ' ' + branch + '\n';
759
+ lastLength += branch.length + 1;
760
+ } else {
761
+ line = spaces(indent * level) + branch;
762
+ str += line + '\n';
763
+ lastLength = line.length;
764
+ }
765
+ } else {// not string
549
766
  }
550
-
551
- return results;
552
767
  }
553
-
554
- var statementListToTree = statementListToTreeMethod.bind(this); // The tree for a subject
555
-
556
- function subjectTree(subject, stats) {
557
- if (subject.termType === 'BlankNode' && !stats.incoming[subject]) {
558
- return objectTree(subject, stats, true).concat(['.']); // Anonymous bnode subject
768
+ return str;
769
+ };
770
+ function statementListToXMLTreeMethod(statements) {
771
+ this.suggestPrefix('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
772
+ var stats = this.rootSubjects(statements);
773
+ var roots = stats.roots;
774
+ var results = [];
775
+ for (var i = 0; i < roots.length; i++) {
776
+ var root = roots[i];
777
+ results.push(subjectXMLTree(root, stats));
778
+ }
779
+ return results;
780
+ }
781
+ var statementListToXMLTree = statementListToXMLTreeMethod.bind(this);
782
+ function escapeForXML(str) {
783
+ if (typeof str === 'undefined') return '@@@undefined@@@@';
784
+ return str.replace(/[&<"]/g, function (m) {
785
+ switch (m[0]) {
786
+ case '&':
787
+ return '&amp;';
788
+ case '<':
789
+ return '&lt;';
790
+ case '"':
791
+ return '&quot;';
792
+ // '
559
793
  }
794
+ });
795
+ }
560
796
 
561
- return [termToN3(subject, stats)].concat([propertyTree(subject, stats)]).concat(['.']);
562
- } // The property tree for a single subject or anonymous node
563
-
564
-
565
- function propertyTreeMethod(subject, stats) {
566
- var results = [];
567
- var lastPred = null;
568
- var sts = stats.subjects[this.toStr(subject)] || []; // relevant statements
797
+ function relURIMethod(term) {
798
+ return escapeForXML(this.base ? Util.uri.refTo(this.base, term.uri) : term.uri);
799
+ }
800
+ var relURI = relURIMethod.bind(this);
801
+
802
+ // The tree for a subject
803
+ function subjectXMLTreeMethod(subject, stats) {
804
+ var results = [];
805
+ var type, t, st, pred;
806
+ var sts = stats.subjects[this.toStr(subject)]; // relevant statements
807
+ if (typeof sts === 'undefined') {
808
+ // empty bnode
809
+ return propertyXMLTree(subject, stats);
810
+ }
569
811
 
570
- if (typeof sts === 'undefined') {
571
- throw new Error('Cant find statements for ' + subject);
812
+ // Sort only on the predicate, leave the order at object
813
+ // level undisturbed. This leaves multilingual content in
814
+ // the order of entry (for partner literals), which helps
815
+ // readability.
816
+ //
817
+ // For the predicate sort, we attempt to split the uri
818
+ // as a hint to the sequence
819
+ sts.sort(function (a, b) {
820
+ var ap = a.predicate.uri;
821
+ var bp = b.predicate.uri;
822
+ if (ap.substring(0, liPrefix.length) === liPrefix || bp.substring(0, liPrefix.length) === liPrefix) {
823
+ // we're only interested in sorting list items
824
+ return ap.localeCompare(bp);
572
825
  }
573
-
574
- var objects = [];
575
-
576
- for (var i = 0; i < sts.length; i++) {
577
- var st = sts[i];
578
-
579
- if (st.predicate.uri === lastPred) {
580
- objects.push(',');
581
- } else {
582
- if (lastPred) {
583
- results = results.concat([objects]).concat([';']);
584
- objects = [];
585
- }
586
-
587
- results.push(predMap[st.predicate.uri] ? predMap[st.predicate.uri] : termToN3(st.predicate, stats));
588
- }
589
-
590
- lastPred = st.predicate.uri;
591
- objects.push(objectTree(st.object, stats));
826
+ var as = ap.substring(liPrefix.length);
827
+ var bs = bp.substring(liPrefix.length);
828
+ var an = parseInt(as, 10);
829
+ var bn = parseInt(bs, 10);
830
+ if (isNaN(an) || isNaN(bn) || an !== as || bn !== bs) {
831
+ // we only care about integers
832
+ return ap.localeCompare(bp);
833
+ }
834
+ return an - bn;
835
+ });
836
+ for (var i = 0; i < sts.length; i++) {
837
+ st = sts[i];
838
+ // look for a type
839
+ if (st.predicate.uri === 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' && !type && st.object.termType === 'NamedNode') {
840
+ type = st.object;
841
+ continue; // don't include it as a child element
592
842
  }
593
843
 
594
- results = results.concat([objects]);
595
- return results;
596
- }
597
-
598
- var propertyTree = propertyTreeMethod.bind(this);
599
-
600
- function objectTreeMethod(obj, stats, force) {
601
- if (obj.termType === 'BlankNode' && (force || stats.rootsHash[obj.toNT()] === undefined)) {
602
- // if not a root
603
- if (stats.subjects[this.toStr(obj)]) {
604
- return ['[', propertyTree(obj, stats), ']'];
605
- } else {
606
- return '[]';
844
+ // see whether predicate can be replaced with "li"
845
+ pred = st.predicate;
846
+ if (pred.uri.substr(0, liPrefix.length) === liPrefix) {
847
+ var number = pred.uri.substr(liPrefix.length);
848
+ // make sure these are actually numeric list items
849
+ var intNumber = parseInt(number, 10);
850
+ if (number === intNumber.toString()) {
851
+ // was numeric; don't need to worry about ordering since we've already
852
+ // sorted the statements
853
+ pred = this.rdfFactory.namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#li');
607
854
  }
608
855
  }
609
-
610
- return termToN3(obj, stats);
611
- }
612
-
613
- var objectTree = objectTreeMethod.bind(this);
614
-
615
- function termToN3Method(expr, stats) {
616
- //
617
- var i, res;
618
-
619
- switch (expr.termType) {
620
- case 'Graph':
621
- res = ['{'];
622
- res = res.concat(statementListToTree(expr.statements));
623
- return res.concat(['}']);
624
-
625
- case 'Collection':
626
- res = ['('];
627
-
628
- for (i = 0; i < expr.elements.length; i++) {
629
- res.push([objectTree(expr.elements[i], stats)]);
856
+ t = qname(pred);
857
+ switch (st.object.termType) {
858
+ case 'BlankNode':
859
+ if (stats.incoming[st.object].length === 1) {
860
+ // there should always be something in the incoming array for a bnode
861
+ results = results.concat(['<' + t + ' rdf:parseType="Resource">', subjectXMLTree(st.object, stats), '</' + t + '>']);
862
+ } else {
863
+ results = results.concat(['<' + t + ' rdf:nodeID="' + st.object.toNT().slice(2) + '"/>']);
630
864
  }
631
-
632
- res.push(')');
633
- return res;
634
-
865
+ break;
866
+ case 'NamedNode':
867
+ results = results.concat(['<' + t + ' rdf:resource="' + relURI(st.object) + '"/>']);
868
+ break;
869
+ case 'Literal':
870
+ results = results.concat(['<' + t + (st.object.datatype.equals(this.xsd.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.uri) + '"') + (st.object.language ? ' xml:lang="' + st.object.language + '"' : '') + '>' + escapeForXML(st.object.value) + '</' + t + '>']);
871
+ break;
872
+ case 'Collection':
873
+ results = results.concat(['<' + t + ' rdf:parseType="Collection">', collectionXMLTree(st.object, stats), '</' + t + '>']);
874
+ break;
635
875
  default:
636
- return this.atomicTermToN3(expr);
637
- }
876
+ throw new Error("Can't serialize object of type " + st.object.termType + ' into XML');
877
+ } // switch
638
878
  }
639
879
 
640
- Serializer.prototype.termToN3 = termToN3;
641
- var termToN3 = termToN3Method.bind(this);
642
-
643
- function prefixDirectivesMethod() {
644
- var str = '';
645
-
646
- if (this.defaultNamespace) {
647
- str += '@prefix : ' + this.explicitURI(this.defaultNamespace) + '.\n';
648
- }
649
-
650
- for (var ns in this.prefixes) {
651
- if (!this.prefixes.hasOwnProperty(ns)) continue;
652
- if (!this.namespacesUsed[ns]) continue;
653
- str += '@prefix ' + this.prefixes[ns] + ': ' + this.explicitURI(ns) + '.\n';
880
+ var tag = type ? qname(type) : 'rdf:Description';
881
+ var attrs = '';
882
+ if (subject.termType === 'BlankNode') {
883
+ if (!stats.incoming[subject] || stats.incoming[subject].length !== 1) {
884
+ // not an anonymous bnode
885
+ attrs = ' rdf:nodeID="' + subject.toNT().slice(2) + '"';
654
886
  }
655
-
656
- return str + '\n';
887
+ } else {
888
+ attrs = ' rdf:about="' + relURI(subject) + '"';
657
889
  }
890
+ return ['<' + tag + attrs + '>'].concat([results]).concat(['</' + tag + '>']);
891
+ }
892
+ var subjectXMLTree = subjectXMLTreeMethod.bind(this);
893
+ function collectionXMLTree(subject, stats) {
894
+ var res = [];
895
+ for (var i = 0; i < subject.elements.length; i++) {
896
+ res.push(subjectXMLTree(subject.elements[i], stats));
897
+ }
898
+ return res;
899
+ }
658
900
 
659
- var prefixDirectives = prefixDirectivesMethod.bind(this); // Body of statementsToN3:
660
-
661
- var tree = statementListToTree(sts);
662
- return prefixDirectives() + treeToString(tree);
663
- } // //////////////////////////////////////////// Atomic Terms
664
- // Deal with term level things and nesting with no bnode structure
665
-
666
- }, {
667
- key: "atomicTermToN3",
668
- value: function atomicTermToN3(expr, stats) {
669
- switch (expr.termType) {
670
- case 'BlankNode':
671
- case 'Variable':
672
- return expr.toNT();
673
-
674
- case 'Literal':
675
- var val = expr.value;
676
-
677
- if (typeof val !== 'string') {
678
- throw new TypeError('Value of RDF literal node must be a string');
679
- } // var val = expr.value.toString() // should be a string already
680
-
681
-
682
- if (expr.datatype && this.flags.indexOf('x') < 0) {
683
- // Supress native numbers
684
- switch (expr.datatype.uri) {
685
- case 'http://www.w3.org/2001/XMLSchema#integer':
686
- return val;
687
-
688
- case 'http://www.w3.org/2001/XMLSchema#decimal':
689
- // In Turtle, must have dot
690
- if (val.indexOf('.') < 0) val += '.0';
691
- return val;
692
-
693
- case 'http://www.w3.org/2001/XMLSchema#double':
694
- {
695
- // Must force use of 'e'
696
- var eNotation = val.toLowerCase().indexOf('e') > 0;
697
- if (val.indexOf('.') < 0 && !eNotation) val += '.0';
698
- if (!eNotation) val += 'e0';
699
- return val;
700
- }
701
-
702
- case 'http://www.w3.org/2001/XMLSchema#boolean':
703
- return expr.value === '1' ? 'true' : 'false';
901
+ // The property tree for a single subject or anonymos node
902
+ function propertyXMLTreeMethod(subject, stats) {
903
+ var results = [];
904
+ var sts = stats.subjects[this.toStr(subject)]; // relevant statements
905
+ if (!sts) return results; // No relevant statements
906
+ sts.sort();
907
+ for (var i = 0; i < sts.length; i++) {
908
+ var st = sts[i];
909
+ switch (st.object.termType) {
910
+ case 'BlankNode':
911
+ if (stats.rootsHash[st.object.toNT()]) {
912
+ // This bnode has been done as a root -- no content here @@ what bout first time
913
+ results = results.concat(['<' + qname(st.predicate) + ' rdf:nodeID="' + st.object.toNT().slice(2) + '">', '</' + qname(st.predicate) + '>']);
914
+ } else {
915
+ results = results.concat(['<' + qname(st.predicate) + ' rdf:parseType="Resource">', propertyXMLTree(st.object, stats), '</' + qname(st.predicate) + '>']);
704
916
  }
705
- }
706
-
707
- var str = this.stringToN3(expr.value);
708
-
709
- if (expr.language) {
710
- str += '@' + expr.language;
711
- } else if (!expr.datatype.equals(this.xsd.string)) {
712
- str += '^^' + this.atomicTermToN3(expr.datatype, stats);
713
- }
714
-
715
- return str;
716
-
717
- case 'NamedNode':
718
- return this.symbolToN3(expr);
719
-
720
- case 'DefaultGraph':
721
- return '';
722
-
723
- default:
724
- throw new Error('Internal: atomicTermToN3 cannot handle ' + expr + ' of termType: ' + expr.termType);
917
+ break;
918
+ case 'NamedNode':
919
+ results = results.concat(['<' + qname(st.predicate) + ' rdf:resource="' + relURI(st.object) + '"/>']);
920
+ break;
921
+ case 'Literal':
922
+ results = results.concat(['<' + qname(st.predicate) + (st.object.datatype.equals(this.xsd.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.value) + '"') + (st.object.language ? ' xml:lang="' + st.object.language + '"' : '') + '>' + escapeForXML(st.object.value) + '</' + qname(st.predicate) + '>']);
923
+ break;
924
+ case 'Collection':
925
+ results = results.concat(['<' + qname(st.predicate) + ' rdf:parseType="Collection">', collectionXMLTree(st.object, stats), '</' + qname(st.predicate) + '>']);
926
+ break;
927
+ default:
928
+ throw new Error("Can't serialize object of type " + st.object.termType + ' into XML');
929
+ } // switch
725
930
  }
726
- } // stringToN3: String escaping for N3
727
931
 
728
- }, {
729
- key: "stringToN3",
730
- value: function stringToN3(str, flags) {
731
- if (!flags) flags = 'e';
732
- var res = '';
733
- var i, j, k;
734
- var delim;
735
- var forbidden;
736
-
737
- if (str.length > 20 && // Long enough to make sense
738
- str.slice(-1) !== '"' && // corner case'
739
- flags.indexOf('n') < 0 && ( // Force single line
740
- str.indexOf('\n') > 0 || str.indexOf('"') > 0)) {
741
- delim = '"""';
742
- forbidden = this.forbidden3;
743
- } else {
744
- delim = '"';
745
- forbidden = this.forbidden1;
932
+ return results;
933
+ }
934
+ var propertyXMLTree = propertyXMLTreeMethod.bind(this);
935
+ function qnameMethod(term) {
936
+ var uri = term.uri;
937
+ var j = uri.indexOf('#');
938
+ if (j < 0 && this.flags.indexOf('/') < 0) {
939
+ j = uri.lastIndexOf('/');
746
940
  }
747
-
748
- for (i = 0; i < str.length;) {
749
- forbidden.lastIndex = 0;
750
- var m = forbidden.exec(str.slice(i));
751
- if (m == null) break;
752
- j = i + forbidden.lastIndex - 1;
753
- res += str.slice(i, j);
754
- var ch = str[j];
755
-
756
- if (ch === '"' && delim === '"""' && str.slice(j, j + 3) !== '"""') {
757
- res += ch;
758
- } else {
759
- k = '\b\f\r\t\v\n\\"'.indexOf(ch); // No escaping of bell (7)?
760
-
761
- if (k >= 0) {
762
- res += '\\' + 'bfrtvn\\"'[k];
763
- } else {
764
- if (flags.indexOf('e') >= 0) {
765
- // Unicode escaping in strings not unix style
766
- res += "\\u" + ('000' + ch.charCodeAt(0).toString(16).toLowerCase()).slice(-4);
767
- } else {
768
- // no 'e' flag
769
- res += ch;
770
- }
771
- }
941
+ if (j < 0) throw new Error('Cannot make qname out of <' + uri + '>');
942
+ for (var k = j + 1; k < uri.length; k++) {
943
+ if (this._notNameChars.indexOf(uri[k]) >= 0) {
944
+ throw new Error('Invalid character "' + uri[k] + '" cannot be in XML qname for URI: ' + uri);
772
945
  }
773
-
774
- i = j + 1;
775
946
  }
947
+ var localid = uri.slice(j + 1);
948
+ var namesp = uri.slice(0, j + 1);
949
+ if (this.defaultNamespace && this.defaultNamespace === namesp && this.flags.indexOf('d') < 0) {
950
+ // d -> suppress default
951
+ return localid;
952
+ }
953
+ var prefix = this.prefixes[namesp];
954
+ if (!prefix) prefix = this.makeUpPrefix(namesp);
955
+ namespaceCounts[namesp] = true;
956
+ return prefix + ':' + localid;
957
+ }
958
+ var qname = qnameMethod.bind(this);
776
959
 
777
- return delim + res + str.slice(i) + delim;
778
- } // A single symbol, either in <> or namespace notation
960
+ // Body of toXML:
779
961
 
780
- }, {
781
- key: "symbolToN3",
782
- value: function symbolToN3(x) {
783
- // c.f. symbolString() in notation3.py
784
- var uri = x.uri;
962
+ var tree = statementListToXMLTree(sts);
963
+ var str = '<rdf:RDF';
964
+ if (this.defaultNamespace) {
965
+ str += ' xmlns="' + escapeForXML(this.defaultNamespace) + '"';
966
+ }
967
+ for (var ns in namespaceCounts) {
968
+ if (!namespaceCounts.hasOwnProperty(ns)) continue;
969
+ // Rel uris in xml ns is not strictly allowed in the XMLNS spec but needed in practice often
970
+ var ns2 = this.base && this.flags.includes('z') ? Util.uri.refTo(this.base, ns) : ns;
971
+ str += '\n xmlns:' + this.prefixes[ns] + '="' + escapeForXML(ns2) + '"';
972
+ }
973
+ str += '>';
974
+ var tree2 = [str, tree, '</rdf:RDF>']; // @@ namespace declrations
975
+ return XMLtreeToString(tree2, -1);
976
+ } // End @@ body
977
+
978
+ statementsToJsonld(sts) {
979
+ // find all @context prefix except base
980
+ function contextMethod(n3String) {
981
+ let prefixes = new Set();
982
+ const regex = /<(.*?)>/g;
983
+ n3String.match(regex).map(string => {
984
+ const uri = string.slice(1).slice(0, -1);
985
+ if (uri.includes('//') && (!this.base || !uri.includes(this.base))) prefixes.add(addPrefix(uri));
986
+ });
987
+ let context = `{ `;
988
+ const test = [...prefixes].map(term => {
989
+ context += `${term},`;
990
+ });
991
+ return context.slice(0, -1) + `}`;
992
+ }
993
+ function addPrefixMethod(uri) {
785
994
  var j = uri.indexOf('#');
786
-
787
- if (j < 0 && this.flags.indexOf('/') < 0) {
995
+ if (j < 0) {
788
996
  j = uri.lastIndexOf('/');
789
997
  }
790
-
791
- if (j >= 0 && this.flags.indexOf('p') < 0 && ( // Can split at namespace but only if http[s]: URI or file: or ws[s] (why not others?)
998
+ if (j >= 0 && (
999
+ // Can split at namespace but only if http[s]: URI or file: or ws[s] (why not others?)
792
1000
  uri.indexOf('http') === 0 || uri.indexOf('ws') === 0 || uri.indexOf('file') === 0)) {
793
1001
  var canSplit = true;
794
-
795
1002
  for (var k = j + 1; k < uri.length; k++) {
796
1003
  if (this._notNameChars.indexOf(uri[k]) >= 0) {
797
1004
  canSplit = false;
798
1005
  break;
799
1006
  }
800
1007
  }
801
- /*
802
- if (uri.slice(0, j + 1) === this.base + '#') { // base-relative
803
- if (canSplit) {
804
- return ':' + uri.slice(j + 1) // assume deafult ns is local
805
- } else {
806
- return '<#' + uri.slice(j + 1) + '>'
807
- }
808
- }
809
- */
810
-
811
-
812
1008
  if (canSplit) {
813
1009
  var localid = uri.slice(j + 1);
814
1010
  var namesp = uri.slice(0, j + 1);
815
-
816
- if (this.defaultNamespace && this.defaultNamespace === namesp && this.flags.indexOf('d') < 0) {
817
- // d -> suppress default
818
- if (this.flags.indexOf('k') >= 0 && this.keyords.indexOf(localid) < 0) {
819
- return localid;
820
- }
821
-
822
- return ':' + localid;
823
- } // this.checkIntegrity() // @@@ Remove when not testing
824
-
825
-
826
1011
  var prefix = this.prefixes[namesp];
827
1012
  if (!prefix) prefix = this.makeUpPrefix(namesp);
828
-
829
1013
  if (prefix) {
830
- this.namespacesUsed[namesp] = true;
831
- return prefix + ':' + localid;
832
- } // Fall though if can't do qname
833
-
834
- }
835
- }
836
-
837
- return this.explicitURI(uri);
838
- } // /////////////////////////// Quad store serialization
839
- // @para. write - a function taking a single string to be output
840
- //
841
-
842
- }, {
843
- key: "writeStore",
844
- value: function writeStore(write) {
845
- var kb = this.store;
846
- var fetcher = kb.fetcher;
847
- var session = fetcher && fetcher.appNode; // The core data
848
-
849
- var sources = this.store.index[3];
850
-
851
- for (var s in sources) {
852
- // -> assume we can use -> as short for log:semantics
853
- var source = kb.fromNT(s);
854
- if (session && source.equals(session)) continue;
855
- write('\n' + this.atomicTermToN3(source) + ' ' + this.atomicTermToN3(kb.sym('http://www.w3.org/2000/10/swap/log#semantics')) + ' { ' + this.statementsToN3(kb.statementsMatching(undefined, undefined, undefined, source)) + ' }.\n');
856
- } // The metadata from HTTP interactions:
857
-
858
-
859
- kb.statementsMatching(undefined, kb.sym('http://www.w3.org/2007/ont/link#requestedURI')).map(function (st) {
860
- write('\n<' + st.object.value + '> log:metadata {\n');
861
- var sts = kb.statementsMatching(undefined, undefined, undefined, st.subject);
862
- write(this.statementsToN3(this.statementsToN3(sts)));
863
- write('}.\n');
864
- }); // Inferences we have made ourselves not attributable to anyone else
865
-
866
- var metaSources = [];
867
- if (session) metaSources.push(session);
868
- var metadata = [];
869
- metaSources.map(function (source) {
870
- metadata = metadata.concat(kb.statementsMatching(undefined, undefined, undefined, source));
871
- });
872
- write(this.statementsToN3(metadata));
873
- } // ////////////////////////////////////////////// XML serialization
874
-
875
- }, {
876
- key: "statementsToXML",
877
- value: function statementsToXML(sts) {
878
- var indent = 4;
879
- var width = 80;
880
- var namespaceCounts = []; // which have been used
881
-
882
- namespaceCounts['http://www.w3.org/1999/02/22-rdf-syntax-ns#'] = true;
883
- var liPrefix = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_'; // prefix for ordered list items
884
- // //////////////////////// Arrange the bits of XML text
885
-
886
- var spaces = function spaces(n) {
887
- var s = '';
888
-
889
- for (var i = 0; i < n; i++) {
890
- s += ' ';
891
- }
892
-
893
- return s;
894
- };
895
-
896
- var XMLtreeToLine = function XMLtreeToLine(tree) {
897
- var str = '';
898
-
899
- for (var i = 0; i < tree.length; i++) {
900
- var branch = tree[i];
901
- var s2 = typeof branch === 'string' ? branch : XMLtreeToLine(branch);
902
- str += s2;
903
- }
904
-
905
- return str;
906
- }; // Convert a nested tree of lists and strings to a string
907
-
908
-
909
- var XMLtreeToString = function XMLtreeToString(tree, level) {
910
- var str = '';
911
- var line;
912
- var lastLength = 100000;
913
- if (!level) level = 0;
914
-
915
- for (var i = 0; i < tree.length; i++) {
916
- var branch = tree[i];
917
-
918
- if (typeof branch !== 'string') {
919
- var substr = XMLtreeToString(branch, level + 1);
920
-
921
- if (substr.length < 10 * (width - indent * level) && substr.indexOf('"""') < 0) {
922
- // Don't mess up multiline strings
923
- line = XMLtreeToLine(branch);
924
-
925
- if (line.length < width - indent * level) {
926
- branch = ' ' + line; // @@ Hack: treat as string below
927
-
928
- substr = '';
929
- }
930
- }
931
-
932
- if (substr) lastLength = 10000;
933
- str += substr;
934
- }
935
-
936
- if (typeof branch === 'string') {
937
- if (lastLength < indent * level + 4) {
938
- // continue
939
- str = str.slice(0, -1) + ' ' + branch + '\n';
940
- lastLength += branch.length + 1;
941
- } else {
942
- line = spaces(indent * level) + branch;
943
- str += line + '\n';
944
- lastLength = line.length;
945
- }
946
- } else {// not string
1014
+ return `"${prefix}": "${namesp}"`;
947
1015
  }
948
1016
  }
949
-
950
- return str;
951
- };
952
-
953
- function statementListToXMLTreeMethod(statements) {
954
- this.suggestPrefix('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
955
- var stats = this.rootSubjects(statements);
956
- var roots = stats.roots;
957
- var results = [];
958
-
959
- for (var i = 0; i < roots.length; i++) {
960
- var root = roots[i];
961
- results.push(subjectXMLTree(root, stats));
962
- }
963
-
964
- return results;
965
- }
966
-
967
- var statementListToXMLTree = statementListToXMLTreeMethod.bind(this);
968
-
969
- function escapeForXML(str) {
970
- if (typeof str === 'undefined') return '@@@undefined@@@@';
971
- return str.replace(/[&<"]/g, function (m) {
972
- switch (m[0]) {
973
- case '&':
974
- return '&amp;';
975
-
976
- case '<':
977
- return '&lt;';
978
-
979
- case '"':
980
- return '&quot;';
981
- // '
982
- }
983
- });
984
- }
985
-
986
- function relURIMethod(term) {
987
- return escapeForXML(this.base ? Util.uri.refTo(this.base, term.uri) : term.uri);
988
- }
989
-
990
- var relURI = relURIMethod.bind(this); // The tree for a subject
991
-
992
- function subjectXMLTreeMethod(subject, stats) {
993
- var results = [];
994
- var type, t, st, pred;
995
- var sts = stats.subjects[this.toStr(subject)]; // relevant statements
996
-
997
- if (typeof sts === 'undefined') {
998
- // empty bnode
999
- return propertyXMLTree(subject, stats);
1000
- } // Sort only on the predicate, leave the order at object
1001
- // level undisturbed. This leaves multilingual content in
1002
- // the order of entry (for partner literals), which helps
1003
- // readability.
1004
- //
1005
- // For the predicate sort, we attempt to split the uri
1006
- // as a hint to the sequence
1007
-
1008
-
1009
- sts.sort(function (a, b) {
1010
- var ap = a.predicate.uri;
1011
- var bp = b.predicate.uri;
1012
-
1013
- if (ap.substring(0, liPrefix.length) === liPrefix || bp.substring(0, liPrefix.length) === liPrefix) {
1014
- // we're only interested in sorting list items
1015
- return ap.localeCompare(bp);
1016
- }
1017
-
1018
- var as = ap.substring(liPrefix.length);
1019
- var bs = bp.substring(liPrefix.length);
1020
- var an = parseInt(as, 10);
1021
- var bn = parseInt(bs, 10);
1022
-
1023
- if (isNaN(an) || isNaN(bn) || an !== as || bn !== bs) {
1024
- // we only care about integers
1025
- return ap.localeCompare(bp);
1026
- }
1027
-
1028
- return an - bn;
1029
- });
1030
-
1031
- for (var i = 0; i < sts.length; i++) {
1032
- st = sts[i]; // look for a type
1033
-
1034
- if (st.predicate.uri === 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' && !type && st.object.termType === 'NamedNode') {
1035
- type = st.object;
1036
- continue; // don't include it as a child element
1037
- } // see whether predicate can be replaced with "li"
1038
-
1039
-
1040
- pred = st.predicate;
1041
-
1042
- if (pred.uri.substr(0, liPrefix.length) === liPrefix) {
1043
- var number = pred.uri.substr(liPrefix.length); // make sure these are actually numeric list items
1044
-
1045
- var intNumber = parseInt(number, 10);
1046
-
1047
- if (number === intNumber.toString()) {
1048
- // was numeric; don't need to worry about ordering since we've already
1049
- // sorted the statements
1050
- pred = this.rdfFactory.namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#li');
1051
- }
1052
- }
1053
-
1054
- t = qname(pred);
1055
-
1056
- switch (st.object.termType) {
1057
- case 'BlankNode':
1058
- if (stats.incoming[st.object].length === 1) {
1059
- // there should always be something in the incoming array for a bnode
1060
- results = results.concat(['<' + t + ' rdf:parseType="Resource">', subjectXMLTree(st.object, stats), '</' + t + '>']);
1061
- } else {
1062
- results = results.concat(['<' + t + ' rdf:nodeID="' + st.object.toNT().slice(2) + '"/>']);
1063
- }
1064
-
1065
- break;
1066
-
1067
- case 'NamedNode':
1068
- results = results.concat(['<' + t + ' rdf:resource="' + relURI(st.object) + '"/>']);
1069
- break;
1070
-
1071
- case 'Literal':
1072
- results = results.concat(['<' + t + (st.object.datatype.equals(this.xsd.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.uri) + '"') + (st.object.language ? ' xml:lang="' + st.object.language + '"' : '') + '>' + escapeForXML(st.object.value) + '</' + t + '>']);
1073
- break;
1074
-
1075
- case 'Collection':
1076
- results = results.concat(['<' + t + ' rdf:parseType="Collection">', collectionXMLTree(st.object, stats), '</' + t + '>']);
1077
- break;
1078
-
1079
- default:
1080
- throw new Error("Can't serialize object of type " + st.object.termType + ' into XML');
1081
- } // switch
1082
-
1083
- }
1084
-
1085
- var tag = type ? qname(type) : 'rdf:Description';
1086
- var attrs = '';
1087
-
1088
- if (subject.termType === 'BlankNode') {
1089
- if (!stats.incoming[subject] || stats.incoming[subject].length !== 1) {
1090
- // not an anonymous bnode
1091
- attrs = ' rdf:nodeID="' + subject.toNT().slice(2) + '"';
1092
- }
1093
- } else {
1094
- attrs = ' rdf:about="' + relURI(subject) + '"';
1095
- }
1096
-
1097
- return ['<' + tag + attrs + '>'].concat([results]).concat(['</' + tag + '>']);
1098
1017
  }
1099
-
1100
- var subjectXMLTree = subjectXMLTreeMethod.bind(this);
1101
-
1102
- function collectionXMLTree(subject, stats) {
1103
- var res = [];
1104
-
1105
- for (var i = 0; i < subject.elements.length; i++) {
1106
- res.push(subjectXMLTree(subject.elements[i], stats));
1107
- }
1108
-
1109
- return res;
1110
- } // The property tree for a single subject or anonymos node
1111
-
1112
-
1113
- function propertyXMLTreeMethod(subject, stats) {
1114
- var results = [];
1115
- var sts = stats.subjects[this.toStr(subject)]; // relevant statements
1116
-
1117
- if (!sts) return results; // No relevant statements
1118
-
1119
- sts.sort();
1120
-
1121
- for (var i = 0; i < sts.length; i++) {
1122
- var st = sts[i];
1123
-
1124
- switch (st.object.termType) {
1125
- case 'BlankNode':
1126
- if (stats.rootsHash[st.object.toNT()]) {
1127
- // This bnode has been done as a root -- no content here @@ what bout first time
1128
- results = results.concat(['<' + qname(st.predicate) + ' rdf:nodeID="' + st.object.toNT().slice(2) + '">', '</' + qname(st.predicate) + '>']);
1129
- } else {
1130
- results = results.concat(['<' + qname(st.predicate) + ' rdf:parseType="Resource">', propertyXMLTree(st.object, stats), '</' + qname(st.predicate) + '>']);
1131
- }
1132
-
1133
- break;
1134
-
1135
- case 'NamedNode':
1136
- results = results.concat(['<' + qname(st.predicate) + ' rdf:resource="' + relURI(st.object) + '"/>']);
1137
- break;
1138
-
1139
- case 'Literal':
1140
- results = results.concat(['<' + qname(st.predicate) + (st.object.datatype.equals(this.xsd.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.value) + '"') + (st.object.language ? ' xml:lang="' + st.object.language + '"' : '') + '>' + escapeForXML(st.object.value) + '</' + qname(st.predicate) + '>']);
1141
- break;
1142
-
1143
- case 'Collection':
1144
- results = results.concat(['<' + qname(st.predicate) + ' rdf:parseType="Collection">', collectionXMLTree(st.object, stats), '</' + qname(st.predicate) + '>']);
1145
- break;
1146
-
1147
- default:
1148
- throw new Error("Can't serialize object of type " + st.object.termType + ' into XML');
1149
- } // switch
1150
-
1151
- }
1152
-
1153
- return results;
1154
- }
1155
-
1156
- var propertyXMLTree = propertyXMLTreeMethod.bind(this);
1157
-
1158
- function qnameMethod(term) {
1159
- var uri = term.uri;
1160
- var j = uri.indexOf('#');
1161
-
1162
- if (j < 0 && this.flags.indexOf('/') < 0) {
1163
- j = uri.lastIndexOf('/');
1164
- }
1165
-
1166
- if (j < 0) throw new Error('Cannot make qname out of <' + uri + '>');
1167
-
1168
- for (var k = j + 1; k < uri.length; k++) {
1169
- if (this._notNameChars.indexOf(uri[k]) >= 0) {
1170
- throw new Error('Invalid character "' + uri[k] + '" cannot be in XML qname for URI: ' + uri);
1171
- }
1172
- }
1173
-
1174
- var localid = uri.slice(j + 1);
1175
- var namesp = uri.slice(0, j + 1);
1176
-
1177
- if (this.defaultNamespace && this.defaultNamespace === namesp && this.flags.indexOf('d') < 0) {
1178
- // d -> suppress default
1179
- return localid;
1180
- }
1181
-
1182
- var prefix = this.prefixes[namesp];
1183
- if (!prefix) prefix = this.makeUpPrefix(namesp);
1184
- namespaceCounts[namesp] = true;
1185
- return prefix + ':' + localid;
1186
- }
1187
-
1188
- var qname = qnameMethod.bind(this); // Body of toXML:
1189
-
1190
- var tree = statementListToXMLTree(sts);
1191
- var str = '<rdf:RDF';
1192
-
1193
- if (this.defaultNamespace) {
1194
- str += ' xmlns="' + escapeForXML(this.defaultNamespace) + '"';
1018
+ }
1019
+ function makeRelativeMethod(jsonldString) {
1020
+ if (this.base.includes('#')) throw new Error(`${this.base} must be an URL, it is an URI`);
1021
+ const id = '"@id": "'; // find URI
1022
+ const regex = new RegExp(id + this.base, 'g');
1023
+ let result,
1024
+ indices = [];
1025
+ // store indices at begin and end of URI
1026
+ while (result = regex.exec(jsonldString)) {
1027
+ indices.push(result.index + id.length);
1028
+ indices.push(jsonldString.indexOf('"', result.index + id.length));
1195
1029
  }
1196
-
1197
- for (var ns in namespaceCounts) {
1198
- if (!namespaceCounts.hasOwnProperty(ns)) continue; // Rel uris in xml ns is not strictly allowed in the XMLNS spec but needed in practice often
1199
-
1200
- var ns2 = this.base && this.flags.includes('z') ? Util.uri.refTo(this.base, ns) : ns;
1201
- str += '\n xmlns:' + this.prefixes[ns] + '="' + escapeForXML(ns2) + '"';
1030
+ for (let i = indices.length - 2; i >= 0; i = i - 2) {
1031
+ const idUri = jsonldString.substring(indices[i], indices[i + 1]);
1032
+ jsonldString = jsonldString.replace(idUri, Uri.refTo(this.base, idUri));
1202
1033
  }
1034
+ return jsonldString;
1035
+ }
1036
+ const addPrefix = addPrefixMethod.bind(this);
1037
+ const context = contextMethod.bind(this);
1038
+ const makeRelative = makeRelativeMethod.bind(this);
1039
+ const n3String = this.statementsToNTriples(sts);
1040
+ let contextObj = JSON.parse(context(n3String));
1041
+ return jsonld.fromRDF(n3String, {
1042
+ format: 'application/n-quads'
1043
+ }).then(jsonldObj => {
1044
+ return jsonld.compact(jsonldObj, contextObj);
1045
+ })
1046
+ // TODO collections, compact do not do it on rdf:first rdf:rest
1047
+ .then(jsonldCompactObj => {
1048
+ return JSON.stringify(jsonldCompactObj, null, 2);
1049
+ }).then(jsonldString => {
1050
+ return makeRelative(jsonldString);
1051
+ }).catch(e => {
1052
+ throw e;
1053
+ });
1054
+ }
1055
+ }
1203
1056
 
1204
- str += '>';
1205
- var tree2 = [str, tree, '</rdf:RDF>']; // @@ namespace declrations
1206
-
1207
- return XMLtreeToString(tree2, -1);
1208
- } // End @@ body
1209
-
1210
- }]);
1211
- return Serializer;
1212
- }(); // String escaping utilities
1213
-
1214
-
1057
+ // String escaping utilities
1215
1058
  exports.Serializer = Serializer;
1216
-
1217
1059
  function hexify(str) {
1218
1060
  // also used in parser
1219
1061
  return encodeURI(str);
1220
1062
  }
1221
-
1222
1063
  function backslashUify(str) {
1223
1064
  var res = '';
1224
1065
  var k;
1225
-
1226
1066
  for (var i = 0; i < str.length; i++) {
1227
1067
  k = str.charCodeAt(i);
1228
-
1229
1068
  if (k > 65535) {
1230
- res += "\\U" + ('00000000' + k.toString(16)).slice(-8); // convert to upper?
1069
+ res += '\\U' + ('00000000' + k.toString(16)).slice(-8); // convert to upper?
1231
1070
  } else if (k > 126) {
1232
- res += "\\u" + ('0000' + k.toString(16)).slice(-4);
1071
+ res += '\\u' + ('0000' + k.toString(16)).slice(-4);
1233
1072
  } else {
1234
1073
  res += str[i];
1235
1074
  }
1236
1075
  }
1237
-
1238
1076
  return res;
1239
1077
  }