vis-chronicle 1.2.5 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -95,8 +95,6 @@ Item properties:
95
95
  * `general`: General query segment, usually for selecting the item and property.
96
96
  * `start`: Query segment for selecting the start value.
97
97
  * `end`: Query segment for selecting the end value.
98
- * `startPath`: Another way of writing Wikidata queries. TODO.
99
- * `endPath`: See `startPath`
100
98
  * `expectedDuration`: Describes the expected duration, for hinting if the start or end is missing.
101
99
  * `min`: The absolute minimum duration.
102
100
  * `max`: The absolute maximum duration.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vis-chronicle",
3
- "version": "1.2.5",
3
+ "version": "1.3.5",
4
4
  "description": "Generates JSON for populating a vis.js timeline from Wikidata queries.",
5
5
  "keywords": [
6
6
  "wikidata",
package/src/fetch.js CHANGED
@@ -112,7 +112,6 @@ entryPoint()
112
112
  var templateItem = wikidata.inputSpec.items[i]
113
113
  if (templateItem.itemQuery || templateItem.items)
114
114
  {
115
- //TODO: caching for item queries
116
115
  wikidata.inputSpec.items.splice(i, 1)
117
116
  const newItems = await wikidata.createTemplateItems(templateItem)
118
117
  for (const newItem of newItems)
@@ -200,8 +199,16 @@ entryPoint()
200
199
  {
201
200
  if (item.finished) continue
202
201
 
203
- if (item.startPath) pathQueries.push(item.startPath)
204
- if (item.endPath) pathQueries.push(item.endPath)
202
+ if (item.startPath)
203
+ {
204
+ item.startPath = wikidata.replaceQueryWildcards(item.startPath, item)
205
+ pathQueries.push(item.startPath)
206
+ }
207
+ if (item.endPath)
208
+ {
209
+ item.endPath = wikidata.replaceQueryWildcards(item.endPath, item)
210
+ pathQueries.push(item.endPath)
211
+ }
205
212
 
206
213
  // the bundle key is the queries, as well as any wildcard parameters
207
214
  const keyObject = {}
package/src/index.js CHANGED
@@ -3,5 +3,5 @@ module.exports = {
3
3
 
4
4
  SparqlBuilder: require('./sparql-builder'),
5
5
  Wikidata: require('./wikidata.js'),
6
- flattenRelativeDate: require('./relativeDates.js')
7
6
  }
7
+ module.exports = Object.assign(module.exports, require('./relativeDates.js'))
@@ -24,54 +24,61 @@ function durationToWikidataPrecision(duration)
24
24
  else return 9
25
25
  }
26
26
 
27
- // Flattens a relative date string into a hard date string
28
- module.exports = function flattenRelativeDate(wikidataCache, dateString)
27
+ /**
28
+ * Breaks down a relative date path into its components.
29
+ * @param {*} dateString
30
+ * @returns An array of strings, or null.
31
+ */
32
+ function breakRelativeDate(dateString)
29
33
  {
30
34
  if (dateString == '') return null
31
35
 
32
36
  // parse out relative date components
33
- var relSplit
34
37
  var match = dateString.match(wikidata.pathQueryRegex)
35
- if (match)
36
- {
37
- relSplit = match.slice(1)
38
- }
39
- else
38
+ if (!match)
40
39
  {
41
40
  console.error(`Failed to parse relative date '${dateString}'.`)
42
41
  return null
43
42
  }
44
43
 
45
- if (!relSplit[0])
44
+ const dateComponents = [ match[1] ]
45
+ var opStartIndex = 0
46
+ const operatorString = match[2]
47
+ if (operatorString.length > 0)
48
+ {
49
+ for (var i = 1; i < operatorString.length; i++)
50
+ {
51
+ if (operatorString[i] == '+' || operatorString[i] == '>')
52
+ {
53
+ dateComponents.push(operatorString.substring(opStartIndex, i))
54
+ opStartIndex = i
55
+ }
56
+ }
57
+ dateComponents.push(operatorString.substring(opStartIndex, i))
58
+ }
59
+ return dateComponents
60
+ }
61
+
62
+ // Flattens a relative date string into a hard date string
63
+ function flattenRelativeDate(wikidataCache, dateString)
64
+ {
65
+ var parsedPath = breakRelativeDate(dateString)
66
+ if (!parsedPath)
46
67
  {
47
68
  return null
48
69
  }
49
- else if (!wikidataCache[relSplit[0]])
70
+ else if (!wikidataCache[parsedPath[0]])
50
71
  {
51
- console.error(`Date for '${relSplit[0]}' wasn't cached.`)
72
+ console.error(`Date for '${parsedPath[0]}' wasn't cached.`)
52
73
  return null
53
74
  }
54
75
  else
55
76
  {
56
- const cacheEntry = wikidataCache[relSplit[0]]
57
- if (cacheEntry.value && relSplit.length > 1)
77
+ const cacheEntry = wikidataCache[parsedPath[0]]
78
+ if (cacheEntry.value && parsedPath.length > 1)
58
79
  {
59
80
  // break up operators
60
- const dateOperators = []
61
- var opStartIndex = 0
62
- const operatorString = relSplit[1]
63
- if (operatorString.length > 0)
64
- {
65
- for (var i = 1; i < operatorString.length; i++)
66
- {
67
- if (operatorString[i] == '+' || operatorString[i] == '>')
68
- {
69
- dateOperators.push(operatorString.substring(opStartIndex, i))
70
- opStartIndex = i
71
- }
72
- }
73
- dateOperators.push(operatorString.substring(opStartIndex, i))
74
- }
81
+ const dateOperators = parsedPath.slice(1)
75
82
 
76
83
  // handle relative segments of date
77
84
  // About precision:
@@ -156,4 +163,6 @@ module.exports = function flattenRelativeDate(wikidataCache, dateString)
156
163
  return {...cacheEntry}
157
164
  }
158
165
  }
159
- }
166
+ }
167
+
168
+ module.exports = { breakRelativeDate, flattenRelativeDate }
package/src/render.js CHANGED
@@ -461,7 +461,12 @@ renderer.produceOutput = function(inputSpec, items)
461
461
  {
462
462
  const labelItem = {...outputItem}
463
463
  labelItem.id += "-label"
464
- labelItem.className = [labelItem.className, "visc-toplabel"].join(' '),
464
+
465
+ var classes = labelItem.className.split(' ')
466
+ classes = classes.filter(c => c != "visc-left-connection" && c != "visc-right-connection")
467
+ classes.push("visc-toplabel")
468
+ labelItem.className = classes.join(' ')
469
+
465
470
  outputObject.items.push(labelItem)
466
471
  outputItem.content = outputItem.content ? "&nbsp;" : ""
467
472
  }
package/src/wikidata.js CHANGED
@@ -12,9 +12,9 @@ const wikidata = module.exports = {
12
12
  verboseLogging: false,
13
13
 
14
14
  /**
15
- *
15
+ * Caches results for SPARQL queries, using the query string as the key.
16
16
  */
17
- cache: {},
17
+ queryCache: {},
18
18
 
19
19
  /**
20
20
  * Caches results for path queries, using the path as the key.
@@ -25,9 +25,9 @@ const wikidata = module.exports = {
25
25
  cacheBuster: undefined,
26
26
 
27
27
  /**
28
- * Relative path to the term cache file.
28
+ * Relative path to the query cache file.
29
29
  */
30
- termCacheFile: "intermediate/wikidata-term-cache.json",
30
+ queryCacheFile: "intermediate/sparql-query-cache.json",
31
31
 
32
32
  /**
33
33
  * Relative path to the path cache file.
@@ -126,8 +126,8 @@ const wikidata = module.exports = {
126
126
  {
127
127
  try
128
128
  {
129
- const contents = await fs.promises.readFile(this.termCacheFile)
130
- this.cache = JSON.parse(contents)
129
+ const contents = await fs.promises.readFile(this.queryCacheFile)
130
+ this.queryCache = JSON.parse(contents)
131
131
  }
132
132
  catch
133
133
  {
@@ -147,11 +147,11 @@ const wikidata = module.exports = {
147
147
 
148
148
  writeCache: async function()
149
149
  {
150
- await mypath.ensureDirectoryForFile(this.termCacheFile)
150
+ await mypath.ensureDirectoryForFile(this.queryCacheFile)
151
151
 
152
- fs.writeFile(this.termCacheFile, JSON.stringify(this.cache), err => {
152
+ fs.writeFile(this.queryCacheFile, JSON.stringify(this.queryCache), err => {
153
153
  if (err) {
154
- console.error(`Error writing wikidata term cache:`)
154
+ console.error(`Error writing wikidata query cache:`)
155
155
  console.error(err)
156
156
  }
157
157
  })
@@ -184,25 +184,32 @@ const wikidata = module.exports = {
184
184
  }
185
185
  },
186
186
 
187
- postprocessQueryTerm: function(context, term, item)
187
+ replaceQueryWildcards: function(term, item, itemPrefix = "")
188
188
  {
189
- if (!term)
190
- {
191
- return term;
192
- }
193
-
194
189
  // replace query wildcards
195
190
  for (const key in item)
196
191
  {
197
192
  var insertValue = item[key]
198
193
  if (typeof insertValue === "string" && insertValue.startsWith("Q"))
199
- insertValue = "wd:" + insertValue
194
+ insertValue = itemPrefix + insertValue
200
195
  term = term.replaceAll(`{${key}}`, insertValue)
201
196
  }
202
197
 
203
198
  // detect unreplaced wildcards
204
199
  //TODO:
205
200
 
201
+ return term
202
+ },
203
+
204
+ preprocessQueryTerm: function(context, term, item)
205
+ {
206
+ if (!term)
207
+ {
208
+ return term
209
+ }
210
+
211
+ term = this.replaceQueryWildcards(term, item, "wd:")
212
+
206
213
  // terminate term
207
214
  if (!term.trim().endsWith("."))
208
215
  {
@@ -238,7 +245,7 @@ const wikidata = module.exports = {
238
245
 
239
246
  //TODO: validate query has required wildcards
240
247
 
241
- queryTerm = this.postprocessQueryTerm(inQueryTerm, queryTerm, item)
248
+ queryTerm = this.preprocessQueryTerm(inQueryTerm, queryTerm, item)
242
249
  return queryTerm
243
250
  },
244
251
 
@@ -275,7 +282,7 @@ const wikidata = module.exports = {
275
282
  if (typeof queryTerm === 'string' || queryTerm instanceof String)
276
283
  {
277
284
  return {
278
- value: this.postprocessQueryTerm(inQueryTerm, queryTerm, item),
285
+ value: this.preprocessQueryTerm(inQueryTerm, queryTerm, item),
279
286
  min: "?_prop pqv:P1319 ?_min_value.",
280
287
  max: "?_prop pqv:P1326 ?_max_value."
281
288
  }
@@ -285,7 +292,7 @@ const wikidata = module.exports = {
285
292
  const result = {}
286
293
  for (const key in queryTerm)
287
294
  {
288
- result[key] = this.postprocessQueryTerm(inQueryTerm, queryTerm[key], item)
295
+ result[key] = this.preprocessQueryTerm(inQueryTerm, queryTerm[key], item)
289
296
  }
290
297
  return result
291
298
  }
@@ -393,15 +400,7 @@ const wikidata = module.exports = {
393
400
  queryBuilder.addOptionalQueryTerm(`${propVar} wikibase:rank ${rankVar}.`)
394
401
 
395
402
  const query = queryBuilder.build()
396
-
397
- // read cache
398
- const cacheKey = query
399
- if (!this.skipCache && !item.skipCache && this.cache[cacheKey])
400
- {
401
- return this.cache[cacheKey]
402
- }
403
-
404
- const data = await this.runQuery(query)
403
+ const data = await this.runQuery(query, item.skipCache)
405
404
  console.log(`\tQuery for ${item.id} returned ${data.results.bindings.length} results.`)
406
405
 
407
406
  const readBinding = function(binding)
@@ -487,7 +486,6 @@ const wikidata = module.exports = {
487
486
  }
488
487
  }
489
488
 
490
- this.cache[cacheKey] = result;
491
489
  return result;
492
490
  },
493
491
 
@@ -695,7 +693,11 @@ const wikidata = module.exports = {
695
693
  queryBuilder.addWikibaseLabel(this.lang)
696
694
 
697
695
  const query = queryBuilder.build()
698
- const data = await this.runQuery(query)
696
+ const data = await this.runQuery(query, templateItem.skipCache)
697
+ if (!data)
698
+ {
699
+ throw 'No response data from Wikidata query.'
700
+ }
699
701
 
700
702
  const newItems = []
701
703
 
@@ -723,8 +725,13 @@ const wikidata = module.exports = {
723
725
  },
724
726
 
725
727
  // runs a SPARQL query
726
- runQuery: async function(query)
728
+ runQuery: async function(query, skipCache = false)
727
729
  {
730
+ if (!skipCache && !this.skipCache && this.queryCache[query])
731
+ {
732
+ return this.queryCache[query]
733
+ }
734
+
728
735
  if (this.verboseLogging) console.log(query)
729
736
 
730
737
  assert(this.options)
@@ -739,6 +746,7 @@ const wikidata = module.exports = {
739
746
  else
740
747
  {
741
748
  const data = await response.json()
749
+ this.queryCache[query] = data
742
750
  return data
743
751
  }
744
752
  }