add commands for managing plugin
This commit is contained in:
parent
afd7ea993b
commit
988b0ace8c
|
|
@ -21,9 +21,11 @@
|
|||
"@hot-loader/react-dom": "^16.11.0",
|
||||
"@tweenjs/tween.js": "^18.4.2",
|
||||
"admin-lte": "^3.0.1",
|
||||
"blessing-skin-shell": "^0.2.0",
|
||||
"blessing-skin-shell": "^0.3.1",
|
||||
"cli-spinners": "^2.2.0",
|
||||
"commander": "^5.0.0",
|
||||
"echarts": "^4.6.0",
|
||||
"enquirer": "^2.3.4",
|
||||
"immer": "^6.0.2",
|
||||
"jquery": "^3.4.1",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,11 @@ import { FitAddon } from 'xterm-addon-fit'
|
|||
import { Shell } from 'blessing-skin-shell'
|
||||
import 'xterm/css/xterm.css'
|
||||
import Draggable from 'react-draggable'
|
||||
import * as event from './event'
|
||||
import AptCommand from './cli/AptCommand'
|
||||
import ClosetCommand from './cli/ClosetCommand'
|
||||
import DnfCommand from './cli/DnfCommand'
|
||||
import PacmanCommand from './cli/PacmanCommand'
|
||||
import RmCommand from './cli/RmCommand'
|
||||
import styles from '@/styles/terminal.module.scss'
|
||||
|
||||
|
|
@ -31,14 +35,21 @@ const TerminalWindow: React.FC<{ onClose(): void }> = (props) => {
|
|||
fitAddon.fit()
|
||||
|
||||
const shell = new Shell(terminal)
|
||||
shell.addExternal(AptCommand.name, AptCommand)
|
||||
shell.addExternal('closet', ClosetCommand)
|
||||
shell.addExternal(DnfCommand.name, DnfCommand)
|
||||
shell.addExternal(PacmanCommand.name, PacmanCommand)
|
||||
shell.addExternal('rm', RmCommand)
|
||||
|
||||
const unbind = terminal.onData((e) => shell.input(e))
|
||||
const unbindData = terminal.onData((e) => shell.input(e))
|
||||
const unbindKey = terminal.onKey((e) =>
|
||||
event.emit('terminalKeyPress', e.key),
|
||||
)
|
||||
launched = true
|
||||
|
||||
return () => {
|
||||
unbind.dispose()
|
||||
unbindData.dispose()
|
||||
unbindKey.dispose()
|
||||
shell.free()
|
||||
fitAddon.dispose()
|
||||
terminal.dispose()
|
||||
|
|
|
|||
33
resources/assets/src/scripts/cli/AptCommand.ts
Normal file
33
resources/assets/src/scripts/cli/AptCommand.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import type { Stdio } from 'blessing-skin-shell'
|
||||
import { Command } from 'commander'
|
||||
import { hackStdout, overrideExit } from './configureStdio'
|
||||
import { install, remove } from './pluginManager'
|
||||
|
||||
export default async function apt(stdio: Stdio, args: string[]) {
|
||||
const program = new Command()
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
process.stdout = hackStdout(stdio)
|
||||
overrideExit(program, stdio)
|
||||
}
|
||||
|
||||
program.name(apt.name)
|
||||
|
||||
program
|
||||
.command('install <plugin>')
|
||||
.description('install a new plugin')
|
||||
.action((plugin: string) => install(plugin, stdio))
|
||||
|
||||
program
|
||||
.command('upgrade <plugin>')
|
||||
.description('upgrade an existed plugin')
|
||||
.action((plugin: string) => install(plugin, stdio))
|
||||
|
||||
program
|
||||
.command('remove <plugin>')
|
||||
.description('remove a plugin')
|
||||
.action((plugin: string) => remove(plugin, stdio))
|
||||
|
||||
await program.parseAsync(args, { from: 'user' })
|
||||
}
|
||||
33
resources/assets/src/scripts/cli/DnfCommand.ts
Normal file
33
resources/assets/src/scripts/cli/DnfCommand.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import type { Stdio } from 'blessing-skin-shell'
|
||||
import { Command } from 'commander'
|
||||
import { hackStdout, overrideExit } from './configureStdio'
|
||||
import { install, remove } from './pluginManager'
|
||||
|
||||
export default async function dnf(stdio: Stdio, args: string[]) {
|
||||
const program = new Command()
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
process.stdout = hackStdout(stdio)
|
||||
overrideExit(program, stdio)
|
||||
}
|
||||
|
||||
program.name(dnf.name)
|
||||
|
||||
program
|
||||
.command('install <plugin>')
|
||||
.description('install a new plugin')
|
||||
.action((plugin: string) => install(plugin, stdio))
|
||||
|
||||
program
|
||||
.command('upgrade <plugin>')
|
||||
.description('upgrade an existed plugin')
|
||||
.action((plugin: string) => install(plugin, stdio))
|
||||
|
||||
program
|
||||
.command('remove <plugin>')
|
||||
.description('remove a plugin')
|
||||
.action((plugin: string) => remove(plugin, stdio))
|
||||
|
||||
await program.parseAsync(args, { from: 'user' })
|
||||
}
|
||||
41
resources/assets/src/scripts/cli/PacmanCommand.ts
Normal file
41
resources/assets/src/scripts/cli/PacmanCommand.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import type { Stdio } from 'blessing-skin-shell'
|
||||
import { Command } from 'commander'
|
||||
import { hackStdout, overrideExit } from './configureStdio'
|
||||
import { install, remove } from './pluginManager'
|
||||
|
||||
type Options = {
|
||||
sync?: string
|
||||
remove?: string
|
||||
}
|
||||
|
||||
export default async function pacman(stdio: Stdio, args: string[]) {
|
||||
if (args.length === 0) {
|
||||
stdio.println('error: no operation specified (use -h for help)')
|
||||
return
|
||||
}
|
||||
|
||||
const program = new Command()
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
process.stdout = hackStdout(stdio)
|
||||
overrideExit(program, stdio)
|
||||
}
|
||||
|
||||
program.name(pacman.name)
|
||||
|
||||
program
|
||||
.option('-S, --sync <plugin>')
|
||||
.description('install or upgrade a plugin')
|
||||
program.option('-R, --remove <plugin>').description('remove a plugin')
|
||||
|
||||
program.parse(args, { from: 'user' })
|
||||
|
||||
const opts: Options = program.opts()
|
||||
/* istanbul ignore else */
|
||||
if (opts.sync) {
|
||||
await install(opts.sync, stdio)
|
||||
} else if (opts.remove) {
|
||||
await remove(opts.remove, stdio)
|
||||
}
|
||||
}
|
||||
26
resources/assets/src/scripts/cli/Spinner.ts
Normal file
26
resources/assets/src/scripts/cli/Spinner.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import type { Stdio } from 'blessing-skin-shell'
|
||||
import { dots } from 'cli-spinners'
|
||||
|
||||
export class Spinner {
|
||||
private timerId: number = 0
|
||||
private index: number = 0
|
||||
|
||||
constructor(private stdio: Stdio) {}
|
||||
|
||||
start(message = '') {
|
||||
this.timerId = window.setInterval(() => {
|
||||
this.index += 1
|
||||
this.index %= dots.frames.length
|
||||
|
||||
this.stdio.reset()
|
||||
this.stdio.print(`${dots.frames[this.index]} ${message}`)
|
||||
}, dots.interval)
|
||||
}
|
||||
|
||||
stop(message = '') {
|
||||
clearInterval(this.timerId)
|
||||
this.stdio.reset()
|
||||
this.stdio.println(message)
|
||||
this.stdio.print('\u001B[?25h')
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,36 @@
|
|||
import { Stdio } from 'blessing-skin-shell'
|
||||
import type Commander from 'commander'
|
||||
import * as event from '../event'
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function hackStdin() {
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
return process.stdin
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
return {
|
||||
on(eventName: string, handler: (key: string) => void) {
|
||||
if (eventName === 'keypress') {
|
||||
this._off = event.on('terminalKeyPress', (key: string) => {
|
||||
handler(key)
|
||||
})
|
||||
}
|
||||
},
|
||||
isTTY: true,
|
||||
setRawMode() {},
|
||||
removeListener() {
|
||||
this._off()
|
||||
},
|
||||
} as NodeJS.ReadStream & { _off(): void }
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function hackStdout(stdio: Stdio) {
|
||||
return {
|
||||
write(msg: string) {
|
||||
stdio.print(msg.replace(/\n/g, '\r\n'))
|
||||
return true
|
||||
},
|
||||
} as NodeJS.WriteStream
|
||||
}
|
||||
|
|
@ -14,7 +39,7 @@ export function hackStdout(stdio: Stdio) {
|
|||
export function overrideExit(program: Commander.Command, stdio: Stdio) {
|
||||
Error.captureStackTrace = () => {}
|
||||
|
||||
return program.exitOverride(error => {
|
||||
return program.exitOverride((error) => {
|
||||
if (!error.message.startsWith('(')) {
|
||||
stdio.print(error.message.replace(/\n/g, '\r\n'))
|
||||
}
|
||||
|
|
|
|||
43
resources/assets/src/scripts/cli/pluginManager.ts
Normal file
43
resources/assets/src/scripts/cli/pluginManager.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import type { Stdio } from 'blessing-skin-shell'
|
||||
import { prompt } from 'enquirer'
|
||||
import * as fetch from '../net'
|
||||
import { hackStdout, hackStdin } from './configureStdio'
|
||||
import { Spinner } from './Spinner'
|
||||
|
||||
export async function install(plugin: string, stdio: Stdio) {
|
||||
const spinner = new Spinner(stdio)
|
||||
spinner.start('Installing plugin...')
|
||||
|
||||
const { message, data } = await fetch.post<
|
||||
fetch.ResponseBody<{ reason?: string[] } | undefined>
|
||||
>('/admin/plugins/market/download', { name: plugin })
|
||||
|
||||
spinner.stop(` ${message}`)
|
||||
const reasons = data?.reason
|
||||
if (reasons) {
|
||||
stdio.println(reasons.map((reason) => `- ${reason}`).join('\r\n'))
|
||||
}
|
||||
}
|
||||
|
||||
export async function remove(plugin: string, stdio: Stdio) {
|
||||
const { confirm }: { confirm: boolean } = await prompt({
|
||||
name: 'confirm',
|
||||
type: 'confirm',
|
||||
message: `Are you sure to remove plugin "${plugin}"?`,
|
||||
stdin: hackStdin(),
|
||||
stdout: hackStdout(stdio),
|
||||
})
|
||||
|
||||
if (!confirm) {
|
||||
return
|
||||
}
|
||||
|
||||
const spinner = new Spinner(stdio)
|
||||
spinner.start('Uninstalling plugin...')
|
||||
|
||||
const { message } = await fetch.post<fetch.ResponseBody>(
|
||||
'/admin/plugins/manage',
|
||||
{ action: 'delete', name: plugin },
|
||||
)
|
||||
spinner.stop(` ${message}`)
|
||||
}
|
||||
9
resources/assets/src/scripts/cli/readline.ts
Normal file
9
resources/assets/src/scripts/cli/readline.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export function emitKeypressEvents() {}
|
||||
|
||||
export function createInterface() {
|
||||
return {
|
||||
pause() {},
|
||||
resume() {},
|
||||
close() {},
|
||||
}
|
||||
}
|
||||
68
resources/assets/tests/scripts/cli/AptCommand.test.ts
Normal file
68
resources/assets/tests/scripts/cli/AptCommand.test.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import * as fetch from '@/scripts/net'
|
||||
import apt from '@/scripts/cli/AptCommand'
|
||||
import { Stdio } from './stdio'
|
||||
|
||||
jest.mock('@/scripts/net')
|
||||
|
||||
describe('install plugin', () => {
|
||||
it('succeeded', async () => {
|
||||
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
const stdio = new Stdio()
|
||||
|
||||
await apt(stdio, ['install', 'test'])
|
||||
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
|
||||
name: 'test',
|
||||
})
|
||||
expect(stdio.getStdout()).toInclude('ok')
|
||||
})
|
||||
|
||||
it('failed with reasons', async () => {
|
||||
fetch.post.mockResolvedValue({
|
||||
code: 1,
|
||||
message: 'failed',
|
||||
data: { reason: ['unresolved'] },
|
||||
})
|
||||
const stdio = new Stdio()
|
||||
|
||||
await apt(stdio, ['install', 'test'])
|
||||
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
|
||||
name: 'test',
|
||||
})
|
||||
expect(stdio.getStdout()).toInclude('failed')
|
||||
expect(stdio.getStdout()).toInclude('- unresolved')
|
||||
})
|
||||
|
||||
it('use `upgrade` command', async () => {
|
||||
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
const stdio = new Stdio()
|
||||
|
||||
await apt(stdio, ['upgrade', 'test'])
|
||||
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
|
||||
name: 'test',
|
||||
})
|
||||
expect(stdio.getStdout()).toInclude('ok')
|
||||
})
|
||||
})
|
||||
|
||||
describe('remove plugin', () => {
|
||||
it('cancelled', async () => {
|
||||
const stdio = new Stdio()
|
||||
|
||||
process.nextTick(() => process.stdin.emit('keypress', 'n'))
|
||||
await apt(stdio, ['remove', 'test'])
|
||||
expect(fetch.post).not.toBeCalled()
|
||||
})
|
||||
|
||||
it('succeeded', async () => {
|
||||
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
const stdio = new Stdio()
|
||||
|
||||
process.nextTick(() => process.stdin.emit('keypress', 'y'))
|
||||
await apt(stdio, ['remove', 'test'])
|
||||
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
|
||||
action: 'delete',
|
||||
name: 'test',
|
||||
})
|
||||
expect(stdio.getStdout()).toInclude('ok')
|
||||
})
|
||||
})
|
||||
68
resources/assets/tests/scripts/cli/DnfCommand.test.ts
Normal file
68
resources/assets/tests/scripts/cli/DnfCommand.test.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import * as fetch from '@/scripts/net'
|
||||
import dnf from '@/scripts/cli/DnfCommand'
|
||||
import { Stdio } from './stdio'
|
||||
|
||||
jest.mock('@/scripts/net')
|
||||
|
||||
describe('install plugin', () => {
|
||||
it('succeeded', async () => {
|
||||
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
const stdio = new Stdio()
|
||||
|
||||
await dnf(stdio, ['install', 'test'])
|
||||
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
|
||||
name: 'test',
|
||||
})
|
||||
expect(stdio.getStdout()).toInclude('ok')
|
||||
})
|
||||
|
||||
it('failed with reasons', async () => {
|
||||
fetch.post.mockResolvedValue({
|
||||
code: 1,
|
||||
message: 'failed',
|
||||
data: { reason: ['unresolved'] },
|
||||
})
|
||||
const stdio = new Stdio()
|
||||
|
||||
await dnf(stdio, ['install', 'test'])
|
||||
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
|
||||
name: 'test',
|
||||
})
|
||||
expect(stdio.getStdout()).toInclude('failed')
|
||||
expect(stdio.getStdout()).toInclude('- unresolved')
|
||||
})
|
||||
|
||||
it('use `upgrade` command', async () => {
|
||||
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
const stdio = new Stdio()
|
||||
|
||||
await dnf(stdio, ['upgrade', 'test'])
|
||||
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
|
||||
name: 'test',
|
||||
})
|
||||
expect(stdio.getStdout()).toInclude('ok')
|
||||
})
|
||||
})
|
||||
|
||||
describe('remove plugin', () => {
|
||||
it('cancelled', async () => {
|
||||
const stdio = new Stdio()
|
||||
|
||||
process.nextTick(() => process.stdin.emit('keypress', 'n'))
|
||||
await dnf(stdio, ['remove', 'test'])
|
||||
expect(fetch.post).not.toBeCalled()
|
||||
})
|
||||
|
||||
it('succeeded', async () => {
|
||||
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
const stdio = new Stdio()
|
||||
|
||||
process.nextTick(() => process.stdin.emit('keypress', 'y'))
|
||||
await dnf(stdio, ['remove', 'test'])
|
||||
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
|
||||
action: 'delete',
|
||||
name: 'test',
|
||||
})
|
||||
expect(stdio.getStdout()).toInclude('ok')
|
||||
})
|
||||
})
|
||||
64
resources/assets/tests/scripts/cli/PacmanCommand.test.ts
Normal file
64
resources/assets/tests/scripts/cli/PacmanCommand.test.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import * as fetch from '@/scripts/net'
|
||||
import pacman from '@/scripts/cli/PacmanCommand'
|
||||
import { Stdio } from './stdio'
|
||||
|
||||
jest.mock('@/scripts/net')
|
||||
|
||||
test('no arguments', async () => {
|
||||
const stdio = new Stdio()
|
||||
await pacman(stdio, [])
|
||||
expect(stdio.getStdout()).toInclude('help')
|
||||
expect(fetch.post).not.toBeCalled()
|
||||
})
|
||||
|
||||
describe('install plugin', () => {
|
||||
it('succeeded', async () => {
|
||||
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
const stdio = new Stdio()
|
||||
|
||||
await pacman(stdio, ['-S', 'test'])
|
||||
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
|
||||
name: 'test',
|
||||
})
|
||||
expect(stdio.getStdout()).toInclude('ok')
|
||||
})
|
||||
|
||||
it('failed with reasons', async () => {
|
||||
fetch.post.mockResolvedValue({
|
||||
code: 1,
|
||||
message: 'failed',
|
||||
data: { reason: ['unresolved'] },
|
||||
})
|
||||
const stdio = new Stdio()
|
||||
|
||||
await pacman(stdio, ['-S', 'test'])
|
||||
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
|
||||
name: 'test',
|
||||
})
|
||||
expect(stdio.getStdout()).toInclude('failed')
|
||||
expect(stdio.getStdout()).toInclude('- unresolved')
|
||||
})
|
||||
})
|
||||
|
||||
describe('remove plugin', () => {
|
||||
it('cancelled', async () => {
|
||||
const stdio = new Stdio()
|
||||
|
||||
process.nextTick(() => process.stdin.emit('keypress', 'n'))
|
||||
await pacman(stdio, ['-R', 'test'])
|
||||
expect(fetch.post).not.toBeCalled()
|
||||
})
|
||||
|
||||
it('succeeded', async () => {
|
||||
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
const stdio = new Stdio()
|
||||
|
||||
process.nextTick(() => process.stdin.emit('keypress', 'y'))
|
||||
await pacman(stdio, ['-R', 'test'])
|
||||
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
|
||||
action: 'delete',
|
||||
name: 'test',
|
||||
})
|
||||
expect(stdio.getStdout()).toInclude('ok')
|
||||
})
|
||||
})
|
||||
14
resources/assets/tests/scripts/cli/Spinner.test.ts
Normal file
14
resources/assets/tests/scripts/cli/Spinner.test.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { Spinner } from '@/scripts/cli/Spinner'
|
||||
import { Stdio } from './stdio'
|
||||
|
||||
test('run', () => {
|
||||
const stdio = new Stdio()
|
||||
const spinner = new Spinner(stdio)
|
||||
|
||||
spinner.start()
|
||||
|
||||
jest.runTimersToTime(500)
|
||||
expect(stdio.getStdout().length).toBeGreaterThan(0)
|
||||
|
||||
spinner.stop()
|
||||
})
|
||||
|
|
@ -134,6 +134,7 @@ const config = {
|
|||
alias: {
|
||||
'react-dom': '@hot-loader/react-dom',
|
||||
'@': path.resolve(__dirname, 'resources/assets/src'),
|
||||
'readline': '@/scripts/cli/readline.ts',
|
||||
},
|
||||
},
|
||||
externals: devMode
|
||||
|
|
|
|||
22
yarn.lock
22
yarn.lock
|
|
@ -2072,7 +2072,7 @@ amdefine@>=0.0.4:
|
|||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
|
||||
|
||||
ansi-colors@^3.0.0:
|
||||
ansi-colors@^3.0.0, ansi-colors@^3.2.1:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
|
||||
integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==
|
||||
|
|
@ -2443,10 +2443,10 @@ binary-extensions@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
|
||||
integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
|
||||
|
||||
blessing-skin-shell@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/blessing-skin-shell/-/blessing-skin-shell-0.2.0.tgz#2454e305c69de134164491d2715a34d599c0d8a1"
|
||||
integrity sha512-bwVHWep3jlPwgY7rAmr+KZJr1RdfVS9OTQB25avRW4EzONflQRiRgU76T8X/DeWa3PItEEGf3qNUJJuRhN5orw==
|
||||
blessing-skin-shell@^0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/blessing-skin-shell/-/blessing-skin-shell-0.3.1.tgz#154b1d3d38f7ba137a66795450f8e7d3b0b6eca9"
|
||||
integrity sha512-CaVdi3waNXIUKdpQgppY+LeOAuQB6uakHdA7bhMalw9zTz+/VTyuDtnPnkSjpFLDsbBaWL4vSqcgui+pPYZDzQ==
|
||||
|
||||
bluebird@^3.1.1, bluebird@^3.5.5:
|
||||
version "3.5.5"
|
||||
|
|
@ -2999,6 +2999,11 @@ cli-cursor@^3.1.0:
|
|||
dependencies:
|
||||
restore-cursor "^3.1.0"
|
||||
|
||||
cli-spinners@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.2.0.tgz#e8b988d9206c692302d8ee834e7a85c0144d8f77"
|
||||
integrity sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ==
|
||||
|
||||
cli-width@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
|
||||
|
|
@ -4253,6 +4258,13 @@ enhanced-resolve@^4.0.0:
|
|||
memory-fs "^0.5.0"
|
||||
tapable "^1.0.0"
|
||||
|
||||
enquirer@^2.3.4:
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.4.tgz#c608f2e1134c7f68c1c9ee056de13f9b31076de9"
|
||||
integrity sha512-pkYrrDZumL2VS6VBGDhqbajCM2xpkUNLuKfGPjfKaSIBKYopQbqEFyrOkRMIb2HDR/rO1kGhEt/5twBwtzKBXw==
|
||||
dependencies:
|
||||
ansi-colors "^3.2.1"
|
||||
|
||||
entities@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user