wikibase-cli 17.0.0 → 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)
@@ -54,7 +55,7 @@ See [CHANGELOG.md](CHANGELOG.md) for version info
54
55
  ## Dependencies
55
56
 
56
57
  ### General
57
- * [NodeJs](https://nodejs.org) **>= v10** (recommended way to install it: use the awesome [NVM](https://github.com/creationix/nvm) to install the latest LTS version `nvm install --lts`)
58
+ * [NodeJs](https://nodejs.org) **>= v14** (recommended way to install it: use the awesome [NVM](https://github.com/creationix/nvm) to install the latest LTS version `nvm install --lts`)
58
59
  * [Git](https://git-scm.com/)
59
60
 
60
61
  ### Per feature
@@ -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/bin/wd.js CHANGED
@@ -3,6 +3,10 @@ process.env.WB_INSTANCE = 'https://www.wikidata.org'
3
3
  process.env.WB_SPARQL_ENDPOINT = 'https://query.wikidata.org/sparql'
4
4
  // Fake the executed script to be wb to trick commander to believe it
5
5
  // as it would otherwise fail to build subcommand paths
6
- process.argv[1] = process.argv[1].replace(/wd\.js$/, 'wb.js')
6
+ process.argv[1] = process.argv[1]
7
+ // Case when called directly as ./bin/wd.js
8
+ .replace(/wd\.js$/, 'wb.js')
9
+ // Case when called directly as a link such as defined in package.json, ./node_modules/.bin/wd
10
+ .replace(/wd$/, 'wb')
7
11
 
8
12
  await import('./wb.js')
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,7 +1,7 @@
1
1
  // Args can't be just a line splitted on spaces
2
2
  // as there are JSON strings arguments, and signle or double quoted strings args
3
3
 
4
- import { parse } from 'shell-quote'
4
+ import parse from 'shell-quote/parse.js'
5
5
 
6
6
  export default line => {
7
7
  // One JSON object as single argument
@@ -1,9 +1,6 @@
1
- import { promisify } from 'node:util'
2
1
  import read from 'read'
3
2
  import { blue, yellow, grey } from '#lib/chalk'
4
3
 
5
- const readAsync = promisify(read)
6
-
7
4
  export default readsData => {
8
5
  const results = {}
9
6
 
@@ -30,7 +27,7 @@ const prompt = (label, pattern, options, info) => {
30
27
  })
31
28
  message += '\n-'
32
29
  }
33
- let res = await readAsync({ prompt: message })
30
+ let res = await read({ prompt: message })
34
31
  res = res.trim()
35
32
  if (!pattern || pattern.test(res)) {
36
33
  return res
@@ -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
@@ -22,6 +22,7 @@ export default (entity, attribute, lang, strictLang) => {
22
22
 
23
23
  const attributesPerType = {
24
24
  item: [ 'labels', 'descriptions', 'aliases' ],
25
- property: [ 'labels', 'descriptions', 'aliases' ],
26
25
  lexeme: [ 'lemmas' ],
26
+ mediainfo: [ 'labels', 'descriptions' ],
27
+ property: [ 'labels', 'descriptions', 'aliases' ],
27
28
  }
@@ -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
 
package/lib/fs.js CHANGED
@@ -1,28 +1,13 @@
1
- import fs from 'node:fs'
2
- import mkdirp from 'mkdirp'
1
+ import { accessSync, constants } from 'node:fs'
2
+ import { access } from 'node:fs/promises'
3
3
 
4
- export const writeFile = (filepath, content) => {
5
- return new Promise((resolve, reject) => {
6
- fs.writeFile(filepath, content, (err, res) => {
7
- err ? reject(err) : resolve(res)
8
- })
9
- })
10
- }
11
- export const exists = path => {
12
- return new Promise((resolve, reject) => {
13
- fs.access(path, (err, res) => err ? reject(err) : resolve(res))
14
- })
15
- }
16
- export const createFolder = path => {
17
- return new Promise((resolve, reject) => {
18
- mkdirp(path, err => err ? reject(err) : resolve())
19
- })
20
- }
21
- export const writeAccessSync = path => {
4
+ export const exists = path => access(path)
5
+
6
+ export const assertWriteAccessSync = path => {
22
7
  // Testing right to write
23
8
  // cf https://nodejs.org/api/fs.html#fs_fs_access_path_mode_callback
24
9
  // Will throw if failing
25
- fs.accessSync(path, fs.constants.W_OK)
10
+ accessSync(path, constants.W_OK)
26
11
  }
27
12
 
28
13
  export function getDirname (fileUrl) {
@@ -1,15 +1,18 @@
1
- import { exists, createFolder } from './fs.js'
1
+ import { access } from 'node:fs/promises'
2
+ import { mkdirp } from 'mkdirp'
2
3
  import getFolderPath from './get_folder_path.js'
3
4
 
4
- export default subfolder => {
5
+ export async function getCacheFolderPath (subfolder) {
5
6
  const subfolderPath = getFolderPath('cache', subfolder)
6
- return exists(subfolderPath)
7
- .catch(err => {
7
+ try {
8
+ await access(subfolderPath)
9
+ return subfolderPath
10
+ } catch (err) {
8
11
  if (err.code === 'ENOENT') {
9
- return createFolder(subfolderPath)
12
+ await mkdirp(subfolderPath)
13
+ return subfolderPath
10
14
  } else {
11
15
  throw err
12
16
  }
13
- })
14
- .then(() => subfolderPath)
17
+ }
15
18
  }
@@ -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,9 +1,9 @@
1
- import os from 'node:os'
1
+ import { homedir } from 'node:os'
2
2
  import path from 'node:path'
3
- import mkdirp from 'mkdirp'
4
- import { writeAccessSync } from './fs.js'
3
+ import { mkdirp } from 'mkdirp'
4
+ import { assertWriteAccessSync } from './fs.js'
5
5
 
6
- const homePath = os.homedir()
6
+ const homePath = homedir()
7
7
 
8
8
  export default (category, subfolderName) => {
9
9
  let folderPath
@@ -17,7 +17,7 @@ export default (category, subfolderName) => {
17
17
  }
18
18
  mkdirp.sync(folderPath)
19
19
  // Make sure we have write access right in case the folder already existed
20
- writeAccessSync(folderPath)
20
+ assertWriteAccessSync(folderPath)
21
21
 
22
22
  return folderPath
23
23
  }
@@ -1,9 +1,9 @@
1
+ import { writeFile } from 'node:fs/promises'
1
2
  import { URL } from 'node:url'
2
- import getCacheFolderPath from '#lib/get_cache_folder_path'
3
+ import { getCacheFolderPath } from '#lib/get_cache_folder_path'
3
4
  import { hashString } from '#lib/hash_string'
4
5
  import { readJsonFile } from '#lib/json'
5
6
  import fetchLangProps from './fetch_lang_props.js'
6
- import { writeFile } from './fs.js'
7
7
 
8
8
  export default async program => {
9
9
  const { lang, sparqlEndpoint, noCache } = program
@@ -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")
@@ -1,4 +1,5 @@
1
1
  import { execSync } from 'node:child_process'
2
+ import { dirname } from 'node:path'
2
3
  import { grey } from '#lib/chalk'
3
4
 
4
5
  export default (command, examples, doc, dryRun = false) => {
@@ -8,10 +9,9 @@ export default (command, examples, doc, dryRun = false) => {
8
9
  let { args, comment } = example
9
10
  if (args instanceof Array) args = args.join(' ')
10
11
  if (comment) console.log(grey(`\n # ${comment}`))
11
- const cmd = `wb ${command} ${args}`
12
- console.log(` ${cmd}`)
12
+ console.log(` wb ${command} ${args}`)
13
13
  if (dryRun && example.dryRun !== false) {
14
- const generatedData = execSync(`${cmd} --dry`).toString()
14
+ const generatedData = execSync(`${getWbAbsolutePath()} ${command} ${args} --dry`).toString()
15
15
  console.log(grey(' # output:'))
16
16
  if (command.startsWith('sparql')) console.log(formatSparql(generatedData))
17
17
  else console.log(formatJsonInMixedOutput(generatedData))
@@ -23,6 +23,11 @@ export default (command, examples, doc, dryRun = false) => {
23
23
  console.log('')
24
24
  }
25
25
 
26
+ function getWbAbsolutePath () {
27
+ const binDirectory = dirname(process.argv[1])
28
+ return `${binDirectory}/wb.js`
29
+ }
30
+
26
31
  const indent = line => ' ' + line
27
32
 
28
33
  const formatJsonInMixedOutput = output => {
@@ -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,6 +1,6 @@
1
1
  import { exec } from 'node:child_process'
2
2
  import { green } from '#lib/chalk'
3
- import getCacheFolderPath from '#lib/get_cache_folder_path'
3
+ import { getCacheFolderPath } from '#lib/get_cache_folder_path'
4
4
 
5
5
  export default () => {
6
6
  return getCacheFolderPath('props')
@@ -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.0",
3
+ "version": "17.0.2",
4
4
  "description": "A command-line interface to Wikibase",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -11,8 +11,8 @@
11
11
  "scripts": {
12
12
  "docker:publish": "./scripts/docker_publish",
13
13
  "git-pre-commit": "./scripts/githooks/pre-commit",
14
- "lint": "eslint -c .eslintrc.cjs bin/wb* lib/* lib/*/* test/* test/lib/*",
15
- "lint-fix": "eslint -c .eslintrc.cjs --fix bin/wb* lib/* lib/*/* test/* test/lib/*",
14
+ "lint": "eslint --config .eslintrc.cjs bin/* lib test",
15
+ "lint-fix": "eslint --config .eslintrc.cjs --fix bin/* lib test",
16
16
  "lint-staged": "./scripts/lint_staged",
17
17
  "prepublishOnly": "npm run lint && npm test",
18
18
  "postpublish": "npm run docker:publish && git push --tags",
@@ -47,18 +47,18 @@
47
47
  },
48
48
  "homepage": "https://github.com/maxlath/wikibase-cli#readme",
49
49
  "dependencies": {
50
- "chalk": "^2.4.2",
50
+ "chalk": "^5.3.0",
51
51
  "commander": "^6.0.0",
52
- "copy-paste": "^1.3.0",
52
+ "copy-paste": "^1.5.3",
53
53
  "lodash-es": "^4.17.21",
54
- "mkdirp": "^0.5.1",
54
+ "mkdirp": "^3.0.1",
55
55
  "node-fetch": "^2.6.0",
56
- "open": "^7.0.4",
57
- "read": "^1.0.7",
58
- "shell-quote": "^1.7.3",
56
+ "open": "^9.1.0",
57
+ "read": "^2.1.0",
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
  },
@@ -75,6 +75,6 @@
75
75
  "should": "^13.2.3"
76
76
  },
77
77
  "engines": {
78
- "node": ">= 14.0.0"
78
+ "node": ">= 14.17.0"
79
79
  }
80
80
  }