wikibase-cli 20.0.0 → 20.1.0

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
@@ -55,7 +55,7 @@ See [CHANGELOG.md](CHANGELOG.md) for version info
55
55
  ## Dependencies
56
56
 
57
57
  ### General
58
- * [NodeJs](https://nodejs.org) **>= v18** (recommended way to install it: use [NVM](https://github.com/creationix/nvm) to install the latest LTS version `nvm install --lts`)
58
+ * [NodeJS](https://nodejs.org) **>= v20.12.0** (Older NodeJS versions can be used for older wikibase-cli version, see [changelogs](./CHANGELOG.md). Recommendable way to install NodeJS: you may use [NVM](https://github.com/creationix/nvm) to install the latest LTS version `nvm install --lts`)
59
59
  * [Git](https://git-scm.com/)
60
60
 
61
61
  ### Per feature
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { map, partition, uniq, without } from 'lodash-es'
2
+ import { map, partition, uniq, values, without } from 'lodash-es'
3
3
  import { grey } from 'tiny-chalk'
4
4
  import { isEntityId, isPropertyId } from 'wikibase-sdk'
5
5
  import errors_ from '#lib/errors'
@@ -8,9 +8,10 @@ import { makeSparqlQuery } from '#lib/make_sparql_query'
8
8
  import program from '#lib/program'
9
9
 
10
10
  await program
11
+ .option('-f, --format <format>', 'Available alternative formats: mermaid')
11
12
  .process('graph-path')
12
13
 
13
- const { args } = program
14
+ const { args, format } = program
14
15
  const [ subject, property, joinedObjects ] = args
15
16
 
16
17
  if (!(subject && property && joinedObjects)) {
@@ -41,35 +42,44 @@ if (rows.length === 0) {
41
42
  const intermediaries = uniq(map(rows, 'intermediary'))
42
43
  const relevantRows = rows.filter(row => intermediaries.includes(row.next))
43
44
 
44
- let remainingRows = relevantRows
45
- let nextSubjects = [ subject ]
46
- let paths = [ subject ]
47
- const replacedPaths = []
45
+ const allEntityIds = uniq(relevantRows.flatMap(row => values(row)))
46
+ const labels = await getEntitiesLabels(allEntityIds, program.lang)
48
47
 
49
- while (remainingRows.length > 0) {
50
- const newPaths = []
51
- const [ nextRows, rest ] = partition(remainingRows, ({ intermediary }) => {
52
- return nextSubjects.includes(intermediary)
53
- })
54
- if (rest.length === remainingRows.length) throw new Error('stuck')
55
- remainingRows = rest
56
- nextRows.forEach(({ intermediary, next }) => {
57
- const relevantPaths = paths.filter(path => {
58
- const pathParts = path.split('.')
59
- return pathParts.at(-1) === intermediary
60
- })
61
- const updatedPaths = relevantPaths.map(path => `${path}.${next}`)
62
- // Leave the relevantPaths in paths, to let other rows fork them if needed
63
- replacedPaths.push(...relevantPaths)
64
- newPaths.push(...updatedPaths)
65
- })
66
- nextSubjects = uniq(map(nextRows, 'next'))
67
- paths = [ ...without(paths, ...replacedPaths), ...newPaths ]
68
- }
48
+ if (format === 'mermaid') {
49
+ let output = 'graph LR\n'
50
+ const getNodeLabel = id => `${labels[id]} (${id})`
51
+ for (const { intermediary, next } of relevantRows) {
52
+ output += `${getNodeLabel(intermediary)} --> ${getNodeLabel(next)}\n`
53
+ }
54
+ console.log(output.trim())
55
+ } else {
56
+ let remainingRows = relevantRows
57
+ let nextSubjects = [ subject ]
58
+ let paths = [ subject ]
59
+ const replacedPaths = []
69
60
 
70
- const allParts = uniq(paths.flatMap(path => path.split('.')))
71
- const labels = await getEntitiesLabels(allParts, program.lang)
61
+ while (remainingRows.length > 0) {
62
+ const newPaths = []
63
+ const [ nextRows, rest ] = partition(remainingRows, ({ intermediary }) => {
64
+ return nextSubjects.includes(intermediary)
65
+ })
66
+ if (rest.length === remainingRows.length) throw new Error('stuck')
67
+ remainingRows = rest
68
+ nextRows.forEach(({ intermediary, next }) => {
69
+ const relevantPaths = paths.filter(path => {
70
+ const pathParts = path.split('.')
71
+ return pathParts.at(-1) === intermediary
72
+ })
73
+ const updatedPaths = relevantPaths.map(path => `${path}.${next}`)
74
+ // Leave the relevantPaths in paths, to let other rows fork them if needed
75
+ replacedPaths.push(...relevantPaths)
76
+ newPaths.push(...updatedPaths)
77
+ })
78
+ nextSubjects = uniq(map(nextRows, 'next'))
79
+ paths = [ ...without(paths, ...replacedPaths), ...newPaths ]
80
+ }
72
81
 
73
- for (const path of paths) {
74
- console.log(path.split('.').map(part => `${labels[part]} ${grey(`(${part})`)}`).join(' → '))
82
+ for (const path of paths) {
83
+ console.log(path.split('.').map(part => `${labels[part]} ${grey(`(${part})`)}`).join(' → '))
84
+ }
75
85
  }
@@ -1,7 +1,7 @@
1
1
  export default {
2
2
  alias: 'gp',
3
3
  args: '<subject> <property> <object>',
4
- description: 'Find the path between a subject and an object on the entity relations graph',
4
+ description: 'Find the path between a subject and an object via a given property, on the entities relations graph',
5
5
  options: {
6
6
  lang: true,
7
7
  verbose: true,
@@ -13,5 +13,6 @@ export default {
13
13
  examples: [
14
14
  { args: 'Q336 P279 Q5891', comment: 'Find by which path science (Q336) is a subclass of (P279) philosophy (Q5891)' },
15
15
  { args: 'Q336 P279 Q5891,Q2198855,Q3326717,Q968159', comment: 'Find by which path science (Q336) is a subclass of (P279) either philosophy (Q5891), literary movement (Q3326717), or art movement (Q968159)' },
16
+ { args: 'wd gp Q506259 P279 Q2509280 --format mermaid | mermaid-ascii -f -', comment: 'Output graph in the [mermaid format](https://mermaid.js.org/) and pipe it to [mermaid-ascii](https://github.com/AlexanderGrooff/mermaid-ascii) to visualize the graph in the terminal' },
16
17
  ],
17
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikibase-cli",
3
- "version": "20.0.0",
3
+ "version": "20.1.0",
4
4
  "description": "A command-line interface to Wikibase",
5
5
  "type": "module",
6
6
  "main": "index.js",