add person-as-list

This commit is contained in:
Martin Minka 2022-06-18 14:55:04 +02:00
commit 4bf61e4ecb
9 changed files with 608 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.idea/
node_modules/

1
.tool-versions Normal file
View File

@ -0,0 +1 @@
nodejs 18.4.0

14
README.md Normal file
View File

@ -0,0 +1,14 @@
Git clone and install packages with `yarn`.
Populate database:
```
# show command line parameters
node bin/populate-vikunja.js
# only 100 lists - that works fine
node bin/populate-vikunja.js person-as-list -s /tmp/GoLand/___go_build_code_vikunja_io_api --delete-db
# generate 10.000 lists - this is problem to handle by UI
node bin/populate-vikunja.js person-as-list -s /tmp/GoLand/___go_build_code_vikunja_io_api --delete-db -c 10000
```

74
bin/populate-vikunja.js Normal file
View File

@ -0,0 +1,74 @@
import yargs from 'yargs'
import { hideBin } from 'yargs/helpers'
import { startVikunja, initClient } from '../src/vikunja.js'
import personAsList from '../src/person-as-list.js'
import { keypress } from '../src/utils.js'
function addGlobal (yargs) {
yargs
.option('startVikunja', {
alias: 's',
description: 'Vikinja binary to be started before data are populated or Vikunja has to be started manually'
})
.option('workDir', {
description: 'directory where Sqlite database will be created if startVikunja was provided, default is folder with Vikunja binary'
})
.option('deleteDb', {
'description': 'WARNING! Database will be delete before Vikunja will be started'
})
.option('jwtsecret', {
default: 'C519352B2E9FFBADD92AE5BC63D26A42FC334418373150F8137618EC1F7459D3'
})
.option('user', {
alias: 'u',
default: 'demo'
})
.option('password', {
alias: 'P',
default: 'demo'
})
.option('baseUrl', {
default: 'http://localhost:3456'
})
return yargs
}
async function startVikunjaFromArgv (argv) {
if (argv.startVikunja) {
return startVikunja(argv.startVikunja, argv.jwtsecret, argv.workDir, argv.deleteDb).then(() => true)
}
return false
}
function initClientFromArgv (wasStarted, argv) {
return initClient(argv.baseUrl, argv.user, argv.password, wasStarted)
}
yargs(hideBin(process.argv))
.command(
'$0 person-as-list',
'will populate Vikunja tasks with persons as lists',
yargs => {
addGlobal(yargs)
.option('count', {
alias: 'c',
default: 100
})
},
async argv => {
const wasStarted = await startVikunjaFromArgv(argv)
await personAsList(await initClientFromArgv(wasStarted, argv), argv.count)
if (wasStarted) {
console.log('population done, press any key to quit')
await keypress()
process.exit()
}
}
)
.demandCommand(1)
.help()
.parse()

16
package.json Normal file
View File

@ -0,0 +1,16 @@
{
"name": "populate-db",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"type": "module",
"dependencies": {
"@faker-js/faker": "^7.2.0",
"axios": "^0.27.2",
"fs-extra": "^10.1.0",
"moment": "^2.29.3",
"swedish-ssn-generator": "^1.0.1",
"weighted-random-distribution": "^1.2.2",
"yargs": "^17.5.1"
}
}

183
src/person-as-list.js Normal file
View File

@ -0,0 +1,183 @@
import { faker } from '@faker-js/faker/locale/sk'
import SwedishSSN from 'swedish-ssn-generator'
import { inPlaceUnsorted } from 'weighted-random-distribution'
import moment from 'moment'
import { between } from './utils.js'
async function populate (client, personCount) {
function createRandomPerson () {
const gender = between(0, 1) ? 'male' : 'female'
const p = {
// userId: faker.datatype.uuid(),
// username: faker.internet.userName(),
// email: faker.internet.email(),
// avatar: faker.image.avatar(),
// password: faker.internet.password(),
birthdate: faker.date.birthdate(),
name: faker.name.findName(undefined, undefined, gender)
// registeredAt: faker.date.past()
}
p.rc = SwedishSSN.generateSSNWithParameters(p.birthdate, gender).replace('-', '')
return p
}
async function insertLabel (title) {
try {
const d = (await client.put(
`/labels`,
{
title
}
)).data
return d.id
} catch (ex) {
console.log(ex)
process.exit()
return false
}
}
function createTask (date, past = false) {
const t = {
start_date: date,
title: faker.hacker.phrase() // faker.lorem.sentence()
}
if (inPlaceUnsorted({
0: 95,
1: 5
}) * 1) {
// priority
t.priority = 4
}
if (inPlaceUnsorted({
0: 95,
1: 5
}) * 1) {
// reminder
t.reminder_dates = [moment(date).add(-3, 'day')]
}
// label
const label = inPlaceUnsorted(MY_LABELS)
if (label) {
console.log(label)
t.labels = [{ id: label * 1 }]
if (label * 1 === 1) { // recept
if (1 * inPlaceUnsorted({
0: 30,
1: 70
})) {
// repeat
t.title = 'REPEAT: ' + t.title
t.repeat_after = 60 * 60 * 24 * 30 * 3
t.repeat_mode = 0
}
}
}
if ((past && 1 * inPlaceUnsorted({
0: 30,
1: 70
})) || 1 * inPlaceUnsorted({
0: 95,
1: 5
})) {
// done
t.done = true
}
if (1 * inPlaceUnsorted({
0: 5,
1: 95
})) {
// due
t.due_date = date
}
return t
}
async function insertTask (listId, task) {
try {
let labels
if (task.labels) {
// BUG this is workarround because create task with labels will not insert the labels
labels = task.labels
delete task.labels
}
const d = (await client.put(
`/lists/${listId}`,
task
)).data
if (labels) {
await client.post(
`/tasks/${d.id}/labels/bulk`,
{ labels }
)
}
return d.id
} catch (ex) {
console.log(ex)
process.exit()
return false
}
}
async function insertPerson (person) {
// const d = (await client.get(`/namespaces/${namespace}/lists`)).data
// console.log(d)
try {
const d = (await client.put(
`/namespaces/${namespace}/lists`,
{
title: person.name,
identifier: person.rc
}
)).data
return d.id
} catch (ex) {
console.log(ex)
return false
}
}
const namespace = 1
// prepare labels
const MY_LABELS = { '': 20 }
MY_LABELS[await insertLabel('recept')] = 45
MY_LABELS[await insertLabel('kontrola')] = 20
MY_LABELS[await insertLabel('krv')] = 10
MY_LABELS[await insertLabel('FOB')] = 5
for (let i = 0; i < personCount; i++) {
const person = createRandomPerson()
const pId = await insertPerson(person)
if (pId === false) continue
// lists, sqlite_sequence, tasks
// past dates
for (let c = 0; c < between(0, 20); c++) {
await insertTask(pId, createTask(faker.date.past(), true))
}
// future dates
for (let c = 0; c < between(0, 5); c++) {
const soon = 1 * inPlaceUnsorted({
0: 70,
1: 30
})
await insertTask(pId, createTask(soon ? faker.date.soon(5) : faker.date.future()))
}
}
}
export default populate

13
src/utils.js Normal file
View File

@ -0,0 +1,13 @@
export async function keypress () {
process.stdin.setRawMode(true)
return new Promise(resolve => process.stdin.once('data', () => {
process.stdin.setRawMode(false)
resolve()
}))
}
export function between (min, max) {
return Math.floor(
Math.random() * (max - min + 1) + min
)
}

78
src/vikunja.js Normal file
View File

@ -0,0 +1,78 @@
import axios from 'axios'
import path from 'path'
import fs from 'fs-extra'
import { spawn } from 'child_process'
export function startVikunja (bin, jwtSecret, workDir = false, deleteDb = false) {
if (!workDir) {
workDir = path.dirname(bin)
}
if (deleteDb) {
// clear the database
try {
fs.unlinkSync(path.join(workDir, 'vikunja.db'))
} catch (_) {
// ignore error
}
}
return new Promise(resolve => {
const vikunja = spawn(
bin,
[],
{
cwd: workDir,
env: {
VIKUNJA_SERVICE_JWTSECRET: jwtSecret
}
}
)
vikunja.stdout.on('data', (data) => {
data = data.toString()
console.log(data)
if (data.indexOf(' cmd/func25') !== -1) {
console.log('Vikunja started, will proceed with data population...')
setTimeout(() => resolve(), 1000)
}
})
})
}
export async function initClient (baseURL, username, password, registerUser) {
if (registerUser) {
await axios.post(
baseURL + '/api/v1/register',
{
username,
password,
email: 'demo@example.com'
},
{
headers: {
'Content-Type': 'application/json'
}
}
)
}
// login
const bearer = (await axios.post(
baseURL + '/api/v1/login',
{
username,
password
},
{
headers: {
'Content-Type': 'application/json'
}
}
)).data.token
// prepare client
return axios.create({
baseURL: baseURL + '/api/v1/',
headers: { 'Authorization': 'Bearer ' + bearer }
})
}

227
yarn.lock Normal file
View File

@ -0,0 +1,227 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@faker-js/faker@^7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-7.2.0.tgz#c5fe4c34f3a3664ac64fe1a21bac2004ea5faa22"
integrity sha512-dzjQ0LFT+bPLWg0yyV3MpxaLJp/+VW4a0SnjNSWJ4YpJ928LXDOZAN+kB2/JPPisI3Ra0w2BxbD4M9J7o0jcpw==
ansi-regex@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
ansi-styles@^4.0.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
dependencies:
color-convert "^2.0.1"
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
axios@^0.27.2:
version "0.27.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
dependencies:
follow-redirects "^1.14.9"
form-data "^4.0.0"
cliui@^7.0.2:
version "7.0.4"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
dependencies:
string-width "^4.2.0"
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
dependencies:
color-name "~1.1.4"
color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
combined-stream@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
dependencies:
delayed-stream "~1.0.0"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
follow-redirects@^1.14.9:
version "1.15.1"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==
form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
fs-extra@^10.1.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^2.0.0"
get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.10"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
jsonfile@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
dependencies:
universalify "^2.0.0"
optionalDependencies:
graceful-fs "^4.1.6"
jsonschema@^1.2.6:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.1.tgz#cc4c3f0077fb4542982973d8a083b6b34f482dab"
integrity sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==
lodash.findkey@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.findkey/-/lodash.findkey-4.6.0.tgz#83058e903b51cbb759d09ccf546dea3ea39c4718"
integrity sha512-Y+f2R8KsUDJVqdfeai01P5A1IQeMWsMG1p0rghzdhIl7TIap47Y2Z5UJK8x4pstixNL56KVHFRE1IW9jvRwy4g==
lodash.reduce@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b"
integrity sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw==
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12:
version "2.1.35"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
dependencies:
mime-db "1.52.0"
moment@^2.29.3:
version "2.29.3"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.3.tgz#edd47411c322413999f7a5940d526de183c031f3"
integrity sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw==
require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
swedish-ssn-generator@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/swedish-ssn-generator/-/swedish-ssn-generator-1.0.1.tgz#3cb4aa13752f0a7e45fbd357620dffc1df2e6f18"
integrity sha512-1erBS/U3l0o+59OP/j1TgUTuZTZaERanbBvunWWAw6HwhOyR7TBSeycQg9TQyDTbzcDwd87Az7UyXI8SxtGo9Q==
universalify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
weighted-random-distribution@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/weighted-random-distribution/-/weighted-random-distribution-1.2.2.tgz#b0348672a900362cfc1875069f745e31120d80d3"
integrity sha512-HQnugvf7e26AAWcVPbUEci8eEgRJk9oMbuhHP7IRWftFTF5uX16jXbFtu6Vkmt7rBHTjePgZKturt3jtbgG09w==
dependencies:
jsonschema "^1.2.6"
lodash.findkey "^4.6.0"
lodash.reduce "^4.6.0"
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
y18n@^5.0.5:
version "5.0.8"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
yargs-parser@^21.0.0:
version "21.0.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35"
integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==
yargs@^17.5.1:
version "17.5.1"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e"
integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==
dependencies:
cliui "^7.0.2"
escalade "^3.1.1"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
string-width "^4.2.3"
y18n "^5.0.5"
yargs-parser "^21.0.0"