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 +11 -1
- package/bin/wb-generate-template.js +2 -2
- package/bin/wb-id.js +2 -2
- package/bin/wb-open.js +5 -1
- package/bin/wb-revisions.js +2 -2
- package/bin/wb-search.js +2 -2
- package/bin/wb.js +3 -0
- package/bin/wd.js +5 -1
- package/lib/chalk.js +1 -0
- package/lib/debug.js +19 -0
- package/lib/edit/assert_credentials.js +3 -0
- package/lib/edit/edit_command.js +2 -0
- package/lib/edit/parse_batch_line.js +1 -1
- package/lib/edit/prompt.js +1 -4
- package/lib/entity_attribute_command.js +2 -0
- package/lib/entity_attribute_parser.js +2 -1
- package/lib/entity_data_parser.js +2 -2
- package/lib/fetch_and_log_entity_revision.js +2 -2
- package/lib/fetch_and_log_guid_data.js +2 -2
- package/lib/fetch_and_log_property_claims_data.js +2 -2
- package/lib/fetch_lang_props.js +2 -2
- package/lib/fs.js +6 -21
- package/lib/get_cache_folder_path.js +10 -7
- package/lib/get_entities.js +2 -2
- package/lib/get_entities_by_batches.js +2 -2
- package/lib/get_folder_path.js +5 -5
- package/lib/get_lang_props.js +2 -2
- package/lib/get_sitelink_url.js +2 -2
- package/lib/log_command_examples.js +8 -3
- package/lib/make_sparql_query.js +2 -2
- package/lib/mediainfo.js +11 -0
- package/lib/program.js +16 -1
- package/lib/request.js +10 -3
- package/lib/reset_properties.js +1 -1
- package/lib/sparql_query_command.js +2 -2
- package/lib/summary_parser.js +6 -2
- package/lib/wbk.js +1 -1
- package/package.json +11 -11
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) **>=
|
|
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
|
|
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 } =
|
|
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
|
|
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 } =
|
|
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`)
|
package/bin/wb-revisions.js
CHANGED
|
@@ -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
|
|
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 } =
|
|
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
|
|
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 } =
|
|
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]
|
|
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) => {
|
package/lib/edit/edit_command.js
CHANGED
|
@@ -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
|
|
4
|
+
import parse from 'shell-quote/parse.js'
|
|
5
5
|
|
|
6
6
|
export default line => {
|
|
7
7
|
// One JSON object as single argument
|
package/lib/edit/prompt.js
CHANGED
|
@@ -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
|
|
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
|
|
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 } =
|
|
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
|
|
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 } =
|
|
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
|
|
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 } =
|
|
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
|
|
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 } =
|
|
12
|
+
const { getEntities } = getWbk(program)
|
|
13
13
|
const options = optionsFactory(program)
|
|
14
14
|
const { simplify: simplifyOption } = program
|
|
15
15
|
const output = outputFactory(program)
|
package/lib/fetch_lang_props.js
CHANGED
|
@@ -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
|
|
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 } =
|
|
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
|
|
2
|
-
import
|
|
1
|
+
import { accessSync, constants } from 'node:fs'
|
|
2
|
+
import { access } from 'node:fs/promises'
|
|
3
3
|
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
10
|
+
accessSync(path, constants.W_OK)
|
|
26
11
|
}
|
|
27
12
|
|
|
28
13
|
export function getDirname (fileUrl) {
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import {
|
|
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
|
|
5
|
+
export async function getCacheFolderPath (subfolder) {
|
|
5
6
|
const subfolderPath = getFolderPath('cache', subfolder)
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
try {
|
|
8
|
+
await access(subfolderPath)
|
|
9
|
+
return subfolderPath
|
|
10
|
+
} catch (err) {
|
|
8
11
|
if (err.code === 'ENOENT') {
|
|
9
|
-
|
|
12
|
+
await mkdirp(subfolderPath)
|
|
13
|
+
return subfolderPath
|
|
10
14
|
} else {
|
|
11
15
|
throw err
|
|
12
16
|
}
|
|
13
|
-
}
|
|
14
|
-
.then(() => subfolderPath)
|
|
17
|
+
}
|
|
15
18
|
}
|
package/lib/get_entities.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import
|
|
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 } =
|
|
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
|
|
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 } =
|
|
13
|
+
const { getManyEntities } = getWbk(program)
|
|
14
14
|
|
|
15
15
|
if (ids != null) {
|
|
16
16
|
ids.forEach(id => {
|
package/lib/get_folder_path.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { homedir } from 'node:os'
|
|
2
2
|
import path from 'node:path'
|
|
3
|
-
import mkdirp from 'mkdirp'
|
|
4
|
-
import {
|
|
3
|
+
import { mkdirp } from 'mkdirp'
|
|
4
|
+
import { assertWriteAccessSync } from './fs.js'
|
|
5
5
|
|
|
6
|
-
const homePath =
|
|
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
|
-
|
|
20
|
+
assertWriteAccessSync(folderPath)
|
|
21
21
|
|
|
22
22
|
return folderPath
|
|
23
23
|
}
|
package/lib/get_lang_props.js
CHANGED
|
@@ -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
|
package/lib/get_sitelink_url.js
CHANGED
|
@@ -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
|
|
4
|
+
import { getWbk } from '#lib/wbk'
|
|
5
5
|
|
|
6
6
|
export function getSitelinkUrlFactory (program) {
|
|
7
7
|
exitOnMissingInstance(program.instance)
|
|
8
|
-
const { getEntities } =
|
|
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
|
-
|
|
12
|
-
console.log(` ${cmd}`)
|
|
12
|
+
console.log(` wb ${command} ${args}`)
|
|
13
13
|
if (dryRun && example.dryRun !== false) {
|
|
14
|
-
const generatedData = execSync(`${
|
|
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 => {
|
package/lib/make_sparql_query.js
CHANGED
|
@@ -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
|
|
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 } =
|
|
14
|
+
const { sparqlQuery } = getWbk(program)
|
|
15
15
|
|
|
16
16
|
if (localFormatsDerivedFromJSON.includes(format)) format = 'json'
|
|
17
17
|
|
package/lib/mediainfo.js
ADDED
|
@@ -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,
|
|
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
|
|
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
|
|
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
|
|
47
|
+
const res = await request(url, { method, body, headers: buildHeaders(headers), agent })
|
|
41
48
|
return handleResponse({ res, url, method })
|
|
42
49
|
}
|
|
43
50
|
|
package/lib/reset_properties.js
CHANGED
|
@@ -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
|
|
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 } =
|
|
21
|
+
const { sparqlQuery } = getWbk(program)
|
|
22
22
|
const queryServiceGUI = sparqlQuery(sparql).replace('sparql?format=json&query=', '#')
|
|
23
23
|
openUrl(queryServiceGUI)
|
|
24
24
|
}
|
package/lib/summary_parser.js
CHANGED
|
@@ -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
|
|
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.
|
|
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
|
|
15
|
-
"lint-fix": "eslint
|
|
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": "^
|
|
50
|
+
"chalk": "^5.3.0",
|
|
51
51
|
"commander": "^6.0.0",
|
|
52
|
-
"copy-paste": "^1.3
|
|
52
|
+
"copy-paste": "^1.5.3",
|
|
53
53
|
"lodash-es": "^4.17.21",
|
|
54
|
-
"mkdirp": "^0.
|
|
54
|
+
"mkdirp": "^3.0.1",
|
|
55
55
|
"node-fetch": "^2.6.0",
|
|
56
|
-
"open": "^
|
|
57
|
-
"read": "^1.0
|
|
58
|
-
"shell-quote": "^1.
|
|
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.
|
|
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.
|
|
78
|
+
"node": ">= 14.17.0"
|
|
79
79
|
}
|
|
80
80
|
}
|