wikibase-cli 18.0.4 → 18.2.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/bin/wb-badges.js CHANGED
@@ -5,6 +5,8 @@ import { exitOnMissingInstance } from '#lib/exit_on_missing'
5
5
  import program from '#lib/program'
6
6
  import { get } from '#lib/request'
7
7
 
8
+ program.canHaveZeroArguments = true
9
+
8
10
  await program.process('badges')
9
11
 
10
12
  const { instance } = program
package/bin/wb-config.js CHANGED
@@ -5,6 +5,8 @@ import { configurateCredentials } from '#lib/config/credentials_config'
5
5
  import fileOps from '#lib/config/file_operations'
6
6
  import program from '#lib/program'
7
7
 
8
+ program.canHaveZeroArguments = true
9
+
8
10
  await program.process('config')
9
11
 
10
12
  const { args, json } = program
package/bin/wb-convert.js CHANGED
@@ -5,6 +5,8 @@ import errors_ from '#lib/errors'
5
5
  import { getStdinInput } from '#lib/get_stdin_input'
6
6
  import program from '#lib/program'
7
7
 
8
+ program.canHaveZeroArguments = true
9
+
8
10
  await program
9
11
  .option('-s, --subjects [subjects...]', 'set a subject')
10
12
  .option('-p, --property <property>', 'set a property')
package/bin/wb-data.js CHANGED
@@ -4,6 +4,8 @@ import { parseGuid } from '#lib/parse_command_utils'
4
4
  import program from '#lib/program'
5
5
  import { tolerantIdParserFactory } from '#lib/tolerant_id_parser'
6
6
 
7
+ program.acceptsArgsOnStdin = true
8
+
7
9
  await program
8
10
  .option('-s, --simplify', 'get simplified entities data')
9
11
  .option('-k, --keep <props>', 'data to keep when simplifying claims (ids,richvalues,types,references,qualifiers,hashes,nontruthy,nondeprecated,ranks)')
@@ -9,6 +9,8 @@ import { readIdsFromStdin } from '#lib/read_ids_from_stdin'
9
9
  import { tolerantIdParserFactory } from '#lib/tolerant_id_parser'
10
10
  import { getWbk } from '#lib/wbk'
11
11
 
12
+ program.acceptsArgsOnStdin = true
13
+
12
14
  await program
13
15
  .option('-p, --props <props>', 'request only certain properties (info, sitelinks, aliases, labels, descriptions, claims, datatype)')
14
16
  .option('-r, --revision <id>', 'request a specific revision')
@@ -7,12 +7,12 @@ import { parseGuid } from '#lib/parse_command_utils'
7
7
  import { polymorphicCommandArgsParser } from '#lib/polymorphic_command_args_parser'
8
8
 
9
9
  const inlineArgsParser = args => {
10
- let [ guid, id, property ] = args
10
+ let [ guid, id, property, newValue ] = args
11
11
  if (isPropertyClaimsId(guid)) {
12
- return [ { propertyClaimsId: guid, id, property } ]
12
+ return [ { propertyClaimsId: guid, id, property, newValue } ]
13
13
  } else {
14
14
  guid = parseGuid(guid)
15
- return [ { guid, id, property } ]
15
+ return [ { guid, id, property, newValue } ]
16
16
  }
17
17
  }
18
18
  program.customArgsParser = polymorphicCommandArgsParser({ inlineArgsParser })
package/bin/wb-props.js CHANGED
@@ -7,6 +7,8 @@ import getPatternFilter from '#lib/get_pattern_filter'
7
7
  import program from '#lib/program'
8
8
  import resetProperties from '#lib/reset_properties'
9
9
 
10
+ program.canHaveZeroArguments = true
11
+
10
12
  await program
11
13
  .option('-d, --details', 'include properties labels, types, descriptions, and aliases')
12
14
  .option('-t, --type [type]', 'include properties types, or if a type is specified, keep only properties with that type')
package/bin/wb-query.js CHANGED
@@ -7,6 +7,9 @@ import { outputFactory } from '#lib/output'
7
7
  import program from '#lib/program'
8
8
  import { sparqlQueryCommand } from '#lib/sparql_query_command'
9
9
 
10
+ // All arguments are passed as options values making program.args.length === 0 likely
11
+ program.canHaveZeroArguments = true
12
+
10
13
  await program
11
14
  .option('-s, --subject <subject>', 'set a subject')
12
15
  .option('-p, --property <property>', 'set a property')
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { values } from 'lodash-es'
2
+ import { chunk, values } from 'lodash-es'
3
3
  import { isEntityId } from 'wikibase-sdk'
4
4
  import errors_ from '#lib/errors'
5
5
  import { exitOnMissingInstance } from '#lib/exit_on_missing'
@@ -9,58 +9,82 @@ import { get } from '#lib/request'
9
9
  import { isPositiveIntegerString } from '#lib/types'
10
10
  import { getWbk } from '#lib/wbk'
11
11
 
12
+ program.acceptsArgsOnStdin = true
13
+
12
14
  await program
13
15
  .option('-s, --start <date>', 'start date')
14
16
  .option('-e, --end <date>', 'end date')
15
17
  .option('-n, --limit <num>', 'maximum number of revisions')
18
+ .option('-p, --props <props>', 'requested props, separated by a comma. Available props: https://www.mediawiki.org/wiki/API:Revisions#query+revisions:rvprop')
16
19
  .process('revisions')
17
20
 
18
21
  exitOnMissingInstance(program.instance)
19
22
 
20
23
  const { getRevisions } = getWbk(program)
21
24
 
22
- // Not parsing the ids with ../lib/tolerant_id_parser as that would
23
- // remove prefixes which are required for entities out of the main namespace
24
- // Ex: Property:P570
25
- const ids = program.args
26
- if (!(ids && ids.length > 0)) program.helpAndExit(0)
27
-
28
- ids.forEach(id => {
29
- let [ prefix, entityId ] = id.split(':')
30
- if (entityId) {
31
- if (prefix !== 'Property' && prefix !== 'Item') {
32
- throw new Error(`invalid entity prefix: ${prefix}`)
25
+ async function fetchAndLogRevisions (ids) {
26
+ ids.forEach(id => {
27
+ let [ prefix, entityId ] = id.split(':')
28
+ if (entityId) {
29
+ if (prefix !== 'Property' && prefix !== 'Item') {
30
+ throw new Error(`invalid entity prefix: ${prefix}`)
31
+ }
32
+ } else {
33
+ entityId = prefix
33
34
  }
34
- } else {
35
- entityId = prefix
36
- }
37
- if (!isEntityId(entityId)) throw new Error(`invalid entity id: ${id}`)
38
- })
35
+ if (!isEntityId(entityId)) throw new Error(`invalid entity id: ${id}`)
36
+ })
37
+
38
+ const query = {}
39
+ let { start, end, limit, props, verbose } = program
40
+ if (isPositiveIntegerString(start)) start = parseInt(start)
41
+ if (isPositiveIntegerString(end)) end = parseInt(end)
39
42
 
40
- const query = {}
41
- let { start, end, limit, verbose } = program
42
- if (isPositiveIntegerString(start)) start = parseInt(start)
43
- if (isPositiveIntegerString(end)) end = parseInt(end)
43
+ if (start != null) query.start = start
44
+ if (end != null) query.end = end
45
+ if (limit != null) query.limit = limit
46
+ if (props != null) query.prop = props?.split(/[,|]/)
44
47
 
45
- query.start = start
46
- query.end = end
47
- query.limit = limit
48
+ // Prevent error "titles, pageids or a generator was used to supply multiple pages, but the rvlimit, rvstartid, rvendid, rvdir=newer, rvuser, rvexcludeuser, rvstart, and rvend parameters may only be used on a single page. "
49
+ const usesSinglePageParam = limit != null || start != null || end != null
48
50
 
49
- const getAndLogRevisions = id => {
50
- const url = getRevisions({ ids: [ id ], ...query })
51
- if (verbose) console.log(`revision query: ${id}`, url)
52
- return get(url)
53
- .then(body => values(body.query.pages)[0])
51
+ async function getAndLogRevisions (ids) {
52
+ const url = getRevisions({ ids, ...query })
53
+ if (verbose) console.log(`revision query: ${ids}`, url)
54
+ const body = await get(url)
55
+ return values(body.query.pages)
56
+ }
57
+
58
+ if (usesSinglePageParam) {
59
+ const idsBatches = chunk(ids, 10)
60
+ for (const batch of idsBatches) {
61
+ // Getting revisisions data individually to be able to pass parameters
62
+ // cf https://github.com/maxlath/wikibase-sdk/blob/master/docs/get_revisions.md
63
+ await Promise.all(batch.map(getAndLogRevisions))
64
+ .then(logNdjson)
65
+ .catch(errors_.exit)
66
+ }
67
+ } else {
68
+ const idsBatches = chunk(ids, 50)
69
+ for (const batch of idsBatches) {
70
+ await getAndLogRevisions(batch)
71
+ .then(logNdjson)
72
+ .catch(errors_.exit)
73
+ }
74
+ }
54
75
  }
55
76
 
56
- if (ids.length === 1) {
57
- getAndLogRevisions(ids[0])
58
- .then(data => console.log(JSON.stringify(data)))
59
- .catch(errors_.exit)
77
+ // process.stdin.isTTY will be undefined if the process is receiving
78
+ // its stdin from another process
79
+ if (program.args.length === 0 && process.stdin.isTTY) {
80
+ program.helpAndExit(0)
81
+ } else if (program.args.length > 0) {
82
+ // Not parsing the ids with ../lib/tolerant_id_parser as that would
83
+ // remove prefixes which are required for entities out of the main namespace
84
+ // Ex: Property:P570
85
+ const ids = program.args
86
+ fetchAndLogRevisions(ids)
60
87
  } else {
61
- // Getting revisisions data individually to be able to pass parameters
62
- // cf https://github.com/maxlath/wikibase-sdk/blob/master/docs/get_revisions.md
63
- Promise.all(ids.map(getAndLogRevisions))
64
- .then(logNdjson)
65
- .catch(errors_.exit)
88
+ const { readIdsFromStdin } = await import('#lib/read_ids_from_stdin')
89
+ readIdsFromStdin(fetchAndLogRevisions)
66
90
  }
@@ -106,11 +106,10 @@ function getWbEditConfig () {
106
106
  const { editGroup } = program
107
107
  let { summary, baserevid, maxlag } = program
108
108
 
109
+ let summarySuffix
109
110
  if (editGroup) {
110
111
  const compactEditGroupUrl = getEditGroupUrl(':toollabs:', editGroup)
111
- summary = summary || ''
112
- summary += ` ([[${compactEditGroupUrl}|details]])`
113
- summary = summary.trim()
112
+ summarySuffix = `([[${compactEditGroupUrl}|details]])`
114
113
  }
115
114
 
116
115
  const { instance, credentials } = config
@@ -132,6 +131,7 @@ function getWbEditConfig () {
132
131
  instance,
133
132
  credentials: { oauth, username, password },
134
133
  summary,
134
+ summarySuffix,
135
135
  baserevid,
136
136
  tags,
137
137
  bot: config.bot,
package/lib/log_ndjson.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Log as newline-delimited JSON: one obj JSON per line. No comma.
2
2
 
3
3
  export default array => {
4
- for (const obj of array) {
4
+ for (const obj of array.flat()) {
5
5
  process.stdout.write(JSON.stringify(obj))
6
6
  process.stdout.write('\n')
7
7
  }
package/lib/program.js CHANGED
@@ -27,9 +27,9 @@ program.process = async command => {
27
27
  } else if (showHelp) {
28
28
  program.helpAndExit(0)
29
29
  } else if (program.args.length === 0 && !program.batch) {
30
- if (commandsTakingArgsOnStdin.includes(command)) {
30
+ if (program.acceptsArgsOnStdin) {
31
31
  if (process.stdin.isTTY) program.helpAndExit(0)
32
- } else if (!commandsAcceptingZeroArguments.includes(command)) {
32
+ } else if (!program.canHaveZeroArguments) {
33
33
  program.helpAndExit(0)
34
34
  }
35
35
  }
@@ -48,23 +48,6 @@ function getOptionsKeyValues (options) {
48
48
  return Object.fromEntries(optionsEntries)
49
49
  }
50
50
 
51
- const commandsAcceptingZeroArguments = [
52
- // Can be called without argument
53
- 'props',
54
- 'badges',
55
- // All arguments are passed as options values
56
- // making program.args.length === 0 likely
57
- 'query',
58
- 'convert',
59
- // Needs to also log the current config
60
- 'config',
61
- ]
62
-
63
- const commandsTakingArgsOnStdin = [
64
- 'data',
65
- 'generate-template',
66
- ]
67
-
68
51
  const parseArgv = (argv, isCommandsWithCustomHelpMenu) => {
69
52
  // Make a copy to be able to mutate the array without affecting other operations
70
53
  // that might rely on that array being intact
@@ -1,12 +1,15 @@
1
1
  import split from 'split'
2
2
  import through from 'through'
3
+ import program from '#lib/program'
3
4
 
4
5
  let ids = []
5
6
 
6
7
  export function readIdsFromStdin (handleIdsBatch) {
7
- const write = function (id) {
8
+ let count = 0
9
+ async function write (id) {
8
10
  id = id.trim()
9
11
  if (id === '') return
12
+ count++
10
13
  ids.push(id)
11
14
  if (ids.length < 50) return
12
15
 
@@ -15,18 +18,23 @@ export function readIdsFromStdin (handleIdsBatch) {
15
18
  const batch = ids
16
19
  ids = []
17
20
 
18
- handleIdsBatch(batch)
19
- .then(() => this.resume())
21
+ await handleIdsBatch(batch)
22
+ this.resume()
20
23
  }
21
24
 
22
- const end = function () {
25
+ async function end () {
26
+ if (count === 0) program.helpAndExit(0)
23
27
  if (ids.length === 0) return this.emit('end')
24
- handleIdsBatch(ids)
25
- .then(this.emit.bind(this, 'end'))
28
+ await handleIdsBatch(ids)
29
+ this.emit('end')
26
30
  }
27
31
 
28
32
  process.stdin
29
33
  .pipe(split(/\s/))
30
34
  .pipe(through(write, end))
31
35
  .on('error', console.error)
36
+
37
+ setTimeout(() => {
38
+ if (count === 0) program.helpAndExit(0)
39
+ }, 500)
32
40
  }
package/metadata/data.js CHANGED
@@ -16,7 +16,7 @@ export default {
16
16
  { args: '--simplify Q123', comment: 'fetch Q123 simplified data' },
17
17
  { args: '--simplify --keep ids,references,qualifiers,hashes,nontruthy Q123', comment: 'simplified Q123 data, but keep some attributes' },
18
18
  { args: '--simplify --keep all Q123', comment: 'same as above' },
19
- { args: 'Q1496 | jd labels.pt', comment: "take advantage of the raw data being output as JSON\n # to pass it to a JSON parsers (here jsondepth a.k.a. jd)\n # and get only the piece of data you're looking for" },
20
- { args: '--simplify --keep ids Q123 | jd claims.P138 -j', comment: 'get Q123 P138 claims ids' },
19
+ { args: 'Q1496 | jq .labels.pt', comment: "take advantage of the raw data being output as JSON\n # to pass it to jq (a JSON parsers https://jqlang.github.io/jq/)\n # and get only the piece of data you're looking for" },
20
+ { args: '--simplify --keep ids Q123 | jq .claims.P138 -j', comment: 'get Q123 P138 claims ids' },
21
21
  ],
22
22
  }
package/metadata/query.js CHANGED
@@ -15,7 +15,7 @@ export default {
15
15
  { args: '--property P921 --object Q44559 --labels', comment: 'find out which works have exoplanets (Q44559) for main subject (P921)\n # and include labels' },
16
16
  { args: '--property P7476 --count', comment: 'get a list of all the claims using the property (P7476)' },
17
17
  { args: '-p P921 -o Q44559 -a', comment: 'as always, you can also use the short options syntax' },
18
- { args: '-p P921 -o Q44559 -a | jd 2', comment: 'the output is valid JSON, so you can pipe it to any JSON parser you like\n # (here jsondepth a.k.a. jd)' },
18
+ { args: "-p P921 -o Q44559 -a | jq '.[]' -cr", comment: 'the output is valid JSON, so you can pipe it to any JSON parser you like\n # (here jq https://jqlang.github.io/jq/)' },
19
19
  { args: '-s Q15228 -p P674 -a', comment: 'find out which are the characters (P674) in The Lord of The Ring (Q15228)' },
20
20
  { args: '-s Q15228 -o Q177499 -a', comment: 'find out which property link The Lord of The Ring (Q15228) and Gandalf (Q177499)' },
21
21
  { args: '-s Q177499 -a', comment: 'get the properties and objects for all the triples (subject, property, object) having Gandalf (Q177499) as subject' },
@@ -12,6 +12,7 @@ export default {
12
12
  },
13
13
  examples: [
14
14
  { args: 'Q3548931', comment: "fetch Q3548931's revisions data" },
15
+ { args: 'Q3548931 -p content,user,ids', comment: "fetch only certain attributes from Q3548931's revisions data" },
15
16
  { args: 'Property:P31', comment: "fetch P31's revisions data" },
16
17
  ],
17
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikibase-cli",
3
- "version": "18.0.4",
3
+ "version": "18.2.0",
4
4
  "description": "A command-line interface to Wikibase",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -16,7 +16,7 @@
16
16
  "lint-staged": "./scripts/lint_staged",
17
17
  "prepublishOnly": "export MOCHA_OPTIONS='--bail'; npm run lint && npm test",
18
18
  "postpublish": "npm run docker:publish && git push --tags",
19
- "test": "mocha --exit --timeout 20000 $MOCHA_OPTIONS",
19
+ "test": "export FORCE_COLOR=false; mocha --exit --timeout 20000 $MOCHA_OPTIONS",
20
20
  "update-toc": "./scripts/update_toc"
21
21
  },
22
22
  "repository": {
@@ -57,7 +57,7 @@
57
57
  "shell-quote": "^1.8.1",
58
58
  "split": "^1.0.1",
59
59
  "through": "^2.3.8",
60
- "wikibase-edit": "^7.0.4",
60
+ "wikibase-edit": "^7.1.2",
61
61
  "wikibase-sdk": "^10.1.0",
62
62
  "wikidata-lang": "^2.0.11"
63
63
  },