├── .gitignore
├── .npmignore
├── samples
├── test.ts
├── fail.js
├── succeed.js
└── ci.js
├── .editorconfig
├── spinnerAnimation.js
├── scripts
└── animation.sh
├── isInteractive.js
├── cursor.js
├── index.js
├── logSymbols.js
├── isUnicodeSupported.js
├── CHANGELOG.md
├── README.md
├── plainSpinner.js
├── LICENSE
├── .github
└── workflows
│ └── node.js.yml
├── spinner.js
├── index.d.ts
├── test
└── spinner.test.js
├── package.json
└── terminal-screenshot.svg
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | yarn-error.log
3 |
4 | coverage/
5 |
6 | .cache
7 | dist/
8 | node-warnings.logs
9 | .DS_Store
10 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | test/
3 | .github/
4 | coverage/
5 | samples/
6 | *.tgz
7 | CHANGELOG.md
8 | scripts/
9 | terminal-screenshot.svg
10 |
--------------------------------------------------------------------------------
/samples/test.ts:
--------------------------------------------------------------------------------
1 | import Spinner from '../'
2 |
3 | const spinner = Spinner('test').start()
4 | setTimeout(() => {
5 | spinner.succeed()
6 | }, 3000)
7 |
--------------------------------------------------------------------------------
/samples/fail.js:
--------------------------------------------------------------------------------
1 | const Spinner = require('../index')
2 |
3 | let spinner = Spinner('Loading').start()
4 | setTimeout(() => {
5 | spinner.fail()
6 | }, 3000)
7 |
--------------------------------------------------------------------------------
/samples/succeed.js:
--------------------------------------------------------------------------------
1 | const Spinner = require('../index')
2 |
3 | let spinner = Spinner('Loading').start()
4 | setTimeout(() => {
5 | spinner.succeed()
6 | }, 3000)
7 |
--------------------------------------------------------------------------------
/samples/ci.js:
--------------------------------------------------------------------------------
1 | const Spinner = require('../plainSpinner')
2 |
3 | let spinner = Spinner('Loading').start()
4 | setTimeout(() => {
5 | spinner.succeed()
6 | }, 3000)
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
--------------------------------------------------------------------------------
/spinnerAnimation.js:
--------------------------------------------------------------------------------
1 | const isUnicodeSupported = require('./isUnicodeSupported')
2 |
3 | const dots = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
4 |
5 | const line = ['-', '\\', '|', '/']
6 |
7 | const animation = isUnicodeSupported() ? dots : line
8 |
9 | module.exports = animation
--------------------------------------------------------------------------------
/scripts/animation.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | echo "node samples/succeed.js"
3 | sleep 1
4 | node samples/succeed.js
5 | sleep 3
6 | echo "node samples/fail.js"
7 | sleep 1
8 | node samples/fail.js
9 | sleep 3
10 | echo "node samples/ci.js"
11 | sleep 1
12 | node samples/ci.js
13 | sleep 3
14 |
--------------------------------------------------------------------------------
/isInteractive.js:
--------------------------------------------------------------------------------
1 | const process = require('process')
2 |
3 | function isInteractive({ stream = process.stdout } = {}) {
4 | return Boolean(
5 | stream &&
6 | stream.isTTY &&
7 | process.env.TERM !== 'dumb' &&
8 | !('CI' in process.env)
9 | )
10 | }
11 | module.exports = function () { return isInteractive(); };
12 |
--------------------------------------------------------------------------------
/cursor.js:
--------------------------------------------------------------------------------
1 | exports.show = (writableStream = process.stderr) => {
2 | if (!writableStream.isTTY) {
3 | return
4 | }
5 |
6 | writableStream.write('\u001B[?25h')
7 | }
8 |
9 | exports.hide = (writableStream = process.stderr) => {
10 | if (!writableStream.isTTY) {
11 | return
12 | }
13 |
14 | writableStream.write('\u001B[?25l')
15 | }
16 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const isInteractive = require('./isInteractive')
2 | const Spinner = require('./spinner')
3 | const PlainSpinner = require('./plainSpinner')
4 |
5 | const spinnerFactory = function (...options) {
6 | let SpinnerFunction = isInteractive() ? Spinner : PlainSpinner
7 | return new SpinnerFunction(...options)
8 | }
9 |
10 | module.exports = spinnerFactory
11 |
--------------------------------------------------------------------------------
/logSymbols.js:
--------------------------------------------------------------------------------
1 | const isUnicodeSupported = require('./isUnicodeSupported')
2 |
3 | const main = {
4 | info: 'ℹ',
5 | success: '✔',
6 | warning: '⚠',
7 | error: '✖'
8 | }
9 |
10 | const fallback = {
11 | info: 'i',
12 | success: '√',
13 | warning: '‼',
14 | error: '×'
15 | }
16 |
17 | const logSymbols = isUnicodeSupported() ? main : fallback
18 |
19 | module.exports = logSymbols
20 |
--------------------------------------------------------------------------------
/isUnicodeSupported.js:
--------------------------------------------------------------------------------
1 | function isUnicodeSupported() {
2 | if (process.platform !== 'win32') {
3 | return true
4 | }
5 |
6 | return (
7 | Boolean(process.env.CI) ||
8 | Boolean(process.env.WT_SESSION) || // Windows Terminal
9 | process.env.TERM_PROGRAM === 'vscode' ||
10 | process.env.TERM === 'xterm-256color' ||
11 | process.env.TERM === 'alacritty'
12 | )
13 | }
14 |
15 | module.exports = function () { return isUnicodeSupported(); };
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | This project adheres to [Semantic Versioning](http://semver.org/).
3 | ## 1.4.0
4 | * Replaced nanocolors with picocolors
5 | ## 1.3.0
6 | * Replaced colorette with nanocolors
7 | ## 1.2.2
8 | * fix options passing to the main factory
9 | ## 1.2.1
10 | * added more rules for `.npmignore` to make package slimmer
11 | ## 1.2.0
12 | * added types for TypeScript
13 | ## 1.1.1
14 | * changed colors library to `colorette`
15 |
16 | ## 1.0.0
17 | * Initial release.
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # mico-spinner
2 |
3 |
4 |
5 |
6 | Minimalistic spinner for Node.js.
7 |
8 | * Only single dependency ([Pico Colors](https://github.com/alexeyraspopov/picocolors)) without sub-dependencies. In contrast, `ora` has [30 sub-dependencies](https://npm.anvaka.com/#/view/2d/ora).
9 | * Detects Unicode and color support in terminal.
10 |
11 | ## Usage
12 |
13 | ```js
14 | let micoSpinner = require('mico-spinner')
15 |
16 | let spinner = micoSpinner('Long task').start()
17 | try {
18 | await longTask()
19 | spinner.succeed()
20 | } catch (e) {
21 | spinner.fail()
22 | console.error(e.stack)
23 | }
24 | ```
25 |
26 | ### Similar projects
27 | - [Nano Spinner](https://github.com/usmanyunusov/nanospinner)
28 |
--------------------------------------------------------------------------------
/plainSpinner.js:
--------------------------------------------------------------------------------
1 | const process = require('process')
2 | const readline = require('readline')
3 | const c = require('picocolors')
4 |
5 | const logSymbols = require('./logSymbols')
6 |
7 | function Spinner(textStr = '', opts = {}) {
8 | let text = textStr
9 |
10 | let stream = opts.stream || process.stderr
11 |
12 | return {
13 | text,
14 | stopAndPrint({ color, symbol }) {
15 | let colorFn = c[color]
16 | stream.write(`${colorFn(symbol)} ${text}\n`)
17 | return this
18 | },
19 | fail() {
20 | return this.stopAndPrint({ color: 'red', symbol: logSymbols.error })
21 | },
22 | succeed() {
23 | return this.stopAndPrint({ color: 'green', symbol: logSymbols.success })
24 | },
25 | start() {
26 | stream.write(`${c.yellow('-')} ${text}\n`)
27 | return this
28 | },
29 | stop() {
30 | readline.clearLine(stream)
31 |
32 | return this
33 | }
34 | }
35 | }
36 |
37 | module.exports = Spinner
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright 2017 Nikolay Topkaridi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: Node.js CI
5 |
6 | on:
7 | push:
8 | branches: [ main ]
9 | pull_request:
10 | branches: [ main ]
11 |
12 | env:
13 | FORCE_COLOR: 2
14 |
15 | jobs:
16 | full:
17 | name: Node.js 16 Full
18 | runs-on: ubuntu-latest
19 | steps:
20 | - name: Checkout the repository
21 | uses: actions/checkout@v2
22 | - name: Install Node.js
23 | uses: actions/setup-node@v2
24 | with:
25 | node-version: 16
26 | - name: Install dependencies
27 | uses: bahmutov/npm-install@v1
28 | - name: Run tests
29 | run: yarn test
30 | - name: Run sample
31 | run: node samples/succeed.js
32 | build:
33 |
34 | runs-on: ubuntu-latest
35 |
36 | strategy:
37 | matrix:
38 | node-version: [14.x, 12.x]
39 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
40 |
41 | steps:
42 | - uses: actions/checkout@v2
43 | - name: Use Node.js ${{ matrix.node-version }}
44 | uses: actions/setup-node@v2
45 | with:
46 | node-version: ${{ matrix.node-version }}
47 | - name: Install dependencies
48 | uses: bahmutov/npm-install@v1
49 | - name: Run unit tests
50 | run: npx jest
51 | - name: Test sample
52 | run: node samples/succeed.js
53 |
--------------------------------------------------------------------------------
/spinner.js:
--------------------------------------------------------------------------------
1 | const process = require('process')
2 | const readline = require('readline')
3 | const c = require('picocolors')
4 |
5 | const spinnersList = require('./spinnerAnimation')
6 | const logSymbols = require('./logSymbols')
7 | const { show: showCursor, hide: hideCursor } = require('./cursor')
8 |
9 | function Spinner(textStr = '', opts = {}) {
10 | let text = textStr
11 | let timer = null
12 |
13 | let stream = opts.stream || process.stderr
14 |
15 | return {
16 | text,
17 | stopAndPrint({ color, symbol }) {
18 | clearInterval(timer)
19 | let colorFn = c[color]
20 | readline.clearLine(stream)
21 | readline.cursorTo(stream, 0)
22 |
23 | stream.write(`${colorFn(symbol)} ${text}\n`)
24 |
25 | showCursor()
26 | return this
27 | },
28 | fail() {
29 | return this.stopAndPrint({ color: 'red', symbol: logSymbols.error })
30 | },
31 | succeed() {
32 | return this.stopAndPrint({ color: 'green', symbol: logSymbols.success })
33 | },
34 | start() {
35 | hideCursor()
36 |
37 | let spinners = spinnersList
38 | let index = 0
39 |
40 | timer = setInterval(() => {
41 | index = this.intervalCallback(index, spinners)
42 | }, 100)
43 | return this
44 | },
45 | intervalCallback(index, spinners) {
46 | let line = spinners[index]
47 |
48 | if (line === undefined) {
49 | index = 0
50 | line = spinners[index]
51 | }
52 | readline.clearLine(stream)
53 | stream.write(`${c.green(line)} ${text}`)
54 |
55 | readline.cursorTo(stream, 0)
56 |
57 | return index + 1
58 | },
59 | stop() {
60 | clearInterval(timer)
61 |
62 | readline.clearLine(stream)
63 |
64 | showCursor()
65 | return this
66 | }
67 | }
68 | }
69 |
70 | module.exports = Spinner
71 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | type Color =
2 | | 'black'
3 | | 'red'
4 | | 'green'
5 | | 'yellow'
6 | | 'blue'
7 | | 'magenta'
8 | | 'cyan'
9 | | 'white'
10 | | 'gray'
11 |
12 | type StopAndPrintOptions = {
13 | color: Color
14 | symbol: string
15 | }
16 |
17 | interface Options {
18 | /**
19 | Stream to write the output.
20 | You could for example set this to `process.stdout` instead.
21 | @default process.stderr
22 | */
23 | stream?: NodeJS.WriteStream
24 | }
25 |
26 | interface Spinner {
27 | /**
28 | Text to display after the spinner.
29 | */
30 | readonly text: string
31 |
32 | /**
33 | Stop the spinner, change it to a red `✖`
34 | @returns The spinner instance.
35 | */
36 | fail(): Spinner
37 |
38 | /**
39 | Stop the spinner, change it to a green `✔`
40 | @returns The spinner instance.
41 | */
42 | succeed(): Spinner
43 |
44 | /**
45 | Start the spinner.
46 | @returns The spinner instance.
47 | */
48 | start(): Spinner
49 |
50 | /**
51 | Stop and clear the spinner.
52 | @returns The spinner instance.
53 | */
54 | stop(): Spinner
55 |
56 | /**
57 | Stop the spinner and change the symbol or text.
58 | @returns The spinner instance.
59 | */
60 | stopAndPrint(opts: StopAndPrintOptions): Spinner
61 | }
62 |
63 | /**
64 | Minimalistic spinner for Node.js
65 |
66 | @param textStr - The promise to start the spinner for.
67 | @param opts - The options for the spinner.
68 |
69 | @example
70 | ```
71 | let micoSpinner = require('mico-spinner')
72 |
73 | let spinner = micoSpinner('Long task').start()
74 | try {
75 | await longTask()
76 | spinner.succeed()
77 | } catch (e) {
78 | spinner.fail()
79 | console.error(e.stack)
80 | }
81 | ```
82 |
83 | @returns The spinner instance.
84 | */
85 | declare function MicoSpinner(textStr: string, opts?: Options): Spinner
86 |
87 | export = MicoSpinner
88 |
--------------------------------------------------------------------------------
/test/spinner.test.js:
--------------------------------------------------------------------------------
1 | const { red, green } = require('picocolors')
2 |
3 | const logSymbols = require('../logSymbols')
4 | const Spinner = require('../spinner')
5 |
6 | jest.useFakeTimers()
7 | const testString = 'LoL!'
8 |
9 | jest.mock('process', () => ({
10 | stderr: {
11 | clearLine: jest.fn(),
12 | write: jest.fn(),
13 | cursorTo: jest.fn()
14 | }
15 | }))
16 |
17 | jest.mock('readline', () => ({
18 | clearLine: jest.fn(),
19 | write: jest.fn(),
20 | cursorTo: jest.fn()
21 | }))
22 |
23 | describe('spinner', () => {
24 | afterEach(() => {
25 | jest.clearAllTimers()
26 | jest.clearAllMocks()
27 | })
28 |
29 | it('creates an empty spinner', () => {
30 | let spinner = Spinner().start()
31 | expect(spinner.text).toEqual('')
32 | expect(setInterval).toHaveBeenCalledTimes(1)
33 | })
34 |
35 | it('creates a spinner', () => {
36 | let spinner = Spinner(testString).start()
37 | expect(spinner.text).toEqual(testString)
38 | expect(setInterval).toHaveBeenCalledTimes(1)
39 | })
40 |
41 | it('intervalCallback', () => {
42 | let _Spinner = require('../spinner')
43 |
44 | let spinner = _Spinner(testString)
45 | let spinners = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
46 |
47 | expect(spinner.intervalCallback(10, spinners)).toEqual(1)
48 | })
49 |
50 | it('scroll to first symbol after the loop', () => {
51 | let process = require('process')
52 | let _Spinner = require('../spinner')
53 | let spinner = _Spinner(testString)
54 | spinner.start()
55 | jest.advanceTimersByTime(1100)
56 | expect(process.stderr.write).toHaveBeenLastCalledWith(`${green('⠋')} LoL!`)
57 | spinner.stop()
58 | })
59 |
60 | it('scroll to last animation', () => {
61 | let process = require('process')
62 | let readline = require('readline')
63 | let _Spinner = require('../spinner')
64 |
65 | let spinner = _Spinner(testString)
66 | spinner.start()
67 | jest.advanceTimersByTime(1000)
68 |
69 | expect(readline.clearLine).toHaveBeenCalledTimes(10)
70 | expect(readline.cursorTo).toHaveBeenCalledWith(process.stderr, 0)
71 | spinner.stop()
72 | })
73 |
74 | it('stop and print something generic', () => {
75 | let process = require('process')
76 | let readline = require('readline')
77 | let _Spinner = require('../spinner')
78 |
79 | let spinner = _Spinner(testString)
80 | spinner.stopAndPrint({ color: 'red', symbol: 'X' })
81 | expect(readline.clearLine).toHaveBeenCalledWith(process.stderr)
82 | expect(process.stderr.write).toHaveBeenCalledWith(`${red('X')} LoL!\n`)
83 | })
84 |
85 | it('allow custom stream', () => {
86 | let readline = require('readline')
87 | let _Spinner = require('../spinner')
88 | let stream = { write: jest.fn() }
89 | let spinner = _Spinner(testString, { stream })
90 | spinner.stopAndPrint({ color: 'red', symbol: 'X' })
91 | expect(readline.clearLine).toHaveBeenCalledWith(stream)
92 | expect(stream.write).toHaveBeenCalledWith(`${red('X')} LoL!\n`)
93 | })
94 |
95 | it('#fail', () => {
96 | let spinner = Spinner(testString)
97 | let spy = jest.spyOn(spinner, 'stopAndPrint')
98 | spinner.fail()
99 | expect(spy).toHaveBeenCalledWith({ color: 'red', symbol: logSymbols.error })
100 | })
101 |
102 | it('#succeed', () => {
103 | let spinner = Spinner(testString)
104 | let spy = jest.spyOn(spinner, 'stopAndPrint')
105 | spinner.succeed()
106 | expect(spy).toHaveBeenCalledWith({
107 | color: 'green',
108 | symbol: logSymbols.success
109 | })
110 | })
111 | })
112 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mico-spinner",
3 | "version": "1.4.0",
4 | "description": "minimalistic spinner for nodejs projects",
5 | "main": "index.js",
6 | "types": "index.d.ts",
7 | "author": "Nikolay Topkaridi",
8 | "license": "MIT",
9 | "repository": "enemycnt/mico-spinner",
10 | "scripts": {
11 | "test": "jest --coverage --forceExit && eslint .",
12 | "record-terminal-screenshot": "termtosvg terminal-screenshot.svg -c='./scripts/animation.sh' -g=24x10 -t window_frame"
13 | },
14 | "devDependencies": {
15 | "@logux/eslint-config": "^45.4.4",
16 | "@logux/sharec-config": "^0.10.2",
17 | "check-dts": "^0.4.4",
18 | "clean-publish": "^2.2.0",
19 | "cross-spawn": "^7.0.3",
20 | "eslint": "^7.28.0",
21 | "eslint-config-standard": "^16.0.3",
22 | "eslint-plugin-import": "^2.23.4",
23 | "eslint-plugin-jest": "^24.3.6",
24 | "eslint-plugin-node": "^11.1.0",
25 | "eslint-plugin-prefer-let": "^1.1.0",
26 | "eslint-plugin-promise": "^5.1.0",
27 | "eslint-plugin-security": "^1.4.0",
28 | "eslint-plugin-unicorn": "^33.0.1",
29 | "jest": "^26.6.3",
30 | "lint-staged": "^11.0.0",
31 | "prettier": "^2.3.1",
32 | "print-snapshots": "^0.3.2",
33 | "simple-git-hooks": "^2.4.1",
34 | "typescript": "^4.3.4",
35 | "yaspeller": "^7.0.0"
36 | },
37 | "eslintConfig": {
38 | "extends": "@logux/eslint-config",
39 | "rules": {
40 | "node/no-unsupported-features/es-syntax": "off",
41 | "security/detect-non-literal-require": "off",
42 | "security/detect-non-literal-regexp": "off",
43 | "node/global-require": "off",
44 | "no-console": "off"
45 | },
46 | "overrides": [
47 | {
48 | "files": "*.test.js",
49 | "rules": {
50 | "node/no-extraneous-require": "off"
51 | }
52 | },
53 | {
54 | "files": "packages/*/test/**/*.js",
55 | "rules": {
56 | "node/no-unpublished-require": "off"
57 | }
58 | },
59 | {
60 | "files": "packages/size-limit/run.js",
61 | "rules": {
62 | "consistent-return": "off"
63 | }
64 | }
65 | ]
66 | },
67 | "eslintIgnore": [
68 | "node_modules",
69 | "**/errors.ts",
70 | "index.d.ts"
71 | ],
72 | "jest": {
73 | "testEnvironment": "node",
74 | "modulePathIgnorePatterns": [
75 | "./samples/",
76 | "./dist"
77 | ],
78 | "coverageThreshold": {
79 | "global": {
80 | "statements": 90
81 | }
82 | }
83 | },
84 | "simple-git-hooks": {
85 | "pre-commit": "npx lint-staged"
86 | },
87 | "prettier": {
88 | "arrowParens": "avoid",
89 | "jsxSingleQuote": false,
90 | "quoteProps": "consistent",
91 | "semi": false,
92 | "singleQuote": true,
93 | "trailingComma": "none"
94 | },
95 | "lint-staged": {
96 | "*.md": "yaspeller",
97 | "*.js": [
98 | "prettier --write",
99 | "eslint --fix"
100 | ],
101 | "*.ts": [
102 | "prettier --write",
103 | "eslint --fix"
104 | ]
105 | },
106 | "yaspeller": {
107 | "lang": "en",
108 | "ignoreCapitalization": true,
109 | "ignoreText": [
110 | " \\(by [^)]+\\)."
111 | ],
112 | "dictionary": [
113 | "linter",
114 | "JS",
115 | "polyfills",
116 | "MobX",
117 | "UI",
118 | "Autoprefixer",
119 | "PostCSS",
120 | "Browserslist",
121 | "EmojiMart",
122 | "Logux",
123 | "webpack’s",
124 | "bundler",
125 | "Vue",
126 | "Rollup",
127 | "CI",
128 | "gzip",
129 | "js",
130 | "kB",
131 | "nanoid",
132 | "npm",
133 | "Storeon",
134 | "Travis",
135 | "webpack",
136 | "Versioning",
137 | "JSDoc",
138 | "Puppeter",
139 | "estimo",
140 | "bundlers",
141 | "CLI",
142 | "CRM",
143 | "brotli",
144 | "PnP",
145 | "ES",
146 | "GitHub",
147 | "modifyWebpackConfig",
148 | "mico-spinner",
149 | "mico",
150 | "Minimalistic",
151 | "nanocolors",
152 | "colorette",
153 | "pico",
154 | "picocolors"
155 | ]
156 | },
157 | "sharec": {
158 | "config": "@logux/sharec-config",
159 | "version": "0.10.2"
160 | },
161 | "dependencies": {
162 | "picocolors": "^0.2.0"
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/terminal-screenshot.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------