@verbatims/cli 1.0.4 → 1.0.5
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 +5 -0
- package/package.json +2 -2
- package/src/commands/authors.ts +50 -16
- package/src/commands/quotes.ts +5 -0
package/README.md
CHANGED
|
@@ -30,6 +30,11 @@ verbatims quotes attributions list 123
|
|
|
30
30
|
verbatims quotes attributions create 123 --author-id 1 --reference-id 2 --status manually_verified --primary
|
|
31
31
|
verbatims quotes sources list 123
|
|
32
32
|
verbatims quotes sources create 123 --attribution-id 7 --source-type book --source-url https://example.com/edition --status externally_verified
|
|
33
|
+
verbatims quotes sources update 123 7 --translator-name "Jane Doe"
|
|
34
|
+
|
|
35
|
+
# Structured author dates (era can be bce or ce)
|
|
36
|
+
verbatims authors create --name "Hypatia" --birth-year 350 --birth-era ce --birth-approximate
|
|
37
|
+
verbatims authors update 12 --death-year 415 --death-era ce --death-approximate
|
|
33
38
|
|
|
34
39
|
# Create a quote with a source
|
|
35
40
|
verbatims quotes create --name "Alea jacta est" --author-id 1 --source-type book --source-url https://example.com/edition
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verbatims/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "CLI for the Verbatims quotes API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"typecheck": "tsc --noEmit"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@verbatims/sdk": "^2.0.
|
|
22
|
+
"@verbatims/sdk": "^2.0.4",
|
|
23
23
|
"@clack/prompts": "^0.10.1",
|
|
24
24
|
"chalk": "^5.4.1",
|
|
25
25
|
"commander": "^13.1.0",
|
package/src/commands/authors.ts
CHANGED
|
@@ -11,6 +11,36 @@ function getFormat(program: Command): Format {
|
|
|
11
11
|
return (program.opts().format ?? 'table') as Format
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
function getLifeDateFields(options: Record<string, unknown>): Record<string, unknown> {
|
|
15
|
+
const fields: Record<string, unknown> = {}
|
|
16
|
+
const dateParts = ['date', 'year', 'era', 'month', 'day', 'approximate'] as const
|
|
17
|
+
|
|
18
|
+
for (const period of ['birth', 'death'] as const) {
|
|
19
|
+
for (const part of dateParts) {
|
|
20
|
+
const optionName = part === 'approximate' ? `${period}Approximate` : `${period}${part.slice(0, 1).toUpperCase()}${part.slice(1)}`
|
|
21
|
+
const fieldName = part === 'approximate' ? `${period}_is_approximate` : `${period}_${part}`
|
|
22
|
+
const value = options[optionName]
|
|
23
|
+
if (value !== undefined) fields[fieldName] = part === 'year' || part === 'month' || part === 'day' ? Number(value) : value
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return fields
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function addLifeDateOptions(command: Command): void {
|
|
31
|
+
for (const period of ['birth', 'death'] as const) {
|
|
32
|
+
const label = period === 'birth' ? 'Birth' : 'Death'
|
|
33
|
+
command
|
|
34
|
+
.option(`--${period}-date <date>`, `${label} date`)
|
|
35
|
+
.option(`--${period}-year <year>`, `${label} year (supports BCE with --${period}-era bce)`)
|
|
36
|
+
.option(`--${period}-era <era>`, `${label} era: bce or ce`)
|
|
37
|
+
.option(`--${period}-month <month>`, `${label} month`)
|
|
38
|
+
.option(`--${period}-day <day>`, `${label} day`)
|
|
39
|
+
.option(`--${period}-approximate`, `Mark ${label.toLowerCase()} date as approximate`)
|
|
40
|
+
.option(`--no-${period}-approximate`, `Mark ${label.toLowerCase()} date as exact`)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
14
44
|
export function registerAuthorsCommand(program: Command) {
|
|
15
45
|
const authors = program.command('authors').description('Manage authors')
|
|
16
46
|
|
|
@@ -42,8 +72,8 @@ export function registerAuthorsCommand(program: Command) {
|
|
|
42
72
|
output(data, format)
|
|
43
73
|
})
|
|
44
74
|
|
|
45
|
-
authors
|
|
46
|
-
|
|
75
|
+
const createAuthor = authors.command('create')
|
|
76
|
+
createAuthor
|
|
47
77
|
.description('Create an author')
|
|
48
78
|
.option('--name <name>', 'Author name')
|
|
49
79
|
.option('--job <job>', 'Job title')
|
|
@@ -51,15 +81,15 @@ export function registerAuthorsCommand(program: Command) {
|
|
|
51
81
|
.option('--image-url <url>', 'Image URL')
|
|
52
82
|
.option('--image-path <path>', 'Local image file path')
|
|
53
83
|
.option('--fictional', 'Mark as fictional')
|
|
54
|
-
.action(async (options: Record<string,
|
|
84
|
+
.action(async (options: Record<string, unknown>) => {
|
|
55
85
|
const client = await getClient()
|
|
56
86
|
const format = getFormat(program)
|
|
57
87
|
|
|
58
|
-
const name = options.name ?? await text({ message: 'Author name', validate: (v) => !v ? 'Required' : undefined })
|
|
88
|
+
const name = (options.name as string | undefined) ?? await text({ message: 'Author name', validate: (v) => !v ? 'Required' : undefined })
|
|
59
89
|
if (isCancel(name)) cancel('Cancelled')
|
|
60
90
|
|
|
61
|
-
let image_url: string | null = options.imageUrl
|
|
62
|
-
const imagePath = options.imagePath
|
|
91
|
+
let image_url: string | null = typeof options.imageUrl === 'string' ? options.imageUrl : null
|
|
92
|
+
const imagePath = typeof options.imagePath === 'string' ? options.imagePath : undefined
|
|
63
93
|
if (imagePath) {
|
|
64
94
|
image_url = await withSpinner('Uploading image', () => uploadImageFromPath(client, imagePath), format)
|
|
65
95
|
}
|
|
@@ -67,10 +97,11 @@ export function registerAuthorsCommand(program: Command) {
|
|
|
67
97
|
const { data } = await withSpinner('Creating author', () =>
|
|
68
98
|
client.authors.create({
|
|
69
99
|
name: name as string,
|
|
70
|
-
job: options.job ?? null,
|
|
71
|
-
description: options.description ?? null,
|
|
100
|
+
job: (options.job as string | undefined) ?? null,
|
|
101
|
+
description: (options.description as string | undefined) ?? null,
|
|
72
102
|
image_url,
|
|
73
|
-
fictional: options.fictional
|
|
103
|
+
fictional: options.fictional === true ? true : undefined,
|
|
104
|
+
...getLifeDateFields(options),
|
|
74
105
|
}),
|
|
75
106
|
format,
|
|
76
107
|
)
|
|
@@ -78,8 +109,8 @@ export function registerAuthorsCommand(program: Command) {
|
|
|
78
109
|
output(data, format)
|
|
79
110
|
})
|
|
80
111
|
|
|
81
|
-
authors
|
|
82
|
-
|
|
112
|
+
const updateAuthor = authors.command('update <id>')
|
|
113
|
+
updateAuthor
|
|
83
114
|
.description('Update an author')
|
|
84
115
|
.option('--name <name>', 'Author name')
|
|
85
116
|
.option('--job <job>', 'Job title')
|
|
@@ -88,27 +119,30 @@ export function registerAuthorsCommand(program: Command) {
|
|
|
88
119
|
.option('--image-path <path>', 'Local image file path')
|
|
89
120
|
.option('--fictional', 'Mark as fictional')
|
|
90
121
|
.option('--no-fictional', 'Mark as not fictional')
|
|
91
|
-
.action(async (id: string, options: Record<string,
|
|
122
|
+
.action(async (id: string, options: Record<string, unknown>) => {
|
|
92
123
|
const client = await getClient()
|
|
93
124
|
const format = getFormat(program)
|
|
94
125
|
|
|
95
126
|
const data_: Record<string, unknown> = {}
|
|
96
|
-
if (options.name) data_.name = options.name
|
|
127
|
+
if (typeof options.name === 'string') data_.name = options.name
|
|
97
128
|
if (options.job !== undefined) data_.job = options.job || null
|
|
98
129
|
if (options.description !== undefined) data_.description = options.description || null
|
|
99
130
|
if (options.imageUrl !== undefined) data_.image_url = options.imageUrl || null
|
|
100
|
-
const updateImagePath = options.imagePath
|
|
131
|
+
const updateImagePath = typeof options.imagePath === 'string' ? options.imagePath : undefined
|
|
101
132
|
if (updateImagePath !== undefined) {
|
|
102
133
|
data_.image_url = await withSpinner('Uploading image', () => uploadImageFromPath(client, updateImagePath), format)
|
|
103
134
|
}
|
|
104
|
-
if (options.fictional !== undefined) data_.is_fictional = true
|
|
105
|
-
|
|
135
|
+
if (options.fictional !== undefined) data_.is_fictional = options.fictional === true
|
|
136
|
+
Object.assign(data_, getLifeDateFields(options))
|
|
106
137
|
|
|
107
138
|
const { data } = await withSpinner('Updating author', () => client.authors.update(Number(id), data_ as any), format)
|
|
108
139
|
console.log(chalk.green(' Author updated'))
|
|
109
140
|
output(data, format)
|
|
110
141
|
})
|
|
111
142
|
|
|
143
|
+
addLifeDateOptions(createAuthor)
|
|
144
|
+
addLifeDateOptions(updateAuthor)
|
|
145
|
+
|
|
112
146
|
authors
|
|
113
147
|
.command('delete <id>')
|
|
114
148
|
.description('Delete an author')
|
package/src/commands/quotes.ts
CHANGED
|
@@ -70,6 +70,7 @@ export function registerQuotesCommand(program: Command) {
|
|
|
70
70
|
.option('--reference-id <id>', 'Primary attribution reference ID')
|
|
71
71
|
.option('--source-type <type>', 'Source type for the primary attribution')
|
|
72
72
|
.option('--source-url <url>', 'Source URL for the primary attribution')
|
|
73
|
+
.option('--translator-name <name>', 'Translator name for the primary source')
|
|
73
74
|
.action(async (options: Record<string, string>) => {
|
|
74
75
|
const client = await getClient()
|
|
75
76
|
const format = getFormat(program)
|
|
@@ -103,6 +104,7 @@ export function registerQuotesCommand(program: Command) {
|
|
|
103
104
|
attribution_id: primary.id,
|
|
104
105
|
source_type: sourceType,
|
|
105
106
|
source_url: options.sourceUrl,
|
|
107
|
+
translator_name: options.translatorName,
|
|
106
108
|
is_primary: true,
|
|
107
109
|
}), format)
|
|
108
110
|
}
|
|
@@ -292,6 +294,7 @@ export function registerQuotesCommand(program: Command) {
|
|
|
292
294
|
.option('--source-type <type>', 'Source type')
|
|
293
295
|
.option('--source-url <url>', 'Source URL')
|
|
294
296
|
.option('--label <label>', 'Source label')
|
|
297
|
+
.option('--translator-name <name>', 'Translator name')
|
|
295
298
|
.option('--status <status>', 'Verification status')
|
|
296
299
|
.option('--notes <text>', 'Internal notes')
|
|
297
300
|
.option('--primary', 'Set as primary source')
|
|
@@ -314,6 +317,7 @@ export function registerQuotesCommand(program: Command) {
|
|
|
314
317
|
source_type: options.sourceType,
|
|
315
318
|
source_url: options.sourceUrl,
|
|
316
319
|
label: options.label,
|
|
320
|
+
translator_name: options.translatorName,
|
|
317
321
|
verification_status: options.status,
|
|
318
322
|
notes: options.notes,
|
|
319
323
|
is_primary: options.primary,
|
|
@@ -329,6 +333,7 @@ export function registerQuotesCommand(program: Command) {
|
|
|
329
333
|
if (options.sourceType !== undefined) data_.source_type = options.sourceType
|
|
330
334
|
if (options.sourceUrl !== undefined) data_.source_url = options.sourceUrl
|
|
331
335
|
if (options.label !== undefined) data_.label = options.label
|
|
336
|
+
if (options.translatorName !== undefined) data_.translator_name = options.translatorName
|
|
332
337
|
if (options.status !== undefined) data_.verification_status = options.status
|
|
333
338
|
if (options.notes !== undefined) data_.notes = options.notes
|
|
334
339
|
if (options.primary !== undefined) data_.is_primary = options.primary
|