wikibase-cli 17.0.1 → 17.0.2

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
@@ -44,6 +44,7 @@ This project received [a Wikimedia Project Grant](https://meta.wikimedia.org/wik
44
44
  - [Read operations](docs/read_operations.md)
45
45
  - [Write operations](docs/write_operations.md)
46
46
  - [Config](docs/config.md)
47
+ - [Debug](#debug)
47
48
  - [See Also](#see-also)
48
49
  - [You may also like](#you-may-also-like)
49
50
  - [License](#license)
@@ -108,6 +109,15 @@ Allows to persist options
108
109
 
109
110
  See [Config](docs/config.md)
110
111
 
112
+ ## Debug
113
+ To get debugging informations, set the `DEBUG` environment variable:
114
+ ```sh
115
+ # Print all debugging information
116
+ export DEBUG=wikibase-cli ; wb
117
+ # Print only request debugging information
118
+ export DEBUG=wikibase-cli:request ; wd label Q1
119
+ ```
120
+
111
121
  ## See Also
112
122
  * [wikibase-sdk](https://www.npmjs.com/package/wikibase-sdk): A javascript tool suite to query and work with Wikibase data, heavily used by wikibase-cli
113
123
  * [wikibase-edit](https://www.npmjs.com/package/wikibase-edit): Edit Wikibase from NodeJS, used in wikibase-cli for all [write operations](docs/write_operations.md)
@@ -7,7 +7,7 @@ import parseProps from '#lib/parse_props'
7
7
  import program from '#lib/program'
8
8
  import { readIdsFromStdin } from '#lib/read_ids_from_stdin'
9
9
  import { tolerantIdParserFactory } from '#lib/tolerant_id_parser'
10
- import wbk from '#lib/wbk'
10
+ import { getWbk } from '#lib/wbk'
11
11
 
12
12
  await program
13
13
  .option('-p, --props <props>', 'request only certain properties (info, sitelinks, aliases, labels, descriptions, claims, datatype)')
@@ -22,7 +22,7 @@ const parseId = tolerantIdParserFactory()
22
22
  const ids = program.args.map(parseId)
23
23
  exitOnMissingInstance(program.instance)
24
24
 
25
- const { getEntityRevision, getManyEntities } = wbk(program)
25
+ const { getEntityRevision, getManyEntities } = getWbk(program)
26
26
 
27
27
  const { revision, minimize } = program
28
28
  let { format, json } = program
package/bin/wb-id.js CHANGED
@@ -6,13 +6,13 @@ import getRedirectedSitelinkTitle from '#lib/get_redirected_sitelink_title'
6
6
  import { outputFactory } from '#lib/output'
7
7
  import program from '#lib/program'
8
8
  import { get } from '#lib/request'
9
- import wbk from '#lib/wbk'
9
+ import { getWbk } from '#lib/wbk'
10
10
 
11
11
  await program.process('id')
12
12
 
13
13
  exitOnMissingInstance(program.instance)
14
14
 
15
- const { getEntitiesFromSitelinks } = wbk(program)
15
+ const { getEntitiesFromSitelinks } = getWbk(program)
16
16
 
17
17
  let { lang } = program
18
18
  const output = outputFactory(program)
package/bin/wb-open.js CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { isPropertyId } from 'wikibase-sdk'
2
+ import { isMediaInfoId, isPropertyId } from 'wikibase-sdk'
3
3
  import errors_ from '#lib/errors'
4
4
  import { exitOnMissingInstance } from '#lib/exit_on_missing'
5
5
  import { getSitelinkUrlFactory } from '#lib/get_sitelink_url'
6
+ import { getMediaInfoEntityTitle } from '#lib/mediainfo'
6
7
  import { openUrl } from '#lib/open'
7
8
  import program from '#lib/program'
8
9
  import { tolerantIdParserFactory } from '#lib/tolerant_id_parser'
@@ -52,6 +53,9 @@ if (!ids || ids.length === 0) {
52
53
  } else if (program.history) {
53
54
  if (isPropertyId(id)) {
54
55
  openUrl(`${instance}/w/index.php?title=Property:${id}&action=history`)
56
+ } else if (isMediaInfoId(id)) {
57
+ const title = await getMediaInfoEntityTitle(id)
58
+ openUrl(`${instance}/w/index.php?title=${title}&action=history`)
55
59
  } else {
56
60
  // Will be redirected to title=${id} if Item is the main namespace
57
61
  openUrl(`${instance}/w/index.php?title=Item:${id}&action=history`)
@@ -7,7 +7,7 @@ import logNdjson from '#lib/log_ndjson'
7
7
  import program from '#lib/program'
8
8
  import { get } from '#lib/request'
9
9
  import { isPositiveIntegerString } from '#lib/types'
10
- import wbk from '#lib/wbk'
10
+ import { getWbk } from '#lib/wbk'
11
11
 
12
12
  await program
13
13
  .option('-s, --start <date>', 'start date')
@@ -17,7 +17,7 @@ await program
17
17
 
18
18
  exitOnMissingInstance(program.instance)
19
19
 
20
- const { getRevisions } = wbk(program)
20
+ const { getRevisions } = getWbk(program)
21
21
 
22
22
  // Not parsing the ids with ../lib/tolerant_id_parser as that would
23
23
  // remove prefixes which are required for entities out of the main namespace
package/bin/wb-search.js CHANGED
@@ -7,7 +7,7 @@ import parseEntityType from '#lib/parse_entity_type'
7
7
  import program from '#lib/program'
8
8
  import { get } from '#lib/request'
9
9
  import { isValidLang } from '#lib/validate'
10
- import wbk from '#lib/wbk'
10
+ import { getWbk } from '#lib/wbk'
11
11
 
12
12
  await program
13
13
  .option('-p, --properties <properties>', 'request additional properties (separated by a comma) (implies verbose mode)')
@@ -33,7 +33,7 @@ if (!isValidLang(language)) {
33
33
  }
34
34
  exitOnMissingInstance(program.instance)
35
35
 
36
- const { searchEntities, cirrusSearchPages } = wbk(program)
36
+ const { searchEntities, cirrusSearchPages } = getWbk(program)
37
37
 
38
38
  type = parseEntityType(type)
39
39
 
package/bin/wb.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import fs from 'node:fs'
3
3
  import path, { resolve } from 'node:path'
4
4
  import program from 'commander'
5
+ import { debug } from '#lib/debug'
5
6
  import { getDirname } from '#lib/fs'
6
7
  import { readJsonFile } from '#lib/json'
7
8
 
@@ -11,6 +12,8 @@ const pkg = readJsonFile(resolve(dirname, '../package.json'))
11
12
  program.version(pkg.version)
12
13
  program.description(pkg.description)
13
14
 
15
+ debug('program:metadata', { name: pkg.name, version: pkg.version })
16
+
14
17
  // To add a new command, create a file in ../metadata/${new-command-name}
15
18
  // and add an executable at ./wb-${new-command-name}
16
19
 
package/lib/chalk.js CHANGED
@@ -4,6 +4,7 @@ export const bgBlue = chalk.bgBlue
4
4
  export const bgGreen = chalk.bgGreen
5
5
  export const bgMagenta = chalk.bgMagenta
6
6
  export const blue = chalk.blue
7
+ export const cyan = chalk.cyan
7
8
  export const green = chalk.green
8
9
  export const grey = chalk.grey
9
10
  export const inverse = chalk.inverse
package/lib/debug.js ADDED
@@ -0,0 +1,19 @@
1
+ import { cyan, grey } from '#lib/chalk'
2
+
3
+ const { DEBUG = '' } = process.env
4
+ const namespace = 'wikibase-cli'
5
+ const debugMode = DEBUG === '*' || (DEBUG.length > 0 && namespace.startsWith(DEBUG)) || DEBUG.startsWith(`${namespace}:`)
6
+ const debugSection = DEBUG.split(':').slice(1).join(':').replace(/\*$/, '')
7
+
8
+ export function debug (section, ...args) {
9
+ if (!debugMode) return
10
+ if (debugSection && !section.startsWith(debugSection)) return
11
+ console.error(`${grey(new Date().toISOString())} ${cyan(`${namespace}:${section}`)}`, ...args.map(stringify))
12
+ }
13
+
14
+ function stringify (data) {
15
+ if (typeof data === 'string') return data
16
+ const str = JSON.stringify(data)
17
+ if (str === '{}' || str === '[]') return ''
18
+ else return str
19
+ }
@@ -1,4 +1,5 @@
1
1
  import { yellow } from '#lib/chalk'
2
+ import { debug } from '#lib/debug'
2
3
  import { initCredentials } from './init_credentials.js'
3
4
 
4
5
  export default async ({ instance, credentials, batch }) => {
@@ -11,6 +12,8 @@ export default async ({ instance, credentials, batch }) => {
11
12
  if (!(oauth || (username && password))) {
12
13
  return requestCredentials(instance, batch)
13
14
  }
15
+
16
+ debug('credentials', Object.keys(instanceCredentials))
14
17
  }
15
18
 
16
19
  const requestCredentials = (instance, batch) => {
@@ -2,6 +2,7 @@ import { inspect } from 'node:util'
2
2
  import split from 'split'
3
3
  import wbEdit from 'wikibase-edit'
4
4
  import { red } from '#lib/chalk'
5
+ import { debug } from '#lib/debug'
5
6
  import { config } from '../config/config.js'
6
7
  import errors_ from '../errors.js'
7
8
  import program from '../program.js'
@@ -10,6 +11,7 @@ import parseBatchLine from './parse_batch_line.js'
10
11
  import parseObjectValue from './parse_object_value.js'
11
12
 
12
13
  export async function execEditCommand (section, action) {
14
+ debug('edit_command', { section, action })
13
15
  let name
14
16
  if (typeof section === 'object') {
15
17
  // Pass a name when it can not be deduced from the wikibase-edit section
@@ -1,10 +1,12 @@
1
1
  import { max, padEnd, values } from 'lodash-es'
2
2
  import { grey, red } from '#lib/chalk'
3
+ import { debug } from '#lib/debug'
3
4
  import entityAttributeParser from './entity_attribute_parser.js'
4
5
  import { entityDataParser } from './entity_data_parser.js'
5
6
  import pluralize from './pluralize.js'
6
7
 
7
8
  export async function entityAttributeCommand (attribute, extraParams) {
9
+ debug('entity_attribute_command', { attribute, extraParams })
8
10
  let commandName, ids
9
11
  if (extraParams) {
10
12
  ids = extraParams.ids
@@ -4,7 +4,7 @@ import { outputFactory } from '#lib/output'
4
4
  import program from '#lib/program'
5
5
  import { get } from '#lib/request'
6
6
  import { tolerantIdParserFactory } from '#lib/tolerant_id_parser'
7
- import wbk from '#lib/wbk'
7
+ import { getWbk } from '#lib/wbk'
8
8
 
9
9
  const parseId = tolerantIdParserFactory()
10
10
 
@@ -21,7 +21,7 @@ export async function entityDataParser (params) {
21
21
 
22
22
  exitOnMissingInstance(program.instance)
23
23
 
24
- const { getEntities } = wbk(program)
24
+ const { getEntities } = getWbk(program)
25
25
  const output = outputFactory(program)
26
26
 
27
27
  const { args, lang, strictLang } = program
@@ -3,13 +3,13 @@ import { simplifyEntity } from 'wikibase-sdk'
3
3
  import { exitOnMissingInstance } from '#lib/exit_on_missing'
4
4
  import optionsFactory from '#lib/parse_simplify_options'
5
5
  import { get } from '#lib/request'
6
- import wbk from '#lib/wbk'
6
+ import { getWbk } from '#lib/wbk'
7
7
  import program from './program.js'
8
8
 
9
9
  exitOnMissingInstance(program.instance)
10
10
 
11
11
  export async function fetchAndLogEntityRevision (id, revision) {
12
- const { getEntityRevision } = wbk(program)
12
+ const { getEntityRevision } = getWbk(program)
13
13
  const { simplify: simplifyOption } = program
14
14
  const options = optionsFactory(program)
15
15
  const url = getEntityRevision({ id, revision })
@@ -4,13 +4,13 @@ import { simplifyClaim } from 'wikibase-sdk'
4
4
  import { exitOnMissingInstance } from '#lib/exit_on_missing'
5
5
  import optionsFactory from '#lib/parse_simplify_options'
6
6
  import { get } from '#lib/request'
7
- import wbk from '#lib/wbk'
7
+ import { getWbk } from '#lib/wbk'
8
8
  import { outputFactory } from './output.js'
9
9
  import program from './program.js'
10
10
 
11
11
  export async function fetchAndLogGuidData (guid) {
12
12
  exitOnMissingInstance(program.instance)
13
- const { getEntities } = wbk(program)
13
+ const { getEntities } = getWbk(program)
14
14
  const options = optionsFactory(program)
15
15
  const { simplify: simplifyOption } = program
16
16
  const output = outputFactory(program)
@@ -3,13 +3,13 @@ import { simplifyPropertyClaims } from 'wikibase-sdk'
3
3
  import { exitOnMissingInstance } from '#lib/exit_on_missing'
4
4
  import optionsFactory from '#lib/parse_simplify_options'
5
5
  import { get } from '#lib/request'
6
- import wbk from '#lib/wbk'
6
+ import { getWbk } from '#lib/wbk'
7
7
  import { outputFactory } from './output.js'
8
8
  import program from './program.js'
9
9
 
10
10
  export async function fetchAndLogPropertyClaimsData (propertyClaimsId) {
11
11
  exitOnMissingInstance(program.instance)
12
- const { getEntities } = wbk(program)
12
+ const { getEntities } = getWbk(program)
13
13
  const options = optionsFactory(program)
14
14
  const { simplify: simplifyOption } = program
15
15
  const output = outputFactory(program)
@@ -2,14 +2,14 @@ import { simplifySparqlResults } from 'wikibase-sdk'
2
2
  import { red, yellow } from '#lib/chalk'
3
3
  import { get } from '#lib/request'
4
4
  import { isValidLang } from '#lib/validate'
5
- import wbk from '#lib/wbk'
5
+ import { getWbk } from '#lib/wbk'
6
6
  import { exitOnMissingSparqlEndpoint } from './exit_on_missing.js'
7
7
  import queryAllProperties from './queries/all_properties.js'
8
8
 
9
9
  export default async program => {
10
10
  const { lang, sparqlEndpoint } = program
11
11
  exitOnMissingSparqlEndpoint(program.sparqlEndpoint)
12
- const { sparqlQuery } = wbk(program)
12
+ const { sparqlQuery } = getWbk(program)
13
13
 
14
14
  if (!isValidLang(lang)) throw Error(red(`invalid language: ${lang}`))
15
15
 
@@ -1,11 +1,11 @@
1
- import wbk from '#lib/wbk'
1
+ import { getWbk } from '#lib/wbk'
2
2
  import program from './program.js'
3
3
  import { get } from './request.js'
4
4
 
5
5
  export default async params => {
6
6
  // JIT require to be sure program.process was already called
7
7
  // and program.instance is set
8
- const { getManyEntities } = wbk(program)
8
+ const { getManyEntities } = getWbk(program)
9
9
 
10
10
  const urls = getManyEntities(params)
11
11
  const allEntities = {}
@@ -4,13 +4,13 @@ import errors_ from './errors.js'
4
4
  import program from './program.js'
5
5
  import { get } from './request.js'
6
6
  import { wait } from './utils.js'
7
- import wbk from './wbk.js'
7
+ import { getWbk } from './wbk.js'
8
8
 
9
9
  const noop = () => {}
10
10
 
11
11
  export async function getEntitiesByBatches ({ ids, props, languages, urls, onResponse, onDone = noop }) {
12
12
  exitOnMissingInstance(program.instance)
13
- const { getManyEntities } = wbk(program)
13
+ const { getManyEntities } = getWbk(program)
14
14
 
15
15
  if (ids != null) {
16
16
  ids.forEach(id => {
@@ -1,11 +1,11 @@
1
1
  import errors_ from '#lib/errors'
2
2
  import { exitOnMissingInstance } from '#lib/exit_on_missing'
3
3
  import { get } from '#lib/request'
4
- import wbk from '#lib/wbk'
4
+ import { getWbk } from '#lib/wbk'
5
5
 
6
6
  export function getSitelinkUrlFactory (program) {
7
7
  exitOnMissingInstance(program.instance)
8
- const { getEntities } = wbk(program)
8
+ const { getEntities } = getWbk(program)
9
9
  return async function (id, lang, sitelinkSuffix) {
10
10
  if (id[0] === 'P') {
11
11
  console.error("Wikibase properties don't have sitelinks")
@@ -5,13 +5,13 @@ import { exitOnMissingSparqlEndpoint } from '#lib/exit_on_missing'
5
5
  import { outputFactory } from '#lib/output'
6
6
  import program from '#lib/program'
7
7
  import { customGet, post } from '#lib/request'
8
- import wbk from '#lib/wbk'
8
+ import { getWbk } from '#lib/wbk'
9
9
 
10
10
  export default (sparql, format = 'json') => {
11
11
  // JIT require to be sure program.process was already called
12
12
  // and program.sparqlEndpoint is set
13
13
  exitOnMissingSparqlEndpoint(program.sparqlEndpoint)
14
- const { sparqlQuery } = wbk(program)
14
+ const { sparqlQuery } = getWbk(program)
15
15
 
16
16
  if (localFormatsDerivedFromJSON.includes(format)) format = 'json'
17
17
 
@@ -0,0 +1,11 @@
1
+ import program from '#lib/program'
2
+ import { get } from '#lib/request'
3
+ import { getWbk } from '#lib/wbk'
4
+
5
+ export async function getMediaInfoEntityTitle (id) {
6
+ const { getEntities } = getWbk(program)
7
+ const url = getEntities({ ids: [ id ], props: [ 'info' ] })
8
+ const body = await get(url)
9
+ const { title } = Object.values(body.entities)[0]
10
+ return title
11
+ }
package/lib/program.js CHANGED
@@ -1,14 +1,17 @@
1
1
  // Extends commander with options and functions used by all subcommands.
2
2
 
3
3
  import program from 'commander'
4
+ import { debug } from '#lib/debug'
4
5
  import { applyEnvAndConfigDefault } from './apply_env_and_config_default.js'
5
6
  import globalOptionsHelp from './global_options_help.js'
6
7
  import logCommandExamples from './log_command_examples.js'
7
8
 
8
9
  program.process = async command => {
10
+ let options
9
11
  if (command) {
10
12
  const { default: metadata } = await import(`../metadata/${command}.js`)
11
- const { args, description, options, examples, doc } = metadata
13
+ const { args, description, examples, doc } = metadata
14
+ ;({ options } = metadata)
12
15
  program.arguments(args)
13
16
  program.description(description)
14
17
  Object.keys(globalOptionsHelp).forEach(key => {
@@ -31,6 +34,18 @@ program.process = async command => {
31
34
  }
32
35
  }
33
36
  applyEnvAndConfigDefault(program)
37
+ if (command) {
38
+ debug('program:process', { argv, command, args: program.args, options: getOptionsKeyValues(options), showHelp })
39
+ } else {
40
+ debug('program:process', { argv, showHelp })
41
+ }
42
+ }
43
+
44
+ function getOptionsKeyValues (options) {
45
+ const optionsEntries = Object.entries(options)
46
+ .filter(([ , used ]) => used)
47
+ .map(([ option ]) => [ option, program[option] ])
48
+ return Object.fromEntries(optionsEntries)
34
49
  }
35
50
 
36
51
  const commandsAcceptingZeroArguments = [
package/lib/request.js CHANGED
@@ -5,6 +5,7 @@ import http from 'node:http'
5
5
  import https from 'node:https'
6
6
  import { pick } from 'lodash-es'
7
7
  import fetch from 'node-fetch'
8
+ import { debug } from '#lib/debug'
8
9
  import program from './program.js'
9
10
  import globalHeaders from './request_headers.js'
10
11
 
@@ -25,19 +26,25 @@ const buildHeaders = customHeaders => {
25
26
  else return globalHeaders
26
27
  }
27
28
 
29
+ function request (url, options) {
30
+ const { method = 'get', headers, body } = options
31
+ debug('request', method.toUpperCase(), url, { headers, body })
32
+ return fetch(url, options)
33
+ }
34
+
28
35
  export const get = async url => {
29
- const res = await fetch(url, { headers: globalHeaders, agent })
36
+ const res = await request(url, { headers: globalHeaders, agent })
30
37
  return handleResponse({ res, url })
31
38
  }
32
39
 
33
40
  export const customGet = async ({ url, headers }) => {
34
- const res = await fetch(url, { headers: buildHeaders(headers), agent })
41
+ const res = await request(url, { headers: buildHeaders(headers), agent })
35
42
  return handleResponse({ res, url })
36
43
  }
37
44
 
38
45
  export const post = async ({ url, body, headers }) => {
39
46
  const method = 'post'
40
- const res = await fetch(url, { method, body, headers: buildHeaders(headers), agent })
47
+ const res = await request(url, { method, body, headers: buildHeaders(headers), agent })
41
48
  return handleResponse({ res, url, method })
42
49
  }
43
50
 
@@ -1,5 +1,5 @@
1
1
  import { openUrl } from '#lib/open'
2
- import wbk from '#lib/wbk'
2
+ import { getWbk } from '#lib/wbk'
3
3
  import makeSparqlQuery from './make_sparql_query.js'
4
4
  import { outputFactory } from './output.js'
5
5
  import program from './program.js'
@@ -18,7 +18,7 @@ export function sparqlQueryCommand (sparql, format) {
18
18
  }
19
19
 
20
20
  function openQueryServiceGUI (sparql) {
21
- const { sparqlQuery } = wbk(program)
21
+ const { sparqlQuery } = getWbk(program)
22
22
  const queryServiceGUI = sparqlQuery(sparql).replace('sparql?format=json&query=', '#')
23
23
  openUrl(queryServiceGUI)
24
24
  }
@@ -37,13 +37,17 @@ const parseEntity = async (entity, params) => {
37
37
  }
38
38
 
39
39
  const { lang, program } = params
40
- const { type, datatype } = entity
40
+ const { type, datatype, title } = entity
41
+
42
+ if (type === 'mediainfo') {
43
+ console.log(grey('title'), title)
44
+ }
41
45
 
42
46
  if (datatype) {
43
47
  console.log(bgMagenta(white('Datatype')), datatype)
44
48
  }
45
49
 
46
- if (type === 'item' || type === 'property') {
50
+ if (type === 'item' || type === 'property' || type === 'mediainfo') {
47
51
  const label = entityAttributeParser(entity, 'label', lang)
48
52
  console.log(bgGreen(white('Label')), label)
49
53
  const description = entityAttributeParser(entity, 'description', lang)
package/lib/wbk.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // A wrapper of wikidata SDK to customize the Wikibase instance if requested in config
2
2
  import WBK from 'wikibase-sdk'
3
3
 
4
- export default program => {
4
+ export function getWbk (program) {
5
5
  const { instance, sparqlEndpoint } = program
6
6
  program.wbk = program.wbk || WBK({ instance, sparqlEndpoint })
7
7
  return program.wbk
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikibase-cli",
3
- "version": "17.0.1",
3
+ "version": "17.0.2",
4
4
  "description": "A command-line interface to Wikibase",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -58,7 +58,7 @@
58
58
  "shell-quote": "^1.8.1",
59
59
  "split": "^1.0.1",
60
60
  "through": "^2.3.8",
61
- "wikibase-edit": "^6.0.1",
61
+ "wikibase-edit": "^6.0.2",
62
62
  "wikibase-sdk": "^9.2.0",
63
63
  "wikidata-lang": "^2.0.11"
64
64
  },