├── .editorconfig ├── .github ├── codecov.yml └── workflows │ ├── autofix.yml │ └── ci.yml ├── .gitignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── assets ├── fancy.png └── v1.png ├── basic.d.ts ├── browser.d.ts ├── build.config.ts ├── core.d.ts ├── eslint.config.mjs ├── examples ├── basic.ts ├── box.ts ├── error.ts ├── fancy.ts ├── index.html ├── index.legacy.html ├── json.ts ├── mock.ts ├── no-width.ts ├── pause.ts ├── prompt.mjs ├── prompt.ts ├── raw.ts ├── sample.ts ├── spam.ts ├── special.ts ├── spinner.ts ├── tree.ts ├── utils │ ├── index.ts │ └── sentence.ts ├── wrap-all.ts ├── wrap-console.ts └── wrap-std.ts ├── lib └── index.cjs ├── package.json ├── pnpm-lock.yaml ├── renovate.json ├── src ├── basic.ts ├── browser.ts ├── consola.ts ├── constants.ts ├── core.ts ├── index.ts ├── prompt.ts ├── reporters │ ├── basic.ts │ ├── browser.ts │ └── fancy.ts ├── shared.ts ├── types.ts ├── utils.ts └── utils │ ├── box.ts │ ├── color.ts │ ├── error.ts │ ├── format.ts │ ├── log.ts │ ├── stream.ts │ ├── string.ts │ └── tree.ts ├── test └── consola.test.ts ├── tsconfig.json └── utils.d.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | threshold: 5% 6 | -------------------------------------------------------------------------------- /.github/workflows/autofix.yml: -------------------------------------------------------------------------------- 1 | name: autofix.ci # needed to securely identify the workflow 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: ["main"] 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | autofix: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - run: npm i -fg corepack && corepack enable 17 | - uses: actions/setup-node@v4 18 | with: 19 | node-version: 20 20 | cache: "pnpm" 21 | - run: pnpm install 22 | - name: Fix lint issues 23 | run: pnpm run lint:fix 24 | - uses: autofix-ci/action@551dded8c6cc8a1054039c8bc0b8b48c51dfc6ef 25 | with: 26 | commit-message: "chore: apply automated updates" 27 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | ci: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - run: npm i -fg corepack && corepack enable 17 | - uses: actions/setup-node@v4 18 | with: 19 | node-version: 20 20 | cache: "pnpm" 21 | - run: pnpm install 22 | - run: pnpm lint 23 | - run: pnpm build 24 | - run: pnpm vitest --coverage 25 | - uses: codecov/codecov-action@v5 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log* 3 | dist 4 | coverage 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ## v3.4.2 6 | 7 | [compare changes](https://github.com/unjs/consola/compare/v3.4.1...v3.4.2) 8 | 9 | ### 🩹 Fixes 10 | 11 | - Export tree utils ([#349](https://github.com/unjs/consola/pull/349)) 12 | - Calculate box width with the title width ([#362](https://github.com/unjs/consola/pull/362)) 13 | 14 | ### 🏡 Chore 15 | 16 | - Cleanup unused deps ([#361](https://github.com/unjs/consola/pull/361)) 17 | - Update deps ([1e5f846](https://github.com/unjs/consola/commit/1e5f846)) 18 | 19 | ### ❤️ Contributors 20 | 21 | - Kricsleo ([@kricsleo](https://github.com/kricsleo)) 22 | - Scott Humphries ([@sscotth](https://github.com/sscotth)) 23 | - Pooya Parsa ([@pi0](https://github.com/pi0)) 24 | 25 | ## v3.4.1 26 | 27 | [compare changes](https://github.com/unjs/consola/compare/v3.4.0...v3.4.1) 28 | 29 | ### 🩹 Fixes 30 | 31 | - Remove all message lines from stack ([#356](https://github.com/unjs/consola/pull/356)) 32 | 33 | ### 🏡 Chore 34 | 35 | - Update ci ([#353](https://github.com/unjs/consola/pull/353)) 36 | - Update deps ([da26f10](https://github.com/unjs/consola/commit/da26f10)) 37 | 38 | ### ❤️ Contributors 39 | 40 | - Pooya Parsa ([@pi0](https://github.com/pi0)) 41 | - Nozomu Ikuta ([@nozomuikuta](https://github.com/nozomuikuta)) 42 | 43 | ## v3.4.0 44 | 45 | [compare changes](https://github.com/unjs/consola/compare/v3.3.3...v3.4.0) 46 | 47 | ### 🚀 Enhancements 48 | 49 | - Use upstream `@clack/prompts` ([#332](https://github.com/unjs/consola/pull/332)) 50 | 51 | ### 🩹 Fixes 52 | 53 | - Calculate box width without escape sequence chars ([#336](https://github.com/unjs/consola/pull/336)) 54 | 55 | ### 💅 Refactors 56 | 57 | - Keep prompt styles (cont. #332) ([#332](https://github.com/unjs/consola/issues/332)) 58 | 59 | ### 📦 Build 60 | 61 | - Update exports for node16 typescript resolution ([#331](https://github.com/unjs/consola/pull/331)) 62 | 63 | ### 🏡 Chore 64 | 65 | - Update deps ([9193d63](https://github.com/unjs/consola/commit/9193d63)) 66 | - Apply automated updates ([fc8b9b9](https://github.com/unjs/consola/commit/fc8b9b9)) 67 | 68 | ### ❤️ Contributors 69 | 70 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 71 | - Yongqi 72 | 73 | ## v3.3.3 74 | 75 | [compare changes](https://github.com/unjs/consola/compare/v3.3.2...v3.3.3) 76 | 77 | ### 📦 Build 78 | 79 | - Revert "build: update exports for `node16` typescript resolution" ([2065136](https://github.com/unjs/consola/commit/2065136)) 80 | 81 | ### ❤️ Contributors 82 | 83 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 84 | 85 | ## v3.3.2 86 | 87 | [compare changes](https://github.com/unjs/consola/compare/v3.3.1...v3.3.2) 88 | 89 | ### 📦 Build 90 | 91 | - Patch `string-width` for node 14 support ([421c663](https://github.com/unjs/consola/commit/421c663)) 92 | - Update exports for `node16` typescript resolution ([18bc852](https://github.com/unjs/consola/commit/18bc852)) 93 | 94 | ### ❤️ Contributors 95 | 96 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 97 | 98 | ## v3.3.1 99 | 100 | [compare changes](https://github.com/unjs/consola/compare/v3.3.0...v3.3.1) 101 | 102 | ### 🩹 Fixes 103 | 104 | - **fancy:** Fallback when`Intl` is unavailable ([#326](https://github.com/unjs/consola/pull/326)) 105 | 106 | ### ❤️ Contributors 107 | 108 | - Red Huang 109 | 110 | ## v3.3.0 111 | 112 | [compare changes](https://github.com/unjs/consola/compare/v3.2.3...v3.3.0) 113 | 114 | ### 🚀 Enhancements 115 | 116 | - **utils:** `formatTree` utility ([#223](https://github.com/unjs/consola/pull/223)) 117 | - Export prompt option types ([#301](https://github.com/unjs/consola/pull/301)) 118 | - Support report error `cause` ([#308](https://github.com/unjs/consola/pull/308)) 119 | - **prompt:** Configurable cancel strategy ([#325](https://github.com/unjs/consola/pull/325)) 120 | - **formatTree:** Support max depth ([#267](https://github.com/unjs/consola/pull/267)) 121 | 122 | ### 🩹 Fixes 123 | 124 | - Use `initial` in `select` and `multiselect` prompts ([#232](https://github.com/unjs/consola/pull/232)) 125 | - Make box title color same as border ([#236](https://github.com/unjs/consola/pull/236)) 126 | 127 | ### 📖 Documentation 128 | 129 | - Update screenshot ([205d9c8](https://github.com/unjs/consola/commit/205d9c8)) 130 | - Add vitest ([#182](https://github.com/unjs/consola/pull/182)) 131 | - Add note about raw method ([#271](https://github.com/unjs/consola/pull/271)) 132 | - Add jsdocs for utils functions ([#286](https://github.com/unjs/consola/pull/286)) 133 | - Add jsdocs for top-level functions ([#288](https://github.com/unjs/consola/pull/288)) 134 | 135 | ### 📦 Build 136 | 137 | - Fix subpath types ([#265](https://github.com/unjs/consola/pull/265)) 138 | - Add `require` condition for browser builds ([#243](https://github.com/unjs/consola/pull/243)) 139 | 140 | ### 🌊 Types 141 | 142 | - Fix prompt with `select` type return value type ([#238](https://github.com/unjs/consola/pull/238)) 143 | 144 | ### 🏡 Chore 145 | 146 | - Update dependencies ([68b36c7](https://github.com/unjs/consola/commit/68b36c7)) 147 | - Update dependencies ([dff1ef8](https://github.com/unjs/consola/commit/dff1ef8)) 148 | - Update eslint to v9 ([238d677](https://github.com/unjs/consola/commit/238d677)) 149 | - Lint ([985a786](https://github.com/unjs/consola/commit/985a786)) 150 | - Update pnpm to v9 ([61adfbe](https://github.com/unjs/consola/commit/61adfbe)) 151 | - Update ci scripts ([9545b65](https://github.com/unjs/consola/commit/9545b65)) 152 | - Apply automated updates ([df0e555](https://github.com/unjs/consola/commit/df0e555)) 153 | - Update dependencies ([e851525](https://github.com/unjs/consola/commit/e851525)) 154 | - Fix lint issues ([8238844](https://github.com/unjs/consola/commit/8238844)) 155 | - Update deps ([093d966](https://github.com/unjs/consola/commit/093d966)) 156 | - Lint ([64cd547](https://github.com/unjs/consola/commit/64cd547)) 157 | - Update clack/core ([e2aa5c9](https://github.com/unjs/consola/commit/e2aa5c9)) 158 | 159 | ### 🎨 Styles 160 | 161 | - Format repo ([899173f](https://github.com/unjs/consola/commit/899173f)) 162 | 163 | ### 🤖 CI 164 | 165 | - Use conventional commit for autofix ([#217](https://github.com/unjs/consola/pull/217)) 166 | 167 | ### ❤️ Contributors 168 | 169 | - Guo ([@Plumbiu](http://github.com/Plumbiu)) 170 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 171 | - Kongmoumou ([@kongmoumou](http://github.com/kongmoumou)) 172 | - Max ([@onmax](http://github.com/onmax)) 173 | - Michel EDIGHOFFER 174 | - Sébastien Chopin ([@atinux](http://github.com/atinux)) 175 | - Estéban 176 | - Nozomu Ikuta ([@nozomuikuta](http://github.com/nozomuikuta)) 177 | - Maxim Molochkov ([@klaseca](http://github.com/klaseca)) 178 | - Xjccc ([@xjccc](http://github.com/xjccc)) 179 | - Gangan ([@shinGangan](http://github.com/shinGangan)) 180 | - Daniel Roe ([@danielroe](http://github.com/danielroe)) 181 | 182 | ## v3.2.3 183 | 184 | [compare changes](https://github.com/unjs/consola/compare/v3.2.2...v3.2.3) 185 | 186 | 187 | ### 🩹 Fixes 188 | 189 | - **types:** Partial style options for `box` ([#210](https://github.com/unjs/consola/pull/210)) 190 | - **types:** Add backward compatible declarations ([e46733b](https://github.com/unjs/consola/commit/e46733b)) 191 | 192 | ### 🏡 Chore 193 | 194 | - Remove extra `await` in `spinner` example ([#211](https://github.com/unjs/consola/pull/211)) 195 | - Add autofix ci ([b3aa049](https://github.com/unjs/consola/commit/b3aa049)) 196 | - Update prettier ([9a4b67e](https://github.com/unjs/consola/commit/9a4b67e)) 197 | 198 | ### ❤️ Contributors 199 | 200 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 201 | - Alexander Topalo 202 | - Estéban ([@Barbapapazes](http://github.com/Barbapapazes)) 203 | 204 | ## v3.2.2 205 | 206 | [compare changes](https://github.com/unjs/consola/compare/v3.2.1...v3.2.2) 207 | 208 | 209 | ### 🩹 Fixes 210 | 211 | - **fancy:** Add node 14 compatibility ([#204](https://github.com/unjs/consola/pull/204)) 212 | 213 | ### 📦 Build 214 | 215 | - **pkg:** Add supported engines field ([#179](https://github.com/unjs/consola/pull/179)) 216 | 217 | ### ❤️ Contributors 218 | 219 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 220 | 221 | ## v3.2.1 222 | 223 | [compare changes](https://github.com/unjs/consola/compare/v3.2.0...v3.2.1) 224 | 225 | 226 | ### 🩹 Fixes 227 | 228 | - **box:** Fix preset naming for `singleThick` ([#201](https://github.com/unjs/consola/pull/201)) 229 | - **fancy:** Style underscore with surrounding spaces ([#203](https://github.com/unjs/consola/pull/203)) 230 | 231 | ### ❤️ Contributors 232 | 233 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 234 | - Christian Preston ([@cpreston321](http://github.com/cpreston321)) 235 | 236 | ## v3.2.0 237 | 238 | [compare changes](https://github.com/unjs/consola/compare/v3.1.0...v3.2.0) 239 | 240 | 241 | ### 🚀 Enhancements 242 | 243 | - **fancy:** Support underlining ([#191](https://github.com/unjs/consola/pull/191)) 244 | - `consola.box` ([#193](https://github.com/unjs/consola/pull/193)) 245 | - `consola/utils` subpath export ([#199](https://github.com/unjs/consola/pull/199)) 246 | - Color utils ([#200](https://github.com/unjs/consola/pull/200)) 247 | 248 | ### 🩹 Fixes 249 | 250 | - Inherit mocks ([#183](https://github.com/unjs/consola/pull/183)) 251 | - Correct and improve return types for single and multi select prompts ([#197](https://github.com/unjs/consola/pull/197)) 252 | - Preserve tag casing ([#190](https://github.com/unjs/consola/pull/190)) 253 | 254 | ### 🏡 Chore 255 | 256 | - Update prompt example ([#196](https://github.com/unjs/consola/pull/196)) 257 | - Lint code ([d424218](https://github.com/unjs/consola/commit/d424218)) 258 | - Update dependencies ([dabb705](https://github.com/unjs/consola/commit/dabb705)) 259 | 260 | ### ❤️ Contributors 261 | 262 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 263 | - Christian Preston ([@cpreston321](http://github.com/cpreston321)) 264 | - Leex ([@jsonleex](http://github.com/jsonleex)) 265 | - Inesh Bose 266 | - Damian Głowala 267 | 268 | ## v3.1.0 269 | 270 | [compare changes](https://github.com/unjs/consola/compare/v3.0.2...v3.1.0) 271 | 272 | 273 | ### 🚀 Enhancements 274 | 275 | - Support `fancy` option for `createConsola` and improve docs ([#177](https://github.com/unjs/consola/pull/177)) 276 | - `/basic`, `/core` and `/browser` subpath exports ([#178](https://github.com/unjs/consola/pull/178)) 277 | 278 | ### 🏡 Chore 279 | 280 | - Add json example ([943992d](https://github.com/unjs/consola/commit/943992d)) 281 | - Update the docs ([a952bc2](https://github.com/unjs/consola/commit/a952bc2)) 282 | 283 | ### ❤️ Contributors 284 | 285 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 286 | 287 | ## v3.0.2 288 | 289 | [compare changes](https://github.com/unjs/consola/compare/v3.0.1...v3.0.2) 290 | 291 | 292 | ### 🩹 Fixes 293 | 294 | - **`mockTypes`:** Mock on `options.typs` ([f9d86b6](https://github.com/unjs/consola/commit/f9d86b6)) 295 | - Type `.raw` for types ([dfb976f](https://github.com/unjs/consola/commit/dfb976f)) 296 | 297 | ### 💅 Refactors 298 | 299 | - Use individual named exports of reporters ([57bb579](https://github.com/unjs/consola/commit/57bb579)) 300 | 301 | ### 🏡 Chore 302 | 303 | - Add `codecov.yml` ([1f50123](https://github.com/unjs/consola/commit/1f50123)) 304 | - Update readme ([5a4708d](https://github.com/unjs/consola/commit/5a4708d)) 305 | - Fix mock example ([4dadfb3](https://github.com/unjs/consola/commit/4dadfb3)) 306 | 307 | ### ❤️ Contributors 308 | 309 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 310 | 311 | ## v3.0.1 312 | 313 | [compare changes](https://github.com/unjs/consola/compare/v3.0.0...v3.0.1) 314 | 315 | 316 | ### 🩹 Fixes 317 | 318 | - **utils:** Use default `stream.write` for workers support ([#173](https://github.com/unjs/consola/pull/173)) 319 | - Wrap `options.stdout` and `options.stderr` for wrapStd ([ab59db6](https://github.com/unjs/consola/commit/ab59db6)) 320 | 321 | ### 💅 Refactors 322 | 323 | - **fancy:** More minimal badges when width cannot be determined ([ad24029](https://github.com/unjs/consola/commit/ad24029)) 324 | 325 | ### ❤️ Contributors 326 | 327 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 328 | 329 | ## v3.0.0 330 | 331 | [compare changes](https://github.com/unjs/consola/compare/v2.15.2...v3.0.0) 332 | 333 | 334 | ### 🚀 Enhancements 335 | 336 | - Default `logLevel` to 1 in test environments ([#134](https://github.com/unjs/consola/pull/134)) 337 | - Support literal for logLevels ([#133](https://github.com/unjs/consola/pull/133)) 338 | - Expose `createConsola` and named exports ([ef6e5e5](https://github.com/unjs/consola/commit/ef6e5e5)) 339 | - `consola.prompt` util ([#170](https://github.com/unjs/consola/pull/170)) 340 | - `consola.fail` log level ([#153](https://github.com/unjs/consola/pull/153)) 341 | - Pass `formatOptions` and other options to reporters ([d77286a](https://github.com/unjs/consola/commit/d77286a)) 342 | - Show stack trace with `consola.trace` ([#151](https://github.com/unjs/consola/pull/151)) 343 | 344 | ### 🔥 Performance 345 | 346 | - Switch from chalk to colorette ([271b4db](https://github.com/unjs/consola/commit/271b4db)) 347 | - Remove `dayjs` dependency ([d6a3776](https://github.com/unjs/consola/commit/d6a3776)) 348 | 349 | ### 🩹 Fixes 350 | 351 | - Add `.raw` to mocked functions ([987dadc](https://github.com/unjs/consola/commit/987dadc)) 352 | - Type consola instance with built-in type functions ([1a4b893](https://github.com/unjs/consola/commit/1a4b893)) 353 | - Default value for color format utils ([ec9be78](https://github.com/unjs/consola/commit/ec9be78)) 354 | - **fancy:** Show time and tag on right when width cannot be determined ([#128](https://github.com/unjs/consola/pull/128)) 355 | - Pass level from `CONSOLA_LEVEL` to the `defaults` ([#129](https://github.com/unjs/consola/pull/129)) 356 | - **consola:** Type defaults overrides generic defaults ([d3d3c05](https://github.com/unjs/consola/commit/d3d3c05)) 357 | - **fancy:** Improve colors ([99c2a4f](https://github.com/unjs/consola/commit/99c2a4f)) 358 | - **promp:** Options is optional ([817626f](https://github.com/unjs/consola/commit/817626f)) 359 | 360 | ### 💅 Refactors 361 | 362 | - ⚠️ Rewrite consola with typescript ([4479d2f](https://github.com/unjs/consola/commit/4479d2f)) 363 | - Rename `global` to `globalThis` ([bd03098](https://github.com/unjs/consola/commit/bd03098)) 364 | - **utils:** Rename `global` to `globalThis` ([8c3ef77](https://github.com/unjs/consola/commit/8c3ef77)) 365 | - Strict typechecks ([63bbd56](https://github.com/unjs/consola/commit/63bbd56)) 366 | - Remove `globalThis` caching ([4e7b909](https://github.com/unjs/consola/commit/4e7b909)) 367 | - Drop `json` and `winston` reporters ([5af0e99](https://github.com/unjs/consola/commit/5af0e99)) 368 | - Move all options to `consola.options` without duplication ([2d31ef4](https://github.com/unjs/consola/commit/2d31ef4)) 369 | - Move spam logic into `_lastLog` object ([cabd04f](https://github.com/unjs/consola/commit/cabd04f)) 370 | - Remove global `async` option ([edd1bb9](https://github.com/unjs/consola/commit/edd1bb9)) 371 | - **types:** Merge `LogTypeLiteral` and `logtype` types to `LogType` ([da1bc73](https://github.com/unjs/consola/commit/da1bc73)) 372 | - ⚠️ Move log levels and types to constants ([514f5b3](https://github.com/unjs/consola/commit/514f5b3)) 373 | - Use `index.node.ts` for main build ([b92d23b](https://github.com/unjs/consola/commit/b92d23b)) 374 | - Improve types and exports ([b380d21](https://github.com/unjs/consola/commit/b380d21)) 375 | - Improve fancy reporter ([bc90db8](https://github.com/unjs/consola/commit/bc90db8)) 376 | - Revert back to `dist/index.*` for bw compatibility ([98e300f](https://github.com/unjs/consola/commit/98e300f)) 377 | - **fancy:** Better start color and icon ([5a01d53](https://github.com/unjs/consola/commit/5a01d53)) 378 | 379 | ### 📖 Documentation 380 | 381 | - Fix links to the source files ([#172](https://github.com/unjs/consola/pull/172)) 382 | 383 | ### 📦 Build 384 | 385 | - Use backward compatible cjs wrapper for default export ([e2e6aa6](https://github.com/unjs/consola/commit/e2e6aa6)) 386 | 387 | ### 🏡 Chore 388 | 389 | - **release:** 2.15.3 ([c99ff6c](https://github.com/unjs/consola/commit/c99ff6c)) 390 | - Make example/index.js working ([#110](https://github.com/unjs/consola/pull/110)) 391 | - Add LICENSE ([#121](https://github.com/unjs/consola/pull/121)) 392 | - **npm:** Update repository to unjs orgnization ([#125](https://github.com/unjs/consola/pull/125)) 393 | - Add prerelease script ([cfaba5e](https://github.com/unjs/consola/commit/cfaba5e)) 394 | - Hide rollup warn ([5c3b7f1](https://github.com/unjs/consola/commit/5c3b7f1)) 395 | - Ignore coverage ([da557ac](https://github.com/unjs/consola/commit/da557ac)) 396 | - Update examples ([e07e3ab](https://github.com/unjs/consola/commit/e07e3ab)) 397 | - **release:** V3.0.0-1 ([c24ae27](https://github.com/unjs/consola/commit/c24ae27)) 398 | - Rename dist-tag to 3.x ([3e8f1e0](https://github.com/unjs/consola/commit/3e8f1e0)) 399 | - Update readme ([85bbe3a](https://github.com/unjs/consola/commit/85bbe3a)) 400 | - Update badges ([cf7c6e5](https://github.com/unjs/consola/commit/cf7c6e5)) 401 | - Update badges ([566ff68](https://github.com/unjs/consola/commit/566ff68)) 402 | - **release:** V3.0.0-2 ([4a01304](https://github.com/unjs/consola/commit/4a01304)) 403 | - Update shared exports ([8fc0fdd](https://github.com/unjs/consola/commit/8fc0fdd)) 404 | - **release:** V3.0.0-3 ([6253fb0](https://github.com/unjs/consola/commit/6253fb0)) 405 | - Fix import in examples ([c4fff18](https://github.com/unjs/consola/commit/c4fff18)) 406 | - **release:** V3.0.0-4 ([474f82f](https://github.com/unjs/consola/commit/474f82f)) 407 | - **release:** V3.0.0-5 ([ad20f89](https://github.com/unjs/consola/commit/ad20f89)) 408 | - Add example for readme ([2bb5813](https://github.com/unjs/consola/commit/2bb5813)) 409 | - Update readme ([0568e61](https://github.com/unjs/consola/commit/0568e61)) 410 | - Update readme ([6a5fb0c](https://github.com/unjs/consola/commit/6a5fb0c)) 411 | - Lint changelog ([11ba5be](https://github.com/unjs/consola/commit/11ba5be)) 412 | - Update package.json ([f698f88](https://github.com/unjs/consola/commit/f698f88)) 413 | - Remove browser cjs ([a5db8db](https://github.com/unjs/consola/commit/a5db8db)) 414 | - Update release script to normal ([2634c71](https://github.com/unjs/consola/commit/2634c71)) 415 | 416 | ### ✅ Tests 417 | 418 | - Update test ([64fa81d](https://github.com/unjs/consola/commit/64fa81d)) 419 | 420 | ### 🎨 Styles 421 | 422 | - Prefer object spread instead of `Object.assign` ([c03268a](https://github.com/unjs/consola/commit/c03268a)) 423 | 424 | #### ⚠️ Breaking Changes 425 | 426 | - ⚠️ Rewrite consola with typescript ([4479d2f](https://github.com/unjs/consola/commit/4479d2f)) 427 | - ⚠️ Move log levels and types to constants ([514f5b3](https://github.com/unjs/consola/commit/514f5b3)) 428 | 429 | ### ❤️ Contributors 430 | 431 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 432 | - With-heart ([@with-heart](http://github.com/with-heart)) 433 | - Anthony Fu 434 | - Xin Du (Clark) 435 | - Sébastien Chopin 436 | - Thomas K ([@ThomasKoscheck](http://github.com/ThomasKoscheck)) 437 | 438 | ## v3.0.0-5 439 | 440 | [compare changes](https://github.com/unjs/consola/compare/v3.0.0-4...v3.0.0-5) 441 | 442 | ### 🩹 Fixes 443 | 444 | - **fancy:** Improve colors ([99c2a4f](https://github.com/unjs/consola/commit/99c2a4f)) 445 | 446 | ### 💅 Refactors 447 | 448 | - **fancy:** Better start color and icon ([5a01d53](https://github.com/unjs/consola/commit/5a01d53)) 449 | 450 | ### ❤️ Contributors 451 | 452 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 453 | 454 | ## v3.0.0-4 455 | 456 | [compare changes](https://github.com/unjs/consola/compare/v3.0.0-3...v3.0.0-4) 457 | 458 | ### 🚀 Enhancements 459 | 460 | - `consola.fail` log level ([#153](https://github.com/unjs/consola/pull/153)) 461 | - Pass `formatOptions` and other options to reporters ([d77286a](https://github.com/unjs/consola/commit/d77286a)) 462 | - Show stack trace with `consola.trace` ([#151](https://github.com/unjs/consola/pull/151)) 463 | 464 | ### 🩹 Fixes 465 | 466 | - Type consola instance with built-in type functions ([1a4b893](https://github.com/unjs/consola/commit/1a4b893)) 467 | - Default value for color format utils ([ec9be78](https://github.com/unjs/consola/commit/ec9be78)) 468 | - **fancy:** Show time and tag on right when width cannot be determined ([#128](https://github.com/unjs/consola/pull/128)) 469 | - Pass level from `CONSOLA_LEVEL` to the `defaults` ([#129](https://github.com/unjs/consola/pull/129)) 470 | - **consola:** Type defaults overrides generic defaults ([d3d3c05](https://github.com/unjs/consola/commit/d3d3c05)) 471 | 472 | ### 💅 Refactors 473 | 474 | - Drop `json` and `winston` reporters ([5af0e99](https://github.com/unjs/consola/commit/5af0e99)) 475 | - Move all options to `consola.options` without duplication ([2d31ef4](https://github.com/unjs/consola/commit/2d31ef4)) 476 | - Move spam logic into `_lastLog` object ([cabd04f](https://github.com/unjs/consola/commit/cabd04f)) 477 | - Remove global `async` option ([edd1bb9](https://github.com/unjs/consola/commit/edd1bb9)) 478 | - **types:** Merge `LogTypeLiteral` and `logtype` types to `LogType` ([da1bc73](https://github.com/unjs/consola/commit/da1bc73)) 479 | - ⚠️ Move log levels and types to constants ([514f5b3](https://github.com/unjs/consola/commit/514f5b3)) 480 | - Use `index.node.ts` for main build ([b92d23b](https://github.com/unjs/consola/commit/b92d23b)) 481 | - Improve types and exports ([b380d21](https://github.com/unjs/consola/commit/b380d21)) 482 | - Improve fancy reporter ([bc90db8](https://github.com/unjs/consola/commit/bc90db8)) 483 | - Revert back to `dist/index.*` for bw compatibility ([98e300f](https://github.com/unjs/consola/commit/98e300f)) 484 | 485 | ### 📖 Documentation 486 | 487 | - Fix links to the source files ([#172](https://github.com/unjs/consola/pull/172)) 488 | 489 | ### 🏡 Chore 490 | 491 | - Fix import in examples ([c4fff18](https://github.com/unjs/consola/commit/c4fff18)) 492 | 493 | ### ✅ Tests 494 | 495 | - Update test ([64fa81d](https://github.com/unjs/consola/commit/64fa81d)) 496 | 497 | ### 🎨 Styles 498 | 499 | - Prefer object spread instead of `Object.assign` ([c03268a](https://github.com/unjs/consola/commit/c03268a)) 500 | 501 | #### ⚠️ Breaking Changes 502 | 503 | - ⚠️ Move log levels and types to constants ([514f5b3](https://github.com/unjs/consola/commit/514f5b3)) 504 | 505 | ### ❤️ Contributors 506 | 507 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 508 | - With-heart ([@with-heart](http://github.com/with-heart)) 509 | 510 | ## v3.0.0-3 511 | 512 | [compare changes](https://github.com/unjs/consola/compare/v3.0.0-2...v3.0.0-3) 513 | 514 | ### 💅 Refactors 515 | 516 | - Remove `globalThis` caching ([4e7b909](https://github.com/unjs/consola/commit/4e7b909)) 517 | 518 | ### 📦 Build 519 | 520 | - Use backward compatible cjs wrapper for default export ([e2e6aa6](https://github.com/unjs/consola/commit/e2e6aa6)) 521 | 522 | ### 🏡 Chore 523 | 524 | - Update shared exports ([8fc0fdd](https://github.com/unjs/consola/commit/8fc0fdd)) 525 | 526 | ### ❤️ Contributors 527 | 528 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 529 | 530 | ## v3.0.0-2 531 | 532 | [compare changes](https://github.com/unjs/consola/compare/v3.0.0-1...v3.0.0-2) 533 | 534 | ### 🚀 Enhancements 535 | 536 | - `consola.prompt` util ([#170](https://github.com/unjs/consola/pull/170)) 537 | 538 | ### 🏡 Chore 539 | 540 | - Rename dist-tag to 3.x ([3e8f1e0](https://github.com/unjs/consola/commit/3e8f1e0)) 541 | - Update readme ([85bbe3a](https://github.com/unjs/consola/commit/85bbe3a)) 542 | - Update badges ([cf7c6e5](https://github.com/unjs/consola/commit/cf7c6e5)) 543 | - Update badges ([566ff68](https://github.com/unjs/consola/commit/566ff68)) 544 | 545 | ### ❤️ Contributors 546 | 547 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 548 | 549 | ## v3.0.0-1 550 | 551 | [compare changes](https://github.com/unjs/consola/compare/v2.15.3...v3.0.0-1) 552 | 553 | > 554 | 555 | ### 🚀 Enhancements 556 | 557 | - Default `logLevel` to 1 in test environments ([#134](https://github.com/unjs/consola/pull/134)) 558 | - Support literal for logLevels ([#133](https://github.com/unjs/consola/pull/133)) 559 | - Expose `createConsola` and named exports ([ef6e5e5](https://github.com/unjs/consola/commit/ef6e5e5)) 560 | 561 | ### 🔥 Performance 562 | 563 | - Switch from chalk to colorette ([271b4db](https://github.com/unjs/consola/commit/271b4db)) 564 | - Remove `dayjs` dependency ([d6a3776](https://github.com/unjs/consola/commit/d6a3776)) 565 | 566 | ### 💅 Refactors 567 | 568 | - ⚠️ Rewrite consola with typescript ([4479d2f](https://github.com/unjs/consola/commit/4479d2f)) 569 | - Rename `global` to `globalThis` ([bd03098](https://github.com/unjs/consola/commit/bd03098)) 570 | - **utils:** Rename `global` to `globalThis` ([8c3ef77](https://github.com/unjs/consola/commit/8c3ef77)) 571 | - Strict typechecks ([63bbd56](https://github.com/unjs/consola/commit/63bbd56)) 572 | 573 | ### 🏡 Chore 574 | 575 | - Make example/index.js working ([#110](https://github.com/unjs/consola/pull/110)) 576 | - Add LICENSE ([#121](https://github.com/unjs/consola/pull/121)) 577 | - **npm:** Update repository to unjs orgnization ([#125](https://github.com/unjs/consola/pull/125)) 578 | - Add prerelease script ([cfaba5e](https://github.com/unjs/consola/commit/cfaba5e)) 579 | - Hide rollup warn ([5c3b7f1](https://github.com/unjs/consola/commit/5c3b7f1)) 580 | - Ignore coverage ([da557ac](https://github.com/unjs/consola/commit/da557ac)) 581 | - Update examples ([e07e3ab](https://github.com/unjs/consola/commit/e07e3ab)) 582 | 583 | #### ⚠️ Breaking Changes 584 | 585 | - ⚠️ Rewrite consola with typescript ([4479d2f](https://github.com/unjs/consola/commit/4479d2f)) 586 | 587 | ### ❤️ Contributors 588 | 589 | - Pooya Parsa ([@pi0](http://github.com/pi0)) 590 | - Anthony Fu 591 | - Xin Du (Clark) 592 | - Sébastien Chopin 593 | - Thomas K ([@ThomasKoscheck](http://github.com/ThomasKoscheck)) 594 | 595 | ### [2.15.3](https://github.com/unjs/consola/compare/v2.15.2...v2.15.3) (2021-02-07) 596 | 597 | ### Bug Fixes 598 | 599 | - add `.raw` to mocked functions ([987dadc](https://github.com/unjs/consola/commit/987dadcc81a82698051ade2384ae2f0fc12d8aef)) 600 | 601 | ### [2.15.2](https://github.com/unjs/consola/compare/v2.15.1...v2.15.2) (2021-02-03) 602 | 603 | ### Bug Fixes 604 | 605 | - add isRaw flag only for wrapped calls ([23b1184](https://github.com/unjs/consola/commit/23b1184e2897f5d33943bec7180fb2427402d400)), closes [unjs/unjs.js#8752](https://github.com/unjs/unjs.js/issues/8752) 606 | 607 | ### [2.15.1](https://github.com/unjs/consola/compare/v2.15.0...v2.15.1) (2021-02-02) 608 | 609 | ### Bug Fixes 610 | 611 | - skip logObj check for wrapped calls (fixes [#109](https://github.com/unjs/consola/issues/109)) ([091a244](https://github.com/unjs/consola/commit/091a24423bb9c28b7371e7af849b15c7e39747fa)) 612 | 613 | ## [2.15.0](https://github.com/unjs/consola/compare/v2.14.0...v2.15.0) (2020-08-05) 614 | 615 | ### Features 616 | 617 | - **types:** use union type for `ConsolaLogObject.type` ([#100](https://github.com/unjs/consola/issues/100)) ([a6eba53](https://github.com/unjs/consola/commit/a6eba532381bcec9c84ac5600ac668aca87c8487)) 618 | - support `formatOptions.date` to optionally hide date ([#101](https://github.com/unjs/consola/issues/101)) ([6bf733f](https://github.com/unjs/consola/commit/6bf733f2b9a5320584bdd0de7de08f4341c74335)) 619 | 620 | ## [2.14.0](https://github.com/unjs/consola/compare/v2.13.0...v2.14.0) (2020-06-26) 621 | 622 | ### Features 623 | 624 | - improve spam throttle ([5314eee](https://github.com/unjs/consola/commit/5314eeebb4b564408a4ab14cb457bdbd426f6124)) 625 | 626 | ## [2.13.0](https://github.com/unjs/consola/compare/v2.12.2...v2.13.0) (2020-06-12) 627 | 628 | ### Features 629 | 630 | - remove level boundary check ([8972d47](https://github.com/unjs/consola/commit/8972d478c93690fafb909f49d9d0edbcb67bddae)) 631 | 632 | ### Bug Fixes 633 | 634 | - **types:** fix silent/verbose levels ([7ab0a65](https://github.com/unjs/consola/commit/7ab0a65f383d9dd1b68a18ee439bf19468a57885)) 635 | 636 | ### [2.12.2](https://github.com/unjs/consola/compare/v2.12.1...v2.12.2) (2020-05-26) 637 | 638 | ### Bug Fixes 639 | 640 | - silent log level does not work ([#98](https://github.com/unjs/consola/issues/98)) ([6a4a79c](https://github.com/unjs/consola/commit/6a4a79c24b8db902b078ad92a6ee7a33880ed26c)) 641 | 642 | ### [2.12.1](https://github.com/unjs/consola/compare/v2.12.0...v2.12.1) (2020-05-07) 643 | 644 | ### Bug Fixes 645 | 646 | - new LogLevel enum is not exported properly [#95](https://github.com/unjs/consola/issues/95) ([#96](https://github.com/unjs/consola/issues/96)) ([fafbec2](https://github.com/unjs/consola/commit/fafbec2b1bc75912eea5d0618a27b982738d6cda)) 647 | 648 | ## [2.12.0](https://github.com/unjs/consola/compare/v2.11.3...v2.12.0) (2020-05-07) 649 | 650 | ### Features 651 | 652 | - **types:** add missing typescript definitions for reporters ([#94](https://github.com/unjs/consola/issues/94)) ([4a08ef0](https://github.com/unjs/consola/commit/4a08ef02bc48ddc887f2b91713520eda50793a27)) 653 | 654 | ### [2.11.3](https://github.com/unjs/consola/compare/v2.11.2...v2.11.3) (2019-12-31) 655 | 656 | ### Bug Fixes 657 | 658 | - **typescript:** remove cjs export (fixes [#88](https://github.com/unjs/consola/issues/88)) ([0d9ab1b](https://github.com/unjs/consola/commit/0d9ab1bba8645853c721069c57527764ed708869)) 659 | 660 | ### [2.11.2](https://github.com/unjs/consola/compare/v2.11.1...v2.11.2) (2019-12-27) 661 | 662 | ### Bug Fixes 663 | 664 | - **types:** `const consola = require('consola')` type is wrong ([#80](https://github.com/unjs/consola/issues/80)) ([5c22d8c](https://github.com/unjs/consola/commit/5c22d8cd4624e3bbd7294b9eba09f131ed786332)) 665 | - throttle expiration ([#81](https://github.com/unjs/consola/issues/81)) ([940474d](https://github.com/unjs/consola/commit/940474d3b64a4969acdec04290734e700920c19f)), closes [#68](https://github.com/unjs/consola/issues/68) 666 | 667 | ### [2.11.1](https://github.com/unjs/consola/compare/v2.11.0...v2.11.1) (2019-12-17) 668 | 669 | ### Bug Fixes 670 | 671 | - **consola:** use `options.stderr` ([#77](https://github.com/unjs/consola/issues/77)) ([774c673](https://github.com/unjs/consola/commit/774c6739e794665bc5e2c40aa84921b7f2a26387)) 672 | 673 | ## [2.11.0](https://github.com/unjs/consola/compare/v2.10.0...v2.11.0) (2019-11-10) 674 | 675 | ### Features 676 | 677 | - **browser:** add support of formatted strings ([#66](https://github.com/unjs/consola/issues/66)) ([920f313](https://github.com/unjs/consola/commit/920f313dba322c34ccd1b2f08afba59122c3b8e7)) 678 | 679 | ### Bug Fixes 680 | 681 | - typecheck type and tag before normalize ([1984deb](https://github.com/unjs/consola/commit/1984deb0a5214a3aa82dab972ec76af20ba14d1b)) 682 | - **types:** reporter in remove methods are optional ([#70](https://github.com/unjs/consola/issues/70)) ([a17cdb1](https://github.com/unjs/consola/commit/a17cdb1a423e41076c58692130955d5a9f5e36ba)) 683 | 684 | ### [2.10.1](https://github.com/unjs/consola/compare/v2.10.0...v2.10.1) (2019-08-05) 685 | 686 | ## [2.10.0](https://github.com/unjs/consola/compare/v2.9.0...v2.10.0) (2019-08-05) 687 | 688 | ### Bug Fixes 689 | 690 | - add missing typescript declaration for level, stdout and stderr ([#58](https://github.com/unjs/consola/issues/58)) ([a149dbb](https://github.com/unjs/consola/commit/a149dbb)) 691 | 692 | ### Features 693 | 694 | - improve typescript type definitions ([#57](https://github.com/unjs/consola/issues/57)) ([80eefd8](https://github.com/unjs/consola/commit/80eefd8)) 695 | 696 | ## [2.9.0](https://github.com/unjs/consola/compare/v2.8.0...v2.9.0) (2019-06-18) 697 | 698 | ### Features 699 | 700 | - count spam log ([197a6b3](https://github.com/unjs/consola/commit/197a6b3)) 701 | 702 | ## [2.8.0](https://github.com/unjs/consola/compare/v2.7.1...v2.8.0) (2019-06-18) 703 | 704 | ### Features 705 | 706 | - spam preventation ([7da806b](https://github.com/unjs/consola/commit/7da806b)) 707 | 708 | ### [2.7.1](https://github.com/unjs/consola/compare/v2.7.0...v2.7.1) (2019-05-26) 709 | 710 | ### Bug Fixes 711 | 712 | - **browser:** hide `:` with tag and normal log ([8250d5a](https://github.com/unjs/consola/commit/8250d5a)) 713 | 714 | ## [2.7.0](https://github.com/unjs/consola/compare/v2.6.2...v2.7.0) (2019-05-26) 715 | 716 | ### Bug Fixes 717 | 718 | - correctly calculate line width when using grave accent ([bad52bd](https://github.com/unjs/consola/commit/bad52bd)) 719 | 720 | ### Features 721 | 722 | - always hide right side on width < 80 ([07d8246](https://github.com/unjs/consola/commit/07d8246)) 723 | - improve basic logs ([ea6ce59](https://github.com/unjs/consola/commit/ea6ce59)) 724 | - **browser:** fancier logs ([b64f337](https://github.com/unjs/consola/commit/b64f337)) 725 | - hide time from basic logger as it is commonly used in CI environments ([68c3bae](https://github.com/unjs/consola/commit/68c3bae)) 726 | - smart hide time and tag when there is no space ([00a375f](https://github.com/unjs/consola/commit/00a375f)) 727 | 728 | ### [2.6.2](https://github.com/unjs/consola/compare/v2.6.1...v2.6.2) (2019-05-15) 729 | 730 | ### Bug Fixes 731 | 732 | - transpile browser dist to ES5 ([1f81eea](https://github.com/unjs/consola/commit/1f81eea)), closes [unjs/unjs.js#5743](https://github.com/unjs/consola/issues/5743) 733 | 734 | ### [2.6.1](https://github.com/unjs/consola/compare/v2.6.0...v2.6.1) (2019-05-08) 735 | 736 | ### Bug Fixes 737 | 738 | - **browser:** use `console.warn` when possible ([#49](https://github.com/unjs/consola/issues/49)) ([e386ede](https://github.com/unjs/consola/commit/e386ede)) 739 | 740 | # [2.6.0](https://github.com/unjs/consola/compare/v2.5.8...v2.6.0) (2019-04-12) 741 | 742 | ### Features 743 | 744 | - expose constructor and reporters ([3a8f662](https://github.com/unjs/consola/commit/3a8f662)) 745 | 746 | ## [2.5.8](https://github.com/unjs/consola/compare/v2.5.7...v2.5.8) (2019-03-29) 747 | 748 | ### Bug Fixes 749 | 750 | - **types:** allow passing extra arguments ([#46](https://github.com/unjs/consola/issues/46)) ([d29fc46](https://github.com/unjs/consola/commit/d29fc46)) 751 | 752 | ## [2.5.7](https://github.com/unjs/consola/compare/v2.5.6...v2.5.7) (2019-03-19) 753 | 754 | ### Bug Fixes 755 | 756 | - **formatting:** fix formatting when multiple back-quotes ([#44](https://github.com/unjs/consola/issues/44)) ([669a12e](https://github.com/unjs/consola/commit/669a12e)) 757 | 758 | ## [2.5.6](https://github.com/unjs/consola/compare/v2.5.5...v2.5.6) (2019-02-25) 759 | 760 | ### Bug Fixes 761 | 762 | - **ts:** revert export consola ts declarations ([#43](https://github.com/unjs/consola/issues/43)) ([6bd4f85](https://github.com/unjs/consola/commit/6bd4f85)) 763 | 764 | 765 | 766 | ## [2.4.1](https://github.com/unjs/consola/compare/v2.4.0...v2.4.1) (2019-02-12) 767 | 768 | ### Bug Fixes 769 | 770 | - **ts:** set type "any" ([#40](https://github.com/unjs/consola/issues/40)) ([ea9d551](https://github.com/unjs/consola/commit/ea9d551)) 771 | 772 | 773 | 774 | # [2.4.0](https://github.com/unjs/consola/compare/v2.3.2...v2.4.0) (2019-02-05) 775 | 776 | ### Bug Fixes 777 | 778 | - **esm:** fix esm compatibility ([8ddecc3](https://github.com/unjs/consola/commit/8ddecc3)) 779 | - **consola:** return `this` in setReporters ([544a887](https://github.com/unjs/consola/commit/544a887)) 780 | - **types:** set message type to "any" ([#39](https://github.com/unjs/consola/issues/39)) ([ff97b09](https://github.com/unjs/consola/commit/ff97b09)), closes [#38](https://github.com/unjs/consola/issues/38) 781 | 782 | ### Features 783 | 784 | - **types:** update types ([d0d7455](https://github.com/unjs/consola/commit/d0d7455)) 785 | 786 | 787 | 788 | ## [2.3.2](https://github.com/unjs/consola/compare/v2.3.1...v2.3.2) (2019-01-06) 789 | 790 | ### Bug Fixes 791 | 792 | - **types:** add some of the missing types ([#35](https://github.com/unjs/consola/issues/35)) ([5e3e69b](https://github.com/unjs/consola/commit/5e3e69b)) 793 | - ignore winston dep in webpack ([#37](https://github.com/unjs/consola/issues/37)) ([e534a28](https://github.com/unjs/consola/commit/e534a28)) 794 | 795 | 796 | 797 | ## [2.3.1](https://github.com/unjs/consola/compare/v2.3.0...v2.3.1) (2019-01-02) 798 | 799 | ### Bug Fixes 800 | 801 | - bypass webpack for lazy required version of winston ([500b509](https://github.com/unjs/consola/commit/500b509)) 802 | 803 | 804 | 805 | # [2.3.0](https://github.com/unjs/consola/compare/v2.2.6...v2.3.0) (2018-11-19) 806 | 807 | ### Bug Fixes 808 | 809 | - **isLogObj:** handle non-standard error objects ([8748c81](https://github.com/unjs/consola/commit/8748c81)) 810 | 811 | ### Features 812 | 813 | - browser reporter improvements ([591d0b4](https://github.com/unjs/consola/commit/591d0b4)), closes [#31](https://github.com/unjs/consola/issues/31) 814 | - **fancy:** look like jest traces ([ecae238](https://github.com/unjs/consola/commit/ecae238)) 815 | 816 | 817 | 818 | ## [2.2.6](https://github.com/unjs/consola/compare/v2.2.5...v2.2.6) (2018-11-14) 819 | 820 | ### Bug Fixes 821 | 822 | - **json-reporter:** add a default value to the constructor ([#33](https://github.com/unjs/consola/issues/33)) ([c59db36](https://github.com/unjs/consola/commit/c59db36)) 823 | 824 | 825 | 826 | ## [2.2.5](https://github.com/unjs/consola/compare/v2.2.4...v2.2.5) (2018-11-14) 827 | 828 | ### Bug Fixes 829 | 830 | - expose typescript typings ([f0398ed](https://github.com/unjs/consola/commit/f0398ed)) 831 | 832 | 833 | 834 | ## [2.2.4](https://github.com/unjs/consola/compare/v2.2.3...v2.2.4) (2018-11-08) 835 | 836 | ### Bug Fixes 837 | 838 | - use basic reporter only for ci and test environments ([33220e4](https://github.com/unjs/consola/commit/33220e4)) 839 | 840 | 841 | 842 | ## [2.2.3](https://github.com/unjs/consola/compare/v2.2.2...v2.2.3) (2018-11-07) 843 | 844 | ### Bug Fixes 845 | 846 | - **fancy:** honor logObj.icon ([d56fa38](https://github.com/unjs/consola/commit/d56fa38)) 847 | 848 | 849 | 850 | ## [2.2.2](https://github.com/unjs/consola/compare/v2.2.1...v2.2.2) (2018-11-04) 851 | 852 | ### Bug Fixes 853 | 854 | - update std-env to 2.1.1 ([32a9c67](https://github.com/unjs/consola/commit/32a9c67)) 855 | 856 | 857 | 858 | ## [2.2.1](https://github.com/unjs/consola/compare/v2.2.0...v2.2.1) (2018-11-04) 859 | 860 | ### Bug Fixes 861 | 862 | - remove file:// from error stack traces ([ff24b69](https://github.com/unjs/consola/commit/ff24b69)) 863 | 864 | 865 | 866 | # [2.2.0](https://github.com/unjs/consola/compare/v2.1.1...v2.2.0) (2018-11-04) 867 | 868 | ### Bug Fixes 869 | 870 | - correctly handle falsy values ([367fb19](https://github.com/unjs/consola/commit/367fb19)) 871 | 872 | ### Features 873 | 874 | - support formatOptions. resolves [#29](https://github.com/unjs/consola/issues/29). ([7ed640f](https://github.com/unjs/consola/commit/7ed640f)) 875 | 876 | 877 | 878 | ## [2.1.1](https://github.com/unjs/consola/compare/v2.1.0...v2.1.1) (2018-11-03) 879 | 880 | ### Bug Fixes 881 | 882 | - add legacy ready and start levels for more backward compatibility ([f54b5c2](https://github.com/unjs/consola/commit/f54b5c2)) 883 | 884 | 885 | 886 | # [2.1.0](https://github.com/unjs/consola/compare/v2.0.9...v2.1.0) (2018-11-03) 887 | 888 | ### Features 889 | 890 | - add aliases ([cbea7bd](https://github.com/unjs/consola/commit/cbea7bd)) 891 | - mockTypes for easy mocking ([a332890](https://github.com/unjs/consola/commit/a332890)) 892 | 893 | 894 | 895 | ## [2.0.9](https://github.com/unjs/consola/compare/v2.0.8...v2.0.9) (2018-11-03) 896 | 897 | 898 | 899 | ## [2.0.8](https://github.com/unjs/consola/compare/v2.0.7...v2.0.8) (2018-11-03) 900 | 901 | 902 | 903 | ## [2.0.7](https://github.com/unjs/consola/compare/v2.0.6...v2.0.7) (2018-11-02) 904 | 905 | ### Bug Fixes 906 | 907 | - always use computed values for stdout/stderr ([f91abc0](https://github.com/unjs/consola/commit/f91abc0)) 908 | 909 | 910 | 911 | ## [2.0.6](https://github.com/unjs/consola/compare/v2.0.5...v2.0.6) (2018-11-02) 912 | 913 | 914 | 915 | ## [2.0.5](https://github.com/unjs/consola/compare/v2.0.4...v2.0.5) (2018-11-02) 916 | 917 | 918 | 919 | ## [2.0.4](https://github.com/unjs/consola/compare/v2.0.3...v2.0.4) (2018-11-02) 920 | 921 | ### Bug Fixes 922 | 923 | - **fancy:** remove extra icons ([b66fde0](https://github.com/unjs/consola/commit/b66fde0)) 924 | 925 | 926 | 927 | ## [2.0.3](https://github.com/unjs/consola/compare/v2.0.2...v2.0.3) (2018-11-02) 928 | 929 | ### Bug Fixes 930 | 931 | - **pkg:** exclude src from package ([4b1fb7d](https://github.com/unjs/consola/commit/4b1fb7d)) 932 | - use live console.\_stdout bindings for default stream ([d9573c3](https://github.com/unjs/consola/commit/d9573c3)) 933 | 934 | 935 | 936 | ## [2.0.2](https://github.com/unjs/consola/compare/v2.0.1...v2.0.2) (2018-11-02) 937 | 938 | ### Bug Fixes 939 | 940 | - **error:** always strip first line from stack ([3afa9aa](https://github.com/unjs/consola/commit/3afa9aa)) 941 | 942 | 943 | 944 | ## [2.0.1](https://github.com/unjs/consola/compare/v2.0.0...v2.0.1) (2018-11-02) 945 | 946 | ### Bug Fixes 947 | 948 | - **fancy:** use proper color for log paths ([7c75283](https://github.com/unjs/consola/commit/7c75283)) 949 | 950 | 951 | 952 | # [2.0.0](https://github.com/unjs/consola/compare/v2.0.0-2...v2.0.0) (2018-11-02) 953 | 954 | 955 | 956 | # [2.0.0-2](https://github.com/unjs/consola/compare/v2.0.0-1...v2.0.0-2) (2018-11-02) 957 | 958 | ### Bug Fixes 959 | 960 | - add methods for legacy support ([4bdd034](https://github.com/unjs/consola/commit/4bdd034)) 961 | - preserve additional new lines ([340a001](https://github.com/unjs/consola/commit/340a001)) 962 | - update std-env to 2.1.0 ([2dc2a50](https://github.com/unjs/consola/commit/2dc2a50)) 963 | 964 | ### Features 965 | 966 | - support badge with fancy ([38600fe](https://github.com/unjs/consola/commit/38600fe)) 967 | 968 | 969 | 970 | # [2.0.0-1](https://github.com/unjs/consola/compare/v2.0.0-0...v2.0.0-1) (2018-10-31) 971 | 972 | 973 | 974 | # [2.0.0-0](https://github.com/unjs/consola/compare/v1.4.4...v2.0.0-0) (2018-10-31) 975 | 976 | ### Bug Fixes 977 | 978 | - add schmance.js ([2929648](https://github.com/unjs/consola/commit/2929648)) 979 | - **docs:** update readme ([#22](https://github.com/unjs/consola/issues/22)) ([e75f2a0](https://github.com/unjs/consola/commit/e75f2a0)) 980 | - add default/undefined color for browser ([39584d2](https://github.com/unjs/consola/commit/39584d2)) 981 | - add missing parseStack import ([da53dee](https://github.com/unjs/consola/commit/da53dee)) 982 | - also copy symbols in assignGlobalReference ([b0eefb5](https://github.com/unjs/consola/commit/b0eefb5)) 983 | - don't return this when calling log functions ([f07e056](https://github.com/unjs/consola/commit/f07e056)) 984 | - fix badge display ([e036eed](https://github.com/unjs/consola/commit/e036eed)) 985 | - fix main field ([4b56e48](https://github.com/unjs/consola/commit/4b56e48)) 986 | - fix typos ([45e2f99](https://github.com/unjs/consola/commit/45e2f99)) 987 | - handle null value of obj for assignToLogObj ([d2402af](https://github.com/unjs/consola/commit/d2402af)) 988 | - improve browser packaging ([4d8c8d0](https://github.com/unjs/consola/commit/4d8c8d0)) 989 | - lint ([f909761](https://github.com/unjs/consola/commit/f909761)) 990 | - lint ([d976620](https://github.com/unjs/consola/commit/d976620)) 991 | - only one color ending parameter is enough ([d213634](https://github.com/unjs/consola/commit/d213634)) 992 | - readme: icon string length is digit ([31f1894](https://github.com/unjs/consola/commit/31f1894)) 993 | - remove name assignment ([8d59075](https://github.com/unjs/consola/commit/8d59075)) 994 | - remove pushes for better readability ([418d84a](https://github.com/unjs/consola/commit/418d84a)) 995 | - rename private fields ([244fe5c](https://github.com/unjs/consola/commit/244fe5c)) 996 | - rename require test file ([cfc8f9e](https://github.com/unjs/consola/commit/cfc8f9e)) 997 | - return earlier on not displaying levels ([cfdcf04](https://github.com/unjs/consola/commit/cfdcf04)) 998 | - support Error as logObject ([134ff54](https://github.com/unjs/consola/commit/134ff54)) 999 | - text color comment ([9336fbc](https://github.com/unjs/consola/commit/9336fbc)) 1000 | - update demo ([3842e0e](https://github.com/unjs/consola/commit/3842e0e)) 1001 | - use symbols for private property access ([8e6343c](https://github.com/unjs/consola/commit/8e6343c)) 1002 | 1003 | ### Code Refactoring 1004 | 1005 | - additionalStyle ~> additionalColor ([3f808e9](https://github.com/unjs/consola/commit/3f808e9)) 1006 | 1007 | ### Features 1008 | 1009 | - add **VERSION** to consola prototype ([982c8ca](https://github.com/unjs/consola/commit/982c8ca)) 1010 | - add assignGlobalConsola helper ([1af28f7](https://github.com/unjs/consola/commit/1af28f7)) 1011 | - add getter/setter for level ([7af5ed5](https://github.com/unjs/consola/commit/7af5ed5)) 1012 | - add global.consola ([4da784d](https://github.com/unjs/consola/commit/4da784d)) 1013 | - add shmancy reporter ([dc6121a](https://github.com/unjs/consola/commit/dc6121a)) 1014 | - add symbols to browser ([30cd4f0](https://github.com/unjs/consola/commit/30cd4f0)) 1015 | - add sync/async write ([8525525](https://github.com/unjs/consola/commit/8525525)) 1016 | - add typescript typings ([#24](https://github.com/unjs/consola/issues/24)) ([0853a6f](https://github.com/unjs/consola/commit/0853a6f)) 1017 | - align basic and fancy reporter tags ([38a4729](https://github.com/unjs/consola/commit/38a4729)) 1018 | - better stack formater ([f5acb3c](https://github.com/unjs/consola/commit/f5acb3c)) 1019 | - detect version changes and throw a warning ([73bdd1a](https://github.com/unjs/consola/commit/73bdd1a)) 1020 | - improve packaging and exports ([90da862](https://github.com/unjs/consola/commit/90da862)) 1021 | - improve packaging for browser support ([47af1df](https://github.com/unjs/consola/commit/47af1df)) 1022 | - initial works for v2.0.0 ([455b6f9](https://github.com/unjs/consola/commit/455b6f9)) 1023 | - log formatting using printf ([2afb025](https://github.com/unjs/consola/commit/2afb025)) 1024 | - no more side effects ([c015c31](https://github.com/unjs/consola/commit/c015c31)) 1025 | - pause/resume ([f217cc1](https://github.com/unjs/consola/commit/f217cc1)) 1026 | - return new consola instance with consola.create ([4ae3614](https://github.com/unjs/consola/commit/4ae3614)) 1027 | - rework \_createLogFn with better argument handling ([2d4af39](https://github.com/unjs/consola/commit/2d4af39)) 1028 | - scope inheritance support ([#23](https://github.com/unjs/consola/issues/23)) ([0070c54](https://github.com/unjs/consola/commit/0070c54)) 1029 | - **fancy/basic:** support logObj.stack field ([aa2216f](https://github.com/unjs/consola/commit/aa2216f)) 1030 | - setReporters, withDefaults and withTag ([912446f](https://github.com/unjs/consola/commit/912446f)) 1031 | - showType option ([ed294e4](https://github.com/unjs/consola/commit/ed294e4)) 1032 | - style browser reporter ([d39684d](https://github.com/unjs/consola/commit/d39684d)) 1033 | - support all chalk colors ([2cec678](https://github.com/unjs/consola/commit/2cec678)), closes [#20](https://github.com/unjs/consola/issues/20) 1034 | - wrapConsole ([3962a1f](https://github.com/unjs/consola/commit/3962a1f)) 1035 | - wrapStd ([f8bfbeb](https://github.com/unjs/consola/commit/f8bfbeb)) 1036 | - write error and warns to process.stderr by default ([6565254](https://github.com/unjs/consola/commit/6565254)) 1037 | 1038 | ### Performance Improvements 1039 | 1040 | - **basic:** refactor getWriteMethod ([c52db69](https://github.com/unjs/consola/commit/c52db69)) 1041 | - remove all DEPRECATED helpers for less bundle size ([fe39d37](https://github.com/unjs/consola/commit/fe39d37)) 1042 | 1043 | ### BREAKING CHANGES 1044 | 1045 | - Use new additionalColor prop 1046 | - lot's of internals had been changed. 1047 | - Behavior may be changed in some conditions 1048 | 1049 | 1050 | 1051 | ## [1.4.4](https://github.com/unjs/consola/compare/v1.4.3...v1.4.4) (2018-10-13) 1052 | 1053 | ### Bug Fixes 1054 | 1055 | - add global.consola ([558cae5](https://github.com/unjs/consola/commit/558cae5)) 1056 | 1057 | 1058 | 1059 | ## [1.4.3](https://github.com/unjs/consola/compare/v1.4.2...v1.4.3) (2018-08-18) 1060 | 1061 | ### Bug Fixes 1062 | 1063 | - use more compatible string to clear the console ([82ce410](https://github.com/unjs/consola/commit/82ce410)) 1064 | 1065 | 1066 | 1067 | ## [1.4.2](https://github.com/unjs/consola/compare/v1.4.1...v1.4.2) (2018-08-12) 1068 | 1069 | ### Bug Fixes 1070 | 1071 | - cannot set level as 0 in options ([4c1ecce](https://github.com/unjs/consola/commit/4c1ecce)) 1072 | 1073 | 1074 | 1075 | ## [1.4.1](https://github.com/unjs/consola/compare/v1.4.0...v1.4.1) (2018-05-27) 1076 | 1077 | ### Bug Fixes 1078 | 1079 | - **fancy:** logObj.type ([418be28](https://github.com/unjs/consola/commit/418be28)) 1080 | 1081 | 1082 | 1083 | # [1.4.0](https://github.com/unjs/consola/compare/v1.3.0...v1.4.0) (2018-05-27) 1084 | 1085 | ### Features 1086 | 1087 | - support custom additional style ([#18](https://github.com/unjs/consola/issues/18)) ([7a750bf](https://github.com/unjs/consola/commit/7a750bf)) 1088 | - **fancy:** support icon field ([0123bed](https://github.com/unjs/consola/commit/0123bed)) 1089 | 1090 | 1091 | 1092 | # [1.3.0](https://github.com/unjs/consola/compare/v1.2.0...v1.3.0) (2018-04-15) 1093 | 1094 | ### Bug Fixes 1095 | 1096 | - **reporters/fancy:** extra space for additional ([efeab44](https://github.com/unjs/consola/commit/efeab44)) 1097 | - prevent duplicate consola instances when different versions used by packages ([0bce262](https://github.com/unjs/consola/commit/0bce262)) 1098 | 1099 | ### Features 1100 | 1101 | - support extra log arguments ([8b6d3d2](https://github.com/unjs/consola/commit/8b6d3d2)) 1102 | 1103 | 1104 | 1105 | # [1.2.0](https://github.com/unjs/consola/compare/v1.1.4...v1.2.0) (2018-04-02) 1106 | 1107 | ### Features 1108 | 1109 | - **basic:** support additional field ([b50cad8](https://github.com/unjs/consola/commit/b50cad8)) 1110 | - improve packaging ([158e8ef](https://github.com/unjs/consola/commit/158e8ef)) 1111 | 1112 | ### Performance Improvements 1113 | 1114 | - require needed lodash methods only ([91065e4](https://github.com/unjs/consola/commit/91065e4)) 1115 | 1116 | 1117 | 1118 | ## [1.1.4](https://github.com/unjs/consola/compare/v1.1.3...v1.1.4) (2018-03-31) 1119 | 1120 | ### Bug Fixes 1121 | 1122 | - **package:** add chalk to dependencies ([3f738e9](https://github.com/unjs/consola/commit/3f738e9)) 1123 | 1124 | 1125 | 1126 | ## [1.1.3](https://github.com/unjs/consola/compare/v1.1.2...v1.1.3) (2018-03-31) 1127 | 1128 | ### Bug Fixes 1129 | 1130 | - only include dist and src in package ([8b477ec](https://github.com/unjs/consola/commit/8b477ec)) 1131 | 1132 | 1133 | 1134 | ## [1.1.2](https://github.com/unjs/consola/compare/v1.1.1...v1.1.2) (2018-03-31) 1135 | 1136 | ### Bug Fixes 1137 | 1138 | - handle null and undefined calls ([1f98bb1](https://github.com/unjs/consola/commit/1f98bb1)) 1139 | 1140 | 1141 | 1142 | ## [1.1.1](https://github.com/unjs/consola/compare/v1.1.0...v1.1.1) (2018-03-31) 1143 | 1144 | ### Bug Fixes 1145 | 1146 | - add prepublish script ([8dd8700](https://github.com/unjs/consola/commit/8dd8700)) 1147 | 1148 | 1149 | 1150 | # [1.1.0](https://github.com/unjs/consola/compare/v1.0.0...v1.1.0) (2018-03-31) 1151 | 1152 | ### Features 1153 | 1154 | - rewrite FancyReporter without ora ([73c1ddc](https://github.com/unjs/consola/commit/73c1ddc)) 1155 | 1156 | 1157 | 1158 | # [1.0.0](https://github.com/unjs/consola/compare/v0.1.0...v1.0.0) (2018-03-31) 1159 | 1160 | 1161 | 1162 | # 0.1.0 (2018-03-31) 1163 | 1164 | ### Features 1165 | 1166 | - add log type for console compability ([96a8162](https://github.com/unjs/consola/commit/96a8162)) 1167 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Pooya Parsa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | --- 24 | 25 | Prompt support is based on https://github.com/bombshell-dev/clack 26 | 27 | MIT License 28 | 29 | Copyright (c) Nate Moore 30 | 31 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 32 | 33 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 34 | 35 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 36 | 37 | --- 38 | 39 | Color support is based on https://github.com/jorgebucaran/colorette 40 | 41 | Copyright © Jorge Bucaran 42 | 43 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 44 | 45 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 46 | 47 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🐨 Consola 2 | 3 | > Elegant Console Wrapper 4 | 5 | [![npm version][npm-version-src]][npm-version-href] 6 | [![npm downloads][npm-downloads-src]][npm-downloads-href] 7 | [![bundle][bundle-src]][bundle-href] 8 | 9 | 10 | 11 | ## Why Consola? 12 | 13 | 👌  Easy to use
14 | 💅  Fancy output with fallback for minimal environments
15 | 🔌  Pluggable reporters
16 | 💻  Consistent command line interface (CLI) experience
17 | 🏷  Tag support
18 | 🚏  Redirect `console` and `stdout/stderr` to consola and easily restore redirect.
19 | 🌐  Browser support
20 | ⏯  Pause/Resume support
21 | 👻  Mocking support
22 | 👮‍♂️  Spam prevention by throttling logs
23 | ❯  Interactive prompt support powered by [`clack`](https://github.com/natemoo-re/clack)
24 | 25 | ## Installation 26 | 27 | Using npm: 28 | 29 | ```bash 30 | npm i consola 31 | ``` 32 | 33 | Using yarn: 34 | 35 | ```bash 36 | yarn add consola 37 | ``` 38 | 39 | Using pnpm: 40 | 41 | ```bash 42 | pnpm i consola 43 | ``` 44 | 45 | ## Getting Started 46 | 47 | ```js 48 | // ESM 49 | import { consola, createConsola } from "consola"; 50 | 51 | // CommonJS 52 | const { consola, createConsola } = require("consola"); 53 | 54 | consola.info("Using consola 3.0.0"); 55 | consola.start("Building project..."); 56 | consola.warn("A new version of consola is available: 3.0.1"); 57 | consola.success("Project built!"); 58 | consola.error(new Error("This is an example error. Everything is fine!")); 59 | consola.box("I am a simple box"); 60 | await consola.prompt("Deploy to the production?", { 61 | type: "confirm", 62 | }); 63 | ``` 64 | 65 | Will display in the terminal: 66 | 67 | ![consola-screenshot](https://github.com/unjs/consola/assets/904724/0e511ee6-2543-43ab-9eda-152f07134d94) 68 | 69 | You can use smaller core builds without fancy reporter to save 80% of the bundle size: 70 | 71 | ```ts 72 | import { consola, createConsola } from "consola/basic"; 73 | import { consola, createConsola } from "consola/browser"; 74 | import { createConsola } from "consola/core"; 75 | ``` 76 | 77 | ## Consola Methods 78 | 79 | #### `(logObject)` `(args...)` 80 | 81 | Log to all reporters. 82 | 83 | Example: `consola.info('Message')` 84 | 85 | #### `await prompt(message, { type, cancel })` 86 | 87 | Show an input prompt. Type can either of `text`, `confirm`, `select` or `multiselect`. 88 | 89 | If prompt is canceled by user (with Ctrol+C), default value will be resolved by default. This strategy can be configured by setting `{ cancel: "..." }` option: 90 | 91 | - `"default"` - Resolve the promise with the `default` value or `initial` value. 92 | - `"undefined`" - Resolve the promise with `undefined`. 93 | - `"null"` - Resolve the promise with `null`. 94 | - `"symbol"` - Resolve the promise with a symbol `Symbol.for("cancel")`. 95 | - `"reject"` - Reject the promise with an error. 96 | 97 | See [examples/prompt.ts](./examples/prompt.ts) for usage examples. 98 | 99 | #### `addReporter(reporter)` 100 | 101 | - Aliases: `add` 102 | 103 | Register a custom reporter instance. 104 | 105 | #### `removeReporter(reporter?)` 106 | 107 | - Aliases: `remove`, `clear` 108 | 109 | Remove a registered reporter. 110 | 111 | If no arguments are passed all reporters will be removed. 112 | 113 | #### `setReporters(reporter|reporter[])` 114 | 115 | Replace all reporters. 116 | 117 | #### `create(options)` 118 | 119 | Create a new `Consola` instance and inherit all parent options for defaults. 120 | 121 | #### `withDefaults(defaults)` 122 | 123 | Create a new `Consola` instance with provided defaults 124 | 125 | #### `withTag(tag)` 126 | 127 | - Aliases: `withScope` 128 | 129 | Create a new `Consola` instance with that tag. 130 | 131 | #### `wrapConsole()` `restoreConsole()` 132 | 133 | Globally redirect all `console.log`, etc calls to consola handlers. 134 | 135 | #### `wrapStd()` `restoreStd()` 136 | 137 | Globally redirect all stdout/stderr outputs to consola. 138 | 139 | #### `wrapAll()` `restoreAll()` 140 | 141 | Wrap both, std and console. 142 | 143 | console uses std in the underlying so calling `wrapStd` redirects console too. 144 | Benefit of this function is that things like `console.info` will be correctly redirected to the corresponding type. 145 | 146 | #### `pauseLogs()` `resumeLogs()` 147 | 148 | - Aliases: `pause`/`resume` 149 | 150 | **Globally** pause and resume logs. 151 | 152 | Consola will enqueue all logs when paused and then sends them to the reported when resumed. 153 | 154 | #### `mockTypes` 155 | 156 | - Aliases: `mock` 157 | 158 | Mock all types. Useful for using with tests. 159 | 160 | The first argument passed to `mockTypes` should be a callback function accepting `(typeName, type)` and returning the mocked value: 161 | 162 | ```js 163 | // Jest 164 | consola.mockTypes((typeName, type) => jest.fn()); 165 | // Vitest 166 | consola.mockTypes((typeName, type) => vi.fn()); 167 | ``` 168 | 169 | Please note that with the example above, everything is mocked independently for each type. If you need one mocked fn create it outside: 170 | 171 | ```js 172 | // Jest 173 | const fn = jest.fn(); 174 | // Vitest 175 | const fn = vi.fn(); 176 | consola.mockTypes(() => fn); 177 | ``` 178 | 179 | If callback function returns a _falsy_ value, that type won't be mocked. 180 | 181 | For example if you just need to mock `consola.fatal`: 182 | 183 | ```js 184 | // Jest 185 | consola.mockTypes((typeName) => typeName === "fatal" && jest.fn()); 186 | // Vitest 187 | consola.mockTypes((typeName) => typeName === "fatal" && vi.fn()); 188 | ``` 189 | 190 | **NOTE:** Any instance of consola that inherits the mocked instance, will apply provided callback again. 191 | This way, mocking works for `withTag` scoped loggers without need to extra efforts. 192 | 193 | ## Custom Reporters 194 | 195 | Consola ships with 3 built-in reporters out of the box. A fancy colored reporter by default and fallsback to a basic reporter if running in a testing or CI environment detected using [unjs/std-env](https://github.com/unjs/std-env) and a basic browser reporter. 196 | 197 | You can create a new reporter object that implements `{ log(logObject): () => { } }` interface. 198 | 199 | **Example:** Simple JSON reporter 200 | 201 | ```ts 202 | import { createConsola } from "consola"; 203 | 204 | const consola = createConsola({ 205 | reporters: [ 206 | { 207 | log: (logObj) => { 208 | console.log(JSON.stringify(logObj)); 209 | }, 210 | }, 211 | ], 212 | }); 213 | 214 | // Prints {"date":"2023-04-18T12:43:38.693Z","args":["foo bar"],"type":"log","level":2,"tag":""} 215 | consola.log("foo bar"); 216 | ``` 217 | 218 | **Example:** Exit on fatal errors 219 | 220 | ```ts 221 | import { consola } from 'consola'; 222 | 223 | consola.addReporter({ 224 | log(logObj) { 225 | if(logObj.type === 'fatal') { 226 | process.exit(1) 227 | } 228 | } 229 | }) 230 | 231 | // Will exit on this line. 232 | consola.fatal("fatal error"); 233 | ``` 234 | 235 | ## Log Level 236 | 237 | Consola only shows logs with configured log level or below. (Default is `3`) 238 | 239 | Available log levels: 240 | 241 | - `0`: Fatal and Error 242 | - `1`: Warnings 243 | - `2`: Normal logs 244 | - `3`: Informational logs, success, fail, ready, start, ... 245 | - `4`: Debug logs 246 | - `5`: Trace logs 247 | - `-999`: Silent 248 | - `+999`: Verbose logs 249 | 250 | You can set the log level by either: 251 | 252 | - Passing `level` option to `createConsola` 253 | - Setting `consola.level` on instance 254 | - Using the `CONSOLA_LEVEL` environment variable (not supported for browser and core builds). 255 | 256 | ## Log Types 257 | 258 | Log types are exposed as `consola.[type](...)` and each is a preset of styles and log level. 259 | 260 | A list of all available built-in types is [available here](./src/constants.ts). 261 | 262 | ## Creating a new instance 263 | 264 | Consola has a global instance and is recommended to use everywhere. 265 | In case more control is needed, create a new instance. 266 | 267 | ```js 268 | import { createConsola } from "consola"; 269 | 270 | const logger = createConsola({ 271 | // level: 4, 272 | // fancy: true | false 273 | // formatOptions: { 274 | // columns: 80, 275 | // colors: false, 276 | // compact: false, 277 | // date: false, 278 | // }, 279 | }); 280 | ``` 281 | 282 | ## Integrations 283 | 284 | ### With jest or vitest 285 | 286 | ```js 287 | describe("your-consola-mock-test", () => { 288 | beforeAll(() => { 289 | // Redirect std and console to consola too 290 | // Calling this once is sufficient 291 | consola.wrapAll(); 292 | }); 293 | 294 | beforeEach(() => { 295 | // Re-mock consola before each test call to remove 296 | // calls from before 297 | // Jest 298 | consola.mockTypes(() => jest.fn()); 299 | // Vitest 300 | consola.mockTypes(() => vi.fn()); 301 | }); 302 | 303 | test("your test", async () => { 304 | // Some code here 305 | 306 | // Let's retrieve all messages of `consola.log` 307 | // Get the mock and map all calls to their first argument 308 | const consolaMessages = consola.log.mock.calls.map((c) => c[0]); 309 | expect(consolaMessages).toContain("your message"); 310 | }); 311 | }); 312 | ``` 313 | 314 | ### With jsdom 315 | 316 | ```js 317 | { 318 | new jsdom.VirtualConsole().sendTo(consola); 319 | } 320 | ``` 321 | 322 | ## Console Utils 323 | 324 | ```ts 325 | // ESM 326 | import { 327 | stripAnsi, 328 | centerAlign, 329 | rightAlign, 330 | leftAlign, 331 | align, 332 | box, 333 | colors, 334 | getColor, 335 | colorize, 336 | } from "consola/utils"; 337 | 338 | // CommonJS 339 | const { stripAnsi } = require("consola/utils"); 340 | ``` 341 | 342 | ## Raw logging methods 343 | 344 | Objects sent to the reporter could lead to unexpected output when object is close to internal object structure containing either `message` or `args` props. To enforce the object to be interpreted as pure object, you can use the `raw` method chained to any log type. 345 | 346 | **Example:** 347 | 348 | ```js 349 | // Prints "hello" 350 | consola.log({ message: "hello" }); 351 | 352 | // Prints "{ message: 'hello' }" 353 | consola.log.raw({ message: "hello" }); 354 | ``` 355 | 356 | ## License 357 | 358 | MIT 359 | 360 | 361 | 362 | [npm-version-src]: https://img.shields.io/npm/v/consola?style=flat&colorA=18181B&colorB=F0DB4F 363 | [npm-version-href]: https://npmjs.com/package/consola 364 | [npm-downloads-src]: https://img.shields.io/npm/dm/consola?style=flat&colorA=18181B&colorB=F0DB4F 365 | [npm-downloads-href]: https://npmjs.com/package/consola 366 | [codecov-src]: https://img.shields.io/codecov/c/gh/unjs/consola/main?style=flat&colorA=18181B&colorB=F0DB4F 367 | [codecov-href]: https://codecov.io/gh/unjs/consola 368 | [bundle-src]: https://img.shields.io/bundlephobia/min/consola?style=flat&colorA=18181B&colorB=F0DB4F 369 | [bundle-href]: https://bundlephobia.com/result?p=consola 370 | -------------------------------------------------------------------------------- /assets/fancy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unjs/consola/5ac9ed76b021c9ffc768f0727355238056aabeb1/assets/fancy.png -------------------------------------------------------------------------------- /assets/v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unjs/consola/5ac9ed76b021c9ffc768f0727355238056aabeb1/assets/v1.png -------------------------------------------------------------------------------- /basic.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./dist/basic"; 2 | -------------------------------------------------------------------------------- /browser.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./dist/browser"; 2 | -------------------------------------------------------------------------------- /build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from "unbuild"; 2 | 3 | export default defineBuildConfig({ 4 | rollup: { 5 | inlineDependencies: true, 6 | }, 7 | hooks: { 8 | "rollup:options"(_, options) { 9 | for (const output of options.output as any[]) { 10 | // @ts-ignore 11 | output.exports = "named"; 12 | } 13 | 14 | // Prompts theme 15 | // https://github.com/bombshell-dev/clack/issues/36 16 | options.plugins.push({ 17 | name: "@clack/prompts", 18 | transform(code, id) { 19 | if (id.endsWith("@clack/prompts/dist/index.mjs")) { 20 | const replaces = [ 21 | ["} $", "} $"], 22 | [String.raw`"\u25C6","*"`, '"❯", ">"'], 23 | [String.raw`"\u25A0","x"`, '"■", "x"'], 24 | [String.raw`"\u25B2","x"`, '"▲", "x"'], 25 | [String.raw`"\u25C7","o"`, '"✔", "√"'], 26 | [String.raw`"\u250C","T"`, '""'], 27 | [String.raw`"\u2502","|"`, '""'], 28 | [String.raw`"\u2514","\u2014"`, '""'], 29 | ] as const; 30 | for (const [from, to] of replaces) { 31 | code = code.replaceAll(from, to); 32 | } 33 | return code; 34 | } 35 | }, 36 | }); 37 | 38 | // Node.js 14 support 39 | // https://github.com/unjs/consola/issues/204 40 | options.plugins.push({ 41 | name: "icu-compat", 42 | transform(code, id) { 43 | if (id.endsWith("string-width/index.js")) { 44 | return code.replace( 45 | "const segmenter = new Intl.Segmenter();", 46 | "const segmenter = globalThis.Intl?.Segmenter ? new Intl.Segmenter() : { segment: (str) => str.split('') };", 47 | ); 48 | } 49 | }, 50 | }); 51 | }, 52 | }, 53 | }); 54 | -------------------------------------------------------------------------------- /core.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./dist/core"; 2 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import unjs from "eslint-config-unjs"; 2 | 3 | // https://github.com/unjs/eslint-config 4 | export default unjs({ 5 | ignores: [], 6 | rules: { 7 | "no-undef": 0, 8 | "unicorn/prefer-module": 0, 9 | "unicorn/prefer-top-level-await": 0, 10 | "unicorn/no-null": 0, 11 | "@typescript-eslint/no-unused-vars": 0, 12 | "unicorn/expiring-todo-comments": 0, 13 | }, 14 | markdown: { 15 | rules: { 16 | 'unicorn/no-process-exit': 0, 17 | } 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /examples/basic.ts: -------------------------------------------------------------------------------- 1 | import { reporterDemo } from "./utils"; 2 | 3 | reporterDemo({ 4 | fancy: false, 5 | }); 6 | -------------------------------------------------------------------------------- /examples/box.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "./utils"; 2 | import { colors } from "../src/utils"; 3 | 4 | function main() { 5 | consola.box(`I am the default banner`); 6 | 7 | consola.box( 8 | `${colors.red("I")} ${colors.yellowBright("am")} ${colors.yellow("the")} ${colors.green("rainbow")} ${colors.blue("banner")}`, 9 | ); 10 | 11 | consola.box({ 12 | title: "longer title", 13 | message: "short msg", 14 | }); 15 | 16 | consola.box({ 17 | title: "Box with options", 18 | message: `I am a banner with different options`, 19 | style: { 20 | padding: 1, 21 | borderColor: "magenta", 22 | borderStyle: "double-single-rounded", 23 | }, 24 | }); 25 | 26 | consola.box({ 27 | title: "Update available for `consola`", 28 | message: `\`v1.0.2\` → \`v2.0.0\`\n\nRun \`npm install -g consola\` to update`, 29 | style: { 30 | padding: 2, 31 | borderColor: "yellow", 32 | borderStyle: "rounded", 33 | }, 34 | }); 35 | } 36 | 37 | main(); 38 | -------------------------------------------------------------------------------- /examples/error.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "./utils"; 2 | 3 | const error = new Error("This is an error\nWith second line\nAnd another", { 4 | cause: new Error("This is the cause", { 5 | cause: new Error("This is the cause of the cause"), 6 | }), 7 | }); 8 | 9 | console.error(error); 10 | 11 | console.log("\n"); 12 | 13 | consola.error(error); 14 | -------------------------------------------------------------------------------- /examples/fancy.ts: -------------------------------------------------------------------------------- 1 | import { reporterDemo } from "./utils"; 2 | 3 | reporterDemo({ 4 | fancy: true, 5 | }); 6 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Consola 5 | 6 | 7 | Open developer tools to see the magic! 8 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/index.legacy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Consola 5 | 6 | 7 | Open developer tools to see the magic! 8 | 9 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/json.ts: -------------------------------------------------------------------------------- 1 | import { createConsola } from "consola"; 2 | 3 | const consola = createConsola({ 4 | reporters: [ 5 | { 6 | log: (logObj) => { 7 | console.log(JSON.stringify(logObj)); 8 | }, 9 | }, 10 | ], 11 | }); 12 | 13 | consola.log("foo bar"); 14 | -------------------------------------------------------------------------------- /examples/mock.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "./utils"; 2 | 3 | function mockFn(type) { 4 | if (type === "info") { 5 | return function () { 6 | this.log("(mocked fn with info tag)"); 7 | }; 8 | } 9 | } 10 | 11 | consola.info("before"); 12 | 13 | consola.mockTypes(mockFn); 14 | 15 | const tagged = consola.withTag("newTag"); 16 | 17 | consola.log("log is not mocked!"); 18 | 19 | consola.info("Dont see me"); 20 | tagged.info("Dont see me too"); 21 | -------------------------------------------------------------------------------- /examples/no-width.ts: -------------------------------------------------------------------------------- 1 | import { createConsola } from "../src"; 2 | 3 | function main() { 4 | const consola = createConsola({ 5 | formatOptions: { columns: 0 }, 6 | }); 7 | consola.info("Foobar"); 8 | const scoped = consola.withTag("test"); 9 | scoped.success("Foobar"); 10 | } 11 | 12 | main(); 13 | -------------------------------------------------------------------------------- /examples/pause.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "./utils"; 2 | 3 | const c1 = consola.withTag("foo"); 4 | const c2 = consola.withTag("bar"); 5 | 6 | consola.log("before pause"); 7 | 8 | c2.pause(); 9 | 10 | c1.log("C1 is ready"); 11 | c2.log("C2 is ready"); 12 | 13 | setTimeout(() => { 14 | consola.resume(); 15 | consola.log("Yo!"); 16 | }, 1000); 17 | -------------------------------------------------------------------------------- /examples/prompt.mjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { consola } from "../dist/index.mjs"; 4 | 5 | const name = await consola.prompt("What is your name?", { 6 | placeholder: "Not sure", 7 | initial: "java", 8 | cancel: "undefined", 9 | }); 10 | 11 | if (!name) { 12 | process.exit(1); 13 | } 14 | 15 | const confirmed = await consola.prompt("Do you want to continue?", { 16 | type: "confirm", 17 | cancel: "undefined", 18 | }); 19 | 20 | if (!confirmed) { 21 | process.exit(1); 22 | } 23 | 24 | const projectType = await consola.prompt("Pick a project type.", { 25 | type: "select", 26 | options: [ 27 | "JavaScript", 28 | "TypeScript", 29 | { label: "CoffeeScript", value: "CoffeeScript", hint: "oh no" }, 30 | ], 31 | cancel: "undefined", 32 | initial: "TypeScript", 33 | }); 34 | 35 | if (!projectType) { 36 | process.exit(1); 37 | } 38 | 39 | const tools = await consola.prompt("Select additional tools.", { 40 | type: "multiselect", 41 | required: false, 42 | options: [ 43 | { value: "eslint", label: "ESLint", hint: "recommended" }, 44 | { value: "prettier", label: "Prettier" }, 45 | { value: "gh-action", label: "GitHub Action" }, 46 | ], 47 | cancel: "undefined", 48 | initial: ["eslint", "prettier"], 49 | }); 50 | 51 | if (!tools) { 52 | process.exit(1); 53 | } 54 | 55 | consola.start("Creating project..."); 56 | await new Promise((resolve) => setTimeout(resolve, 1000)); 57 | consola.success("Project created!"); 58 | -------------------------------------------------------------------------------- /examples/prompt.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "./utils"; 2 | 3 | async function main() { 4 | const name = await consola.prompt("What is your name?", { 5 | placeholder: "Not sure", 6 | initial: "java", 7 | }); 8 | 9 | const confirmed = await consola.prompt("Do you want to continue?", { 10 | type: "confirm", 11 | }); 12 | 13 | const projectType = await consola.prompt("Pick a project type.", { 14 | type: "select", 15 | options: [ 16 | "JavaScript", 17 | "TypeScript", 18 | { label: "CoffeeScript", value: "CoffeeScript", hint: "oh no" }, 19 | ], 20 | initial: "TypeScript", 21 | }); 22 | 23 | const tools = await consola.prompt("Select additional tools.", { 24 | type: "multiselect", 25 | required: false, 26 | options: [ 27 | { value: "eslint", label: "ESLint", hint: "recommended" }, 28 | { value: "prettier", label: "Prettier" }, 29 | { value: "gh-action", label: "GitHub Action" }, 30 | ], 31 | initial: ["eslint", "prettier"], 32 | }); 33 | 34 | consola.start("Creating project..."); 35 | await new Promise((resolve) => setTimeout(resolve, 1000)); 36 | consola.success("Project created!"); 37 | } 38 | 39 | main(); 40 | -------------------------------------------------------------------------------- /examples/raw.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "./utils"; 2 | 3 | consola.log('consola.log({ message: "hello" })'); 4 | // Prints "hello" 5 | consola.log({ message: "hello" }); 6 | 7 | consola.log('consola.log.raw({ message: "hello" })'); 8 | // Prints "{ message: 'hello' }" 9 | consola.log.raw({ message: "hello" }); 10 | -------------------------------------------------------------------------------- /examples/sample.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "../src"; 2 | 3 | async function main() { 4 | consola.warn("A new version of consola is available: 3.0.1"); 5 | consola.error(new Error("This is an example error. Everything is fine!")); 6 | consola.info("Using consola 3.0.0"); 7 | consola.start("Building project..."); 8 | consola.success("Project built!"); 9 | await consola.prompt("Deploy to the production?", { 10 | type: "confirm", 11 | }); 12 | } 13 | 14 | main(); 15 | -------------------------------------------------------------------------------- /examples/spam.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "./utils"; 2 | 3 | function waitFor(ms) { 4 | return new Promise((resolve) => setTimeout(resolve, ms)); 5 | } 6 | 7 | async function spam({ count, delay }) { 8 | for (let i = 0; i < count; i++) { 9 | await waitFor(delay); 10 | consola.log(`Spam (Count: ${count} Delay: ${delay} ms)`); 11 | } 12 | } 13 | 14 | (async () => { 15 | await spam({ count: 2, delay: 10 }); 16 | await spam({ count: 20, delay: 10 }); 17 | await spam({ count: 20, delay: 0 }); 18 | await spam({ count: 80, delay: 10 }); 19 | })(); 20 | -------------------------------------------------------------------------------- /examples/special.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "./utils"; 2 | 3 | consola.error({ 4 | message: "Foobar", 5 | }); 6 | 7 | consola.log({ 8 | AAA: "BBB", 9 | }); 10 | 11 | // consola.log(consola) 12 | 13 | consola.log("%d", 12); 14 | 15 | consola.error({ type: "CSSError", message: "Use scss" }); 16 | 17 | consola.error(undefined, null, false, true, Number.NaN); 18 | 19 | consola.log("We can `monospace` keyword using grave accent charachter!"); 20 | 21 | consola.log( 22 | "We can also _underline_ words but not_this or this should_not_be_underlined!", 23 | ); 24 | 25 | // Nonstandard error 26 | const { message, stack } = new Error("Custom Error!"); 27 | consola.error({ message, stack }); 28 | 29 | // Circular object 30 | const a = { foo: 1, bar: undefined as any }; 31 | a.bar = a; 32 | consola.log(a); 33 | 34 | // Multiline 35 | consola.log("`Hello` the `JS`\n`World` and `Beyond`!"); 36 | -------------------------------------------------------------------------------- /examples/spinner.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "./utils"; 2 | 3 | async function main() { 4 | consola.start("Creating project..."); 5 | await new Promise((resolve) => setTimeout(resolve, 1000)); 6 | consola.success("Project created!"); 7 | } 8 | 9 | main(); 10 | -------------------------------------------------------------------------------- /examples/tree.ts: -------------------------------------------------------------------------------- 1 | import { TreeItem, formatTree } from "../src/utils/tree"; 2 | import { consola } from "./utils"; 3 | 4 | function main() { 5 | const keywords = [ 6 | "console", 7 | "logger", 8 | "reporter", 9 | "elegant", 10 | "cli", 11 | "universal", 12 | "unified", 13 | "prompt", 14 | "clack", 15 | "format", 16 | "error", 17 | "stacktrace", 18 | ]; 19 | 20 | consola.log(formatTree(keywords)); 21 | 22 | consola.log( 23 | formatTree(keywords, { 24 | color: "cyan", 25 | prefix: " | ", 26 | }), 27 | ); 28 | 29 | consola.log( 30 | formatTree( 31 | [ 32 | { 33 | text: "consola", 34 | color: "green", 35 | }, 36 | { 37 | text: "logger", 38 | }, 39 | ].map( 40 | (item) => 41 | ({ 42 | text: ` ${item.text}`, 43 | color: item.color, 44 | }) as TreeItem, 45 | ), 46 | { 47 | color: "gray", 48 | }, 49 | ), 50 | ); 51 | 52 | // Deep tree 53 | consola.log( 54 | formatTree([ 55 | { 56 | text: "format", 57 | color: "red", 58 | }, 59 | { 60 | text: "consola", 61 | color: "yellow", 62 | children: [ 63 | { 64 | text: "logger", 65 | color: "green", 66 | children: [ 67 | { 68 | text: "reporter", 69 | color: "cyan", 70 | }, 71 | { 72 | text: "test", 73 | color: "magenta", 74 | children: ["nice tree"], 75 | }, 76 | ], 77 | }, 78 | { 79 | text: "reporter", 80 | color: "bold", 81 | }, 82 | "test", 83 | ], 84 | }, 85 | ]), 86 | ); 87 | 88 | // Deep tree with max depth 89 | consola.log( 90 | formatTree( 91 | [ 92 | { 93 | text: "format", 94 | color: "red", 95 | }, 96 | { 97 | text: "consola", 98 | color: "yellow", 99 | children: [ 100 | { 101 | text: "logger", 102 | color: "green", 103 | children: [ 104 | { 105 | text: "reporter", 106 | color: "cyan", 107 | }, 108 | { 109 | text: "test", 110 | color: "magenta", 111 | children: ["nice tree"], 112 | }, 113 | ], 114 | }, 115 | { 116 | text: "reporter", 117 | color: "bold", 118 | }, 119 | "test", 120 | ], 121 | }, 122 | ], 123 | { 124 | maxDepth: 2, 125 | }, 126 | ), 127 | ); 128 | 129 | // Indicate the ellipsis 130 | consola.log( 131 | formatTree( 132 | [ 133 | { 134 | text: "format", 135 | color: "red", 136 | }, 137 | { 138 | text: "consola", 139 | color: "yellow", 140 | children: [ 141 | { 142 | text: "logger", 143 | color: "green", 144 | children: [ 145 | { 146 | text: "reporter", 147 | color: "cyan", 148 | }, 149 | { 150 | text: "test", 151 | color: "magenta", 152 | children: ["nice tree"], 153 | }, 154 | ], 155 | }, 156 | { 157 | text: "reporter", 158 | color: "bold", 159 | }, 160 | "test", 161 | ], 162 | }, 163 | ], 164 | { 165 | maxDepth: 2, 166 | ellipsis: "---", 167 | }, 168 | ), 169 | ); 170 | } 171 | 172 | main(); 173 | -------------------------------------------------------------------------------- /examples/utils/index.ts: -------------------------------------------------------------------------------- 1 | import { ConsolaOptions, createConsola } from "../../src"; 2 | import { randomSentence } from "./sentence"; 3 | 4 | export function reporterDemo( 5 | opts: Partial, 6 | ) { 7 | const consola = createConsola({ 8 | ...opts, 9 | }); 10 | 11 | for (const type of Object.keys(consola.options.types).sort()) { 12 | consola[type](randomSentence()); 13 | } 14 | 15 | consola.info("JSON", { 16 | name: "Cat", 17 | color: "#454545", 18 | }); 19 | 20 | consola.error(new Error(randomSentence())); 21 | 22 | const tagged = consola.withTag("unjs").withTag("router"); 23 | 24 | for (const type of Object.keys(consola.options.types).sort()) { 25 | tagged[type](randomSentence()); 26 | } 27 | } 28 | 29 | export const consola = createConsola(); 30 | -------------------------------------------------------------------------------- /examples/utils/sentence.ts: -------------------------------------------------------------------------------- 1 | import Sentencer from "sentencer"; 2 | 3 | const sentenceTemplates = [ 4 | "the {{ noun }} is {{ a_noun }}", 5 | "{{ a_noun }} is {{ an_adjective }} {{ noun }}", 6 | "the first {{ adjective }} {{ noun }} is, in its own way, {{ a_noun }}", 7 | "their {{ noun }} was, in this moment, {{ an_adjective }} {{ noun }}", 8 | "{{ a_noun }} is {{ a_noun }} from the right perspective", 9 | "the literature would have us believe that {{ an_adjective }} {{ noun }} is not but {{ a_noun }}", 10 | "{{ an_adjective }} {{ noun }} is {{ a_noun }} of the mind", 11 | "the {{ adjective }} {{ noun }} reveals itself as {{ an_adjective }} {{ noun }} to those who look", 12 | "authors often misinterpret the {{ noun }} as {{ an_adjective }} {{ noun }}, when in actuality it feels more like {{ an_adjective}} {{ noun }}", 13 | "we can assume that any instance of {{ a_noun }} can be construed as {{ an_adjective }} {{ noun }}", 14 | "they were lost without the {{ adjective }} {{ noun }} that composed their {{ noun }}", 15 | "the {{ adjective }} {{ noun }} comes from {{ an_adjective }} {{ noun }}", 16 | "{{ a_noun }} can hardly be considered {{ an_adjective }} {{ noun }} without also being {{ a_noun }}", 17 | "few can name {{ an_adjective }} {{ noun }} that isn't {{ an_adjective }} {{ noun }}", 18 | "some posit the {{ adjective }} {{ noun }} to be less than {{ adjective }}", 19 | "{{ a_noun }} of the {{ noun }} is assumed to be {{ an_adjective }} {{ noun }}", 20 | "{{ a_noun }} sees {{ a_noun }} as {{ an_adjective }} {{ noun }}", 21 | "the {{ noun }} of {{ a_noun }} becomes {{ an_adjective }} {{ noun }}", 22 | "{{ a_noun }} is {{ a_noun }}'s {{ noun }}", 23 | "{{ a_noun }} is the {{ noun }} of {{ a_noun }}", 24 | "{{ an_adjective }} {{ noun }}'s {{ noun }} comes with it the thought that the {{ adjective }} {{ noun }} is {{ a_noun }}", 25 | "{{ nouns }} are {{ adjective }} {{ nouns }}", 26 | "{{ adjective }} {{ nouns }} show us how {{ nouns }} can be {{ nouns }}", 27 | "before {{ nouns }}, {{ nouns }} were only {{ nouns }}", 28 | "those {{ nouns }} are nothing more than {{ nouns }}", 29 | "some {{ adjective }} {{ nouns }} are thought of simply as {{ nouns }}", 30 | "one cannot separate {{ nouns }} from {{ adjective }} {{ nouns }}", 31 | "the {{ nouns }} could be said to resemble {{ adjective }} {{ nouns }}", 32 | "{{ an_adjective }} {{ noun }} without {{ nouns }} is truly a {{ noun }} of {{ adjective }} {{ nouns }}", 33 | ]; 34 | 35 | export function randomSentence() { 36 | const t = 37 | sentenceTemplates[ 38 | Math.round(Math.random() * (sentenceTemplates.length - 1)) 39 | ]; 40 | return Sentencer.make(t); 41 | } 42 | -------------------------------------------------------------------------------- /examples/wrap-all.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "./utils"; 2 | 3 | function foo() { 4 | console.info("console foo"); 5 | process.stderr.write("called from stderr\n"); 6 | } 7 | 8 | consola.wrapAll(); 9 | foo(); 10 | consola.restoreAll(); 11 | foo(); 12 | -------------------------------------------------------------------------------- /examples/wrap-console.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "./utils"; 2 | 3 | function foo() { 4 | console.info("foo"); 5 | console.warn("foo warn"); 6 | } 7 | 8 | function _trace() { 9 | console.trace("foobar"); 10 | } 11 | function trace() { 12 | _trace(); 13 | } 14 | 15 | foo(); 16 | consola.wrapConsole(); 17 | foo(); 18 | trace(); 19 | consola.restoreConsole(); 20 | foo(); 21 | trace(); 22 | -------------------------------------------------------------------------------- /examples/wrap-std.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "./utils"; 2 | 3 | function foo() { 4 | console.info("console foo"); 5 | process.stdout.write("called from stdout foo\n"); 6 | process.stderr.write("called from stderr foo\n"); 7 | } 8 | 9 | consola.wrapStd(); 10 | foo(); 11 | consola.restoreStd(); 12 | foo(); 13 | -------------------------------------------------------------------------------- /lib/index.cjs: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-require-imports 2 | const lib = require("../dist/index.cjs"); 3 | 4 | module.exports = lib.consola; 5 | 6 | for (const key in lib) { 7 | if (!(key in module.exports)) { 8 | module.exports[key] = lib[key]; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "consola", 3 | "version": "3.4.2", 4 | "description": "Elegant Console Wrapper", 5 | "keywords": [ 6 | "console", 7 | "logger", 8 | "reporter", 9 | "elegant", 10 | "cli", 11 | "universal", 12 | "unified", 13 | "prompt", 14 | "clack", 15 | "format", 16 | "error", 17 | "stacktrace" 18 | ], 19 | "repository": "unjs/consola", 20 | "license": "MIT", 21 | "type": "module", 22 | "exports": { 23 | ".": { 24 | "node": { 25 | "import": { 26 | "types": "./dist/index.d.mts", 27 | "default": "./dist/index.mjs" 28 | }, 29 | "require": { 30 | "types": "./dist/index.d.cts", 31 | "default": "./lib/index.cjs" 32 | } 33 | }, 34 | "default": { 35 | "import": { 36 | "types": "./dist/browser.d.mts", 37 | "default": "./dist/browser.mjs" 38 | }, 39 | "require": { 40 | "types": "./dist/browser.d.cts", 41 | "default": "./dist/browser.cjs" 42 | } 43 | } 44 | }, 45 | "./browser": { 46 | "import": { 47 | "types": "./dist/browser.d.mts", 48 | "default": "./dist/browser.mjs" 49 | }, 50 | "require": { 51 | "types": "./dist/browser.d.cts", 52 | "default": "./dist/browser.cjs" 53 | } 54 | }, 55 | "./basic": { 56 | "node": { 57 | "import": { 58 | "types": "./dist/basic.d.mts", 59 | "default": "./dist/basic.mjs" 60 | }, 61 | "require": { 62 | "types": "./dist/basic.d.cts", 63 | "default": "./dist/basic.cjs" 64 | } 65 | }, 66 | "default": { 67 | "import": { 68 | "types": "./dist/browser.d.mts", 69 | "default": "./dist/browser.mjs" 70 | }, 71 | "require": { 72 | "types": "./dist/browser.d.cts", 73 | "default": "./dist/browser.cjs" 74 | } 75 | } 76 | }, 77 | "./core": { 78 | "import": { 79 | "types": "./dist/core.d.mts", 80 | "default": "./dist/core.mjs" 81 | }, 82 | "require": { 83 | "types": "./dist/core.d.cts", 84 | "default": "./dist/core.cjs" 85 | } 86 | }, 87 | "./utils": { 88 | "import": { 89 | "types": "./dist/utils.d.mts", 90 | "default": "./dist/utils.mjs" 91 | }, 92 | "require": { 93 | "types": "./dist/utils.d.cts", 94 | "default": "./dist/utils.cjs" 95 | } 96 | } 97 | }, 98 | "main": "./lib/index.cjs", 99 | "module": "./dist/index.mjs", 100 | "browser": "./dist/browser.mjs", 101 | "types": "./dist/index.d.ts", 102 | "files": [ 103 | "dist", 104 | "lib", 105 | "*.d.ts" 106 | ], 107 | "scripts": { 108 | "build": "unbuild", 109 | "dev": "vitest", 110 | "lint": "eslint . && prettier -c src examples test", 111 | "lint:fix": "eslint . --fix && prettier -w src examples test", 112 | "release": "pnpm test && pnpm build && changelogen --release --push && npm publish", 113 | "test": "pnpm lint && pnpm vitest run --coverage" 114 | }, 115 | "devDependencies": { 116 | "@clack/prompts": "^0.10.0", 117 | "@types/node": "^22.13.10", 118 | "@vitest/coverage-v8": "^3.0.9", 119 | "changelogen": "^0.6.1", 120 | "defu": "^6.1.4", 121 | "eslint": "^9.22.0", 122 | "eslint-config-unjs": "^0.4.2", 123 | "is-unicode-supported": "^2.1.0", 124 | "prettier": "^3.5.3", 125 | "sentencer": "^0.2.1", 126 | "std-env": "^3.8.1", 127 | "string-width": "^7.2.0", 128 | "typescript": "^5.8.2", 129 | "unbuild": "^3.5.0", 130 | "vitest": "^3.0.9" 131 | }, 132 | "engines": { 133 | "node": "^14.18.0 || >=16.10.0" 134 | }, 135 | "packageManager": "pnpm@10.6.3" 136 | } 137 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["github>unjs/renovate-config"] 3 | } 4 | -------------------------------------------------------------------------------- /src/basic.ts: -------------------------------------------------------------------------------- 1 | import { LogLevels, LogLevel } from "./constants"; 2 | import type { ConsolaOptions } from "./types"; 3 | import { BasicReporter } from "./reporters/basic"; 4 | import { ConsolaInstance, createConsola as _createConsola } from "./consola"; 5 | 6 | export * from "./shared"; 7 | 8 | /** 9 | * Factory function to create a new Consola instance 10 | * 11 | * @param {Partial} [options={}] - Optional configuration options. See {@link ConsolaOptions}. 12 | * @returns {ConsolaInstance} A new Consola instance configured with the given options. 13 | */ 14 | export function createConsola( 15 | options: Partial = {}, 16 | ): ConsolaInstance { 17 | // Log level 18 | let level: LogLevel = LogLevels.info; 19 | if (process.env.CONSOLA_LEVEL) { 20 | level = Number.parseInt(process.env.CONSOLA_LEVEL) ?? level; 21 | } 22 | 23 | // Create new consola instance 24 | const consola = _createConsola({ 25 | level, 26 | defaults: { level }, 27 | stdout: process.stdout, 28 | stderr: process.stderr, 29 | reporters: options.reporters || [new BasicReporter()], 30 | ...options, 31 | }); 32 | 33 | return consola; 34 | } 35 | 36 | /** 37 | * Creates and exports a standard instance of Consola with the default configuration. 38 | * This instance can be used directly for logging throughout the application. 39 | * 40 | * @type {ConsolaInstance} consola - The default instance of Consola. 41 | */ 42 | export const consola = createConsola(); 43 | 44 | export default consola; 45 | -------------------------------------------------------------------------------- /src/browser.ts: -------------------------------------------------------------------------------- 1 | import { BrowserReporter } from "./reporters/browser"; 2 | import { createConsola as _createConsola } from "./consola"; 3 | import type { ConsolaOptions } from "./types"; 4 | 5 | export * from "./shared"; 6 | 7 | /** 8 | * Creates a new Consola instance configured specifically for browser environments. 9 | * This function sets up default reporters and a prompt method tailored to the browser's dialogue APIs. 10 | * 11 | * @param {Partial} [options={}] - Optional configuration options. 12 | * The options can override the default reporter and prompt behaviour. See {@link ConsolaOptions}. 13 | * @returns {ConsolaInstance} A new Consola instance optimised for use in browser environments. 14 | */ 15 | export function createConsola(options: Partial = {}) { 16 | const consola = _createConsola({ 17 | reporters: options.reporters || [new BrowserReporter({})], 18 | prompt(message, options = {}) { 19 | if (options.type === "confirm") { 20 | return Promise.resolve(confirm(message) as any); 21 | } 22 | return Promise.resolve(prompt(message)); 23 | }, 24 | ...options, 25 | }); 26 | return consola; 27 | } 28 | 29 | /** 30 | * A standard Consola instance created with browser-specific configurations. 31 | * This instance can be used throughout a browser-based project. 32 | * 33 | * @type {ConsolaInstance} consola - The default browser-configured Consola instance. 34 | */ 35 | export const consola = createConsola(); 36 | 37 | export default consola; 38 | -------------------------------------------------------------------------------- /src/consola.ts: -------------------------------------------------------------------------------- 1 | import { defu } from "defu"; 2 | import { LogTypes, LogType, LogLevel } from "./constants"; 3 | import { isLogObj } from "./utils/log"; 4 | import type { 5 | ConsolaReporter, 6 | InputLogObject, 7 | LogObject, 8 | ConsolaOptions, 9 | } from "./types"; 10 | import type { PromptOptions } from "./prompt"; 11 | 12 | let paused = false; 13 | const queue: any[] = []; 14 | 15 | /** 16 | * Consola class for logging management with support for pause/resume, mocking and customisable reporting. 17 | * Provides flexible logging capabilities including level-based logging, custom reporters and integration options. 18 | * 19 | * @class Consola 20 | */ 21 | export class Consola { 22 | options: ConsolaOptions; 23 | 24 | _lastLog: { 25 | serialized?: string; 26 | object?: LogObject; 27 | count?: number; 28 | time?: Date; 29 | timeout?: ReturnType; 30 | }; 31 | 32 | _mockFn?: ConsolaOptions["mockFn"]; 33 | 34 | /** 35 | * Creates an instance of Consola with specified options or defaults. 36 | * 37 | * @param {Partial} [options={}] - Configuration options for the Consola instance. 38 | */ 39 | constructor(options: Partial = {}) { 40 | // Options 41 | const types = options.types || LogTypes; 42 | this.options = defu( 43 | { 44 | ...options, 45 | defaults: { ...options.defaults }, 46 | level: _normalizeLogLevel(options.level, types), 47 | reporters: [...(options.reporters || [])], 48 | }, 49 | >{ 50 | types: LogTypes, 51 | throttle: 1000, 52 | throttleMin: 5, 53 | formatOptions: { 54 | date: true, 55 | colors: false, 56 | compact: true, 57 | }, 58 | }, 59 | ); 60 | 61 | // Create logger functions for current instance 62 | for (const type in types) { 63 | const defaults: InputLogObject = { 64 | type: type as LogType, 65 | ...this.options.defaults, 66 | ...types[type as LogType], 67 | }; 68 | // @ts-expect-error 69 | (this as unknown as ConsolaInstance)[type as LogType] = 70 | this._wrapLogFn(defaults); 71 | // @ts-expect-error 72 | (this as unknown as ConsolaInstance)[type].raw = this._wrapLogFn( 73 | defaults, 74 | true, 75 | ); 76 | } 77 | 78 | // Use _mockFn if is set 79 | if (this.options.mockFn) { 80 | this.mockTypes(); 81 | } 82 | 83 | // Track of last log 84 | this._lastLog = {}; 85 | } 86 | 87 | /** 88 | * Gets the current log level of the Consola instance. 89 | * 90 | * @returns {number} The current log level. 91 | */ 92 | get level() { 93 | return this.options.level; 94 | } 95 | 96 | /** 97 | * Sets the minimum log level that will be output by the instance. 98 | * 99 | * @param {number} level - The new log level to set. 100 | */ 101 | set level(level) { 102 | this.options.level = _normalizeLogLevel( 103 | level, 104 | this.options.types, 105 | this.options.level, 106 | ); 107 | } 108 | 109 | /** 110 | * Displays a prompt to the user and returns the response. 111 | * Throw an error if `prompt` is not supported by the current configuration. 112 | * 113 | * @template T 114 | * @param {string} message - The message to display in the prompt. 115 | * @param {T} [opts] - Optional options for the prompt. See {@link PromptOptions}. 116 | * @returns {promise} A promise that infer with the prompt options. See {@link PromptOptions}. 117 | */ 118 | prompt(message: string, opts?: T) { 119 | if (!this.options.prompt) { 120 | throw new Error("prompt is not supported!"); 121 | } 122 | return this.options.prompt(message, opts); 123 | } 124 | 125 | /** 126 | * Creates a new instance of Consola, inheriting options from the current instance, with possible overrides. 127 | * 128 | * @param {Partial} options - Optional overrides for the new instance. See {@link ConsolaOptions}. 129 | * @returns {ConsolaInstance} A new Consola instance. See {@link ConsolaInstance}. 130 | */ 131 | create(options: Partial): ConsolaInstance { 132 | const instance = new Consola({ 133 | ...this.options, 134 | ...options, 135 | }) as ConsolaInstance; 136 | 137 | if (this._mockFn) { 138 | instance.mockTypes(this._mockFn); 139 | } 140 | 141 | return instance; 142 | } 143 | 144 | /** 145 | * Creates a new Consola instance with the specified default log object properties. 146 | * 147 | * @param {InputLogObject} defaults - Default properties to include in any log from the new instance. See {@link InputLogObject}. 148 | * @returns {ConsolaInstance} A new Consola instance. See {@link ConsolaInstance}. 149 | */ 150 | withDefaults(defaults: InputLogObject): ConsolaInstance { 151 | return this.create({ 152 | ...this.options, 153 | defaults: { 154 | ...this.options.defaults, 155 | ...defaults, 156 | }, 157 | }); 158 | } 159 | 160 | /** 161 | * Creates a new Consola instance with a specified tag, which will be included in every log. 162 | * 163 | * @param {string} tag - The tag to include in each log of the new instance. 164 | * @returns {ConsolaInstance} A new Consola instance. See {@link ConsolaInstance}. 165 | */ 166 | withTag(tag: string): ConsolaInstance { 167 | return this.withDefaults({ 168 | tag: this.options.defaults.tag 169 | ? this.options.defaults.tag + ":" + tag 170 | : tag, 171 | }); 172 | } 173 | 174 | /** 175 | * Adds a custom reporter to the Consola instance. 176 | * Reporters will be called for each log message, depending on their implementation and log level. 177 | * 178 | * @param {ConsolaReporter} reporter - The reporter to add. See {@link ConsolaReporter}. 179 | * @returns {Consola} The current Consola instance. 180 | */ 181 | addReporter(reporter: ConsolaReporter) { 182 | this.options.reporters.push(reporter); 183 | return this; 184 | } 185 | 186 | /** 187 | * Removes a custom reporter from the Consola instance. 188 | * If no reporter is specified, all reporters will be removed. 189 | * 190 | * @param {ConsolaReporter} reporter - The reporter to remove. See {@link ConsolaReporter}. 191 | * @returns {Consola} The current Consola instance. 192 | */ 193 | removeReporter(reporter: ConsolaReporter) { 194 | if (reporter) { 195 | const i = this.options.reporters.indexOf(reporter); 196 | if (i !== -1) { 197 | return this.options.reporters.splice(i, 1); 198 | } 199 | } else { 200 | this.options.reporters.splice(0); 201 | } 202 | return this; 203 | } 204 | 205 | /** 206 | * Replaces all reporters of the Consola instance with the specified array of reporters. 207 | * 208 | * @param {ConsolaReporter[]} reporters - The new reporters to set. See {@link ConsolaReporter}. 209 | * @returns {Consola} The current Consola instance. 210 | */ 211 | setReporters(reporters: ConsolaReporter[]) { 212 | this.options.reporters = Array.isArray(reporters) ? reporters : [reporters]; 213 | return this; 214 | } 215 | 216 | wrapAll() { 217 | this.wrapConsole(); 218 | this.wrapStd(); 219 | } 220 | 221 | restoreAll() { 222 | this.restoreConsole(); 223 | this.restoreStd(); 224 | } 225 | 226 | /** 227 | * Overrides console methods with Consola logging methods for consistent logging. 228 | */ 229 | wrapConsole() { 230 | for (const type in this.options.types) { 231 | // Backup original value 232 | if (!(console as any)["__" + type]) { 233 | (console as any)["__" + type] = (console as any)[type]; 234 | } 235 | // Override 236 | (console as any)[type] = (this as unknown as ConsolaInstance)[ 237 | type as LogType 238 | ].raw; 239 | } 240 | } 241 | 242 | /** 243 | * Restores the original console methods, removing Consola overrides. 244 | */ 245 | restoreConsole() { 246 | for (const type in this.options.types) { 247 | // Restore if backup is available 248 | if ((console as any)["__" + type]) { 249 | (console as any)[type] = (console as any)["__" + type]; 250 | delete (console as any)["__" + type]; 251 | } 252 | } 253 | } 254 | 255 | /** 256 | * Overrides standard output and error streams to redirect them through Consola. 257 | */ 258 | wrapStd() { 259 | this._wrapStream(this.options.stdout, "log"); 260 | this._wrapStream(this.options.stderr, "log"); 261 | } 262 | 263 | _wrapStream(stream: NodeJS.WriteStream | undefined, type: LogType) { 264 | if (!stream) { 265 | return; 266 | } 267 | 268 | // Backup original value 269 | if (!(stream as any).__write) { 270 | (stream as any).__write = stream.write; 271 | } 272 | 273 | // Override 274 | (stream as any).write = (data: any) => { 275 | (this as unknown as ConsolaInstance)[type].raw(String(data).trim()); 276 | }; 277 | } 278 | 279 | /** 280 | * Restores the original standard output and error streams, removing the Consola redirection. 281 | */ 282 | restoreStd() { 283 | this._restoreStream(this.options.stdout); 284 | this._restoreStream(this.options.stderr); 285 | } 286 | 287 | _restoreStream(stream?: NodeJS.WriteStream) { 288 | if (!stream) { 289 | return; 290 | } 291 | 292 | if ((stream as any).__write) { 293 | stream.write = (stream as any).__write; 294 | delete (stream as any).__write; 295 | } 296 | } 297 | 298 | /** 299 | * Pauses logging, queues incoming logs until resumed. 300 | */ 301 | pauseLogs() { 302 | paused = true; 303 | } 304 | 305 | /** 306 | * Resumes logging, processing any queued logs. 307 | */ 308 | resumeLogs() { 309 | paused = false; 310 | 311 | // Process queue 312 | const _queue = queue.splice(0); 313 | for (const item of _queue) { 314 | item[0]._logFn(item[1], item[2]); 315 | } 316 | } 317 | 318 | /** 319 | * Replaces logging methods with mocks if a mock function is provided. 320 | * 321 | * @param {ConsolaOptions["mockFn"]} mockFn - The function to use for mocking logging methods. See {@link ConsolaOptions["mockFn"]}. 322 | */ 323 | mockTypes(mockFn?: ConsolaOptions["mockFn"]) { 324 | const _mockFn = mockFn || this.options.mockFn; 325 | 326 | this._mockFn = _mockFn; 327 | 328 | if (typeof _mockFn !== "function") { 329 | return; 330 | } 331 | 332 | for (const type in this.options.types) { 333 | // @ts-expect-error 334 | (this as unknown as ConsolaInstance)[type as LogType] = 335 | _mockFn(type as LogType, this.options.types[type as LogType]) || 336 | (this as unknown as ConsolaInstance)[type as LogType]; 337 | (this as unknown as ConsolaInstance)[type as LogType].raw = ( 338 | this as unknown as ConsolaInstance 339 | )[type as LogType]; 340 | } 341 | } 342 | 343 | _wrapLogFn(defaults: InputLogObject, isRaw?: boolean) { 344 | return (...args: any[]) => { 345 | if (paused) { 346 | queue.push([this, defaults, args, isRaw]); 347 | return; 348 | } 349 | return this._logFn(defaults, args, isRaw); 350 | }; 351 | } 352 | 353 | _logFn(defaults: InputLogObject, args: any[], isRaw?: boolean) { 354 | if (((defaults.level as number) || 0) > this.level) { 355 | return false; 356 | } 357 | 358 | // Construct a new log object 359 | const logObj: Partial = { 360 | date: new Date(), 361 | args: [], 362 | ...defaults, 363 | level: _normalizeLogLevel(defaults.level, this.options.types), 364 | }; 365 | 366 | // Consume arguments 367 | if (!isRaw && args.length === 1 && isLogObj(args[0])) { 368 | Object.assign(logObj, args[0]); 369 | } else { 370 | logObj.args = [...args]; 371 | } 372 | 373 | // Aliases 374 | if (logObj.message) { 375 | logObj.args!.unshift(logObj.message); 376 | delete logObj.message; 377 | } 378 | if (logObj.additional) { 379 | if (!Array.isArray(logObj.additional)) { 380 | logObj.additional = logObj.additional.split("\n"); 381 | } 382 | 383 | logObj.args!.push("\n" + logObj.additional.join("\n")); 384 | delete logObj.additional; 385 | } 386 | 387 | // Normalize type to lowercase 388 | logObj.type = ( 389 | typeof logObj.type === "string" ? logObj.type.toLowerCase() : "log" 390 | ) as LogType; 391 | logObj.tag = typeof logObj.tag === "string" ? logObj.tag : ""; 392 | 393 | // Resolve log 394 | /** 395 | * @param newLog false if the throttle expired and 396 | * we don't want to log a duplicate 397 | */ 398 | const resolveLog = (newLog = false) => { 399 | const repeated = (this._lastLog.count || 0) - this.options.throttleMin; 400 | if (this._lastLog.object && repeated > 0) { 401 | const args = [...this._lastLog.object.args]; 402 | if (repeated > 1) { 403 | args.push(`(repeated ${repeated} times)`); 404 | } 405 | this._log({ ...this._lastLog.object, args }); 406 | this._lastLog.count = 1; 407 | } 408 | 409 | // Log 410 | if (newLog) { 411 | this._lastLog.object = logObj as LogObject; 412 | this._log(logObj as LogObject); 413 | } 414 | }; 415 | 416 | // Throttle 417 | clearTimeout(this._lastLog.timeout); 418 | const diffTime = 419 | this._lastLog.time && logObj.date 420 | ? logObj.date.getTime() - this._lastLog.time.getTime() 421 | : 0; 422 | this._lastLog.time = logObj.date; 423 | if (diffTime < this.options.throttle) { 424 | try { 425 | const serializedLog = JSON.stringify([ 426 | logObj.type, 427 | logObj.tag, 428 | logObj.args, 429 | ]); 430 | const isSameLog = this._lastLog.serialized === serializedLog; 431 | this._lastLog.serialized = serializedLog; 432 | if (isSameLog) { 433 | this._lastLog.count = (this._lastLog.count || 0) + 1; 434 | if (this._lastLog.count > this.options.throttleMin) { 435 | // Auto-resolve when throttle is timed out 436 | this._lastLog.timeout = setTimeout( 437 | resolveLog, 438 | this.options.throttle, 439 | ); 440 | return; // SPAM! 441 | } 442 | } 443 | } catch { 444 | // Circular References 445 | } 446 | } 447 | 448 | resolveLog(true); 449 | } 450 | 451 | _log(logObj: LogObject) { 452 | for (const reporter of this.options.reporters) { 453 | reporter.log(logObj, { 454 | options: this.options, 455 | }); 456 | } 457 | } 458 | } 459 | 460 | function _normalizeLogLevel( 461 | input: LogLevel | LogType | undefined, 462 | types: any = {}, 463 | defaultLevel = 3, 464 | ) { 465 | if (input === undefined) { 466 | return defaultLevel; 467 | } 468 | if (typeof input === "number") { 469 | return input; 470 | } 471 | if (types[input] && types[input].level !== undefined) { 472 | return types[input].level; 473 | } 474 | return defaultLevel; 475 | } 476 | 477 | export interface LogFn { 478 | (message: InputLogObject | any, ...args: any[]): void; 479 | raw: (...args: any[]) => void; 480 | } 481 | export type ConsolaInstance = Consola & Record; 482 | 483 | // Legacy support 484 | // @ts-expect-error 485 | Consola.prototype.add = Consola.prototype.addReporter; 486 | // @ts-expect-error 487 | Consola.prototype.remove = Consola.prototype.removeReporter; 488 | // @ts-expect-error 489 | Consola.prototype.clear = Consola.prototype.removeReporter; 490 | // @ts-expect-error 491 | Consola.prototype.withScope = Consola.prototype.withTag; 492 | // @ts-expect-error 493 | Consola.prototype.mock = Consola.prototype.mockTypes; 494 | // @ts-expect-error 495 | Consola.prototype.pause = Consola.prototype.pauseLogs; 496 | // @ts-expect-error 497 | Consola.prototype.resume = Consola.prototype.resumeLogs; 498 | 499 | /** 500 | * Utility for creating a new Consola instance with optional configuration. 501 | * 502 | * @param {Partial} [options={}] - Optional configuration options for the new Consola instance. See {@link ConsolaOptions}. 503 | * @returns {ConsolaInstance} A new instance of Consola. See {@link ConsolaInstance}. 504 | */ 505 | export function createConsola( 506 | options: Partial = {}, 507 | ): ConsolaInstance { 508 | return new Consola(options) as ConsolaInstance; 509 | } 510 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | import { LogObject } from "./types"; 2 | 3 | /** 4 | * Defines the level of logs as specific numbers or special number types. 5 | * 6 | * @type {0 | 1 | 2 | 3 | 4 | 5 | (number & {})} LogLevel - Represents the log level. 7 | * @default 0 - Represents the default log level. 8 | */ 9 | export type LogLevel = 0 | 1 | 2 | 3 | 4 | 5 | (number & {}); 10 | 11 | /** 12 | * A mapping of `LogType` to its corresponding numeric log level. 13 | * 14 | * @type {Record} LogLevels - key-value pairs of log types to their numeric levels. See {@link LogType}. 15 | */ 16 | export const LogLevels: Record = { 17 | silent: Number.NEGATIVE_INFINITY, 18 | 19 | fatal: 0, 20 | error: 0, 21 | 22 | warn: 1, 23 | 24 | log: 2, 25 | info: 3, 26 | 27 | success: 3, 28 | fail: 3, 29 | ready: 3, 30 | start: 3, 31 | box: 3, 32 | 33 | debug: 4, 34 | 35 | trace: 5, 36 | 37 | verbose: Number.POSITIVE_INFINITY, 38 | }; 39 | 40 | /** 41 | * Lists the types of log messages supported by the system. 42 | * 43 | * @type {"silent" | "fatal" | "error" | "warn" | "log" | "info" | "success" | "fail" | "ready" | "start" | "box" | "debug" | "trace" | "verbose"} LogType - Represents the specific type of log message. 44 | */ 45 | export type LogType = 46 | // 0 47 | | "silent" 48 | | "fatal" 49 | | "error" 50 | // 1 51 | | "warn" 52 | // 2 53 | | "log" 54 | // 3 55 | | "info" 56 | | "success" 57 | | "fail" 58 | | "ready" 59 | | "start" 60 | | "box" 61 | // Verbose 62 | | "debug" 63 | | "trace" 64 | | "verbose"; 65 | 66 | /** 67 | * Maps `LogType` to a `Partial`, primarily defining the log level. 68 | * 69 | * @type {Record>} LogTypes - key-value pairs of log types to partial log objects, specifying log levels. See {@link LogType} and {@link LogObject}. 70 | */ 71 | export const LogTypes: Record> = { 72 | // Silent 73 | silent: { 74 | level: -1, 75 | }, 76 | 77 | // Level 0 78 | fatal: { 79 | level: LogLevels.fatal, 80 | }, 81 | error: { 82 | level: LogLevels.error, 83 | }, 84 | 85 | // Level 1 86 | warn: { 87 | level: LogLevels.warn, 88 | }, 89 | 90 | // Level 2 91 | log: { 92 | level: LogLevels.log, 93 | }, 94 | 95 | // Level 3 96 | info: { 97 | level: LogLevels.info, 98 | }, 99 | success: { 100 | level: LogLevels.success, 101 | }, 102 | fail: { 103 | level: LogLevels.fail, 104 | }, 105 | ready: { 106 | level: LogLevels.info, 107 | }, 108 | start: { 109 | level: LogLevels.info, 110 | }, 111 | box: { 112 | level: LogLevels.info, 113 | }, 114 | 115 | // Level 4 116 | debug: { 117 | level: LogLevels.debug, 118 | }, 119 | 120 | // Level 5 121 | trace: { 122 | level: LogLevels.trace, 123 | }, 124 | 125 | // Verbose 126 | verbose: { 127 | level: LogLevels.verbose, 128 | }, 129 | }; 130 | -------------------------------------------------------------------------------- /src/core.ts: -------------------------------------------------------------------------------- 1 | export { createConsola } from "./consola"; 2 | export * from "./shared"; 3 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { isDebug, isTest, isCI } from "std-env"; 2 | import { LogLevels, LogLevel } from "./constants"; 3 | import type { ConsolaOptions } from "./types"; 4 | import { BasicReporter } from "./reporters/basic"; 5 | import { FancyReporter } from "./reporters/fancy"; 6 | import { ConsolaInstance, createConsola as _createConsola } from "./consola"; 7 | 8 | export * from "./shared"; 9 | 10 | /** 11 | * Factory function to create a new Consola instance tailored for use in different environments. 12 | * It automatically adjusts logging levels based on environment variables and execution context. 13 | * 14 | * @param {Partial} [options={}] - Optional configuration options. See {@link ConsolaOptions}. 15 | * @returns {ConsolaInstance} A new Consola instance with configurations based on the given options and the execution environment. 16 | */ 17 | export function createConsola( 18 | options: Partial = {}, 19 | ): ConsolaInstance { 20 | // Log level 21 | let level = _getDefaultLogLevel(); 22 | if (process.env.CONSOLA_LEVEL) { 23 | level = Number.parseInt(process.env.CONSOLA_LEVEL) ?? level; 24 | } 25 | 26 | // Create new consola instance 27 | const consola = _createConsola({ 28 | level: level as LogLevel, 29 | defaults: { level }, 30 | stdout: process.stdout, 31 | stderr: process.stderr, 32 | prompt: (...args) => import("./prompt").then((m) => m.prompt(...args)), 33 | reporters: options.reporters || [ 34 | (options.fancy ?? !(isCI || isTest)) 35 | ? new FancyReporter() 36 | : new BasicReporter(), 37 | ], 38 | ...options, 39 | }); 40 | 41 | return consola; 42 | } 43 | 44 | function _getDefaultLogLevel() { 45 | if (isDebug) { 46 | return LogLevels.debug; 47 | } 48 | if (isTest) { 49 | return LogLevels.warn; 50 | } 51 | return LogLevels.info; 52 | } 53 | 54 | /** 55 | * A default instance of Consola, created and configured for immediate use. 56 | * This instance is configured based on the execution environment and the options provided. 57 | * 58 | * @type {ConsolaInstance} consola - The default Consola instance, ready to use. 59 | */ 60 | export const consola = createConsola(); 61 | 62 | export default consola; 63 | -------------------------------------------------------------------------------- /src/prompt.ts: -------------------------------------------------------------------------------- 1 | import { text, confirm, select, multiselect } from "@clack/prompts"; 2 | 3 | type SelectOption = { 4 | label: string; 5 | value: string; 6 | hint?: string; 7 | }; 8 | 9 | export const kCancel = Symbol.for("cancel"); 10 | 11 | export type PromptCommonOptions = { 12 | /** 13 | * Specify how to handle a cancelled prompt (e.g. by pressing Ctrl+C). 14 | * 15 | * Default strategy is `"default"`. 16 | * 17 | * - `"default"` - Resolve the promise with the `default` value or `initial` value. 18 | * - `"undefined`" - Resolve the promise with `undefined`. 19 | * - `"null"` - Resolve the promise with `null`. 20 | * - `"symbol"` - Resolve the promise with a symbol `Symbol.for("cancel")`. 21 | * - `"reject"` - Reject the promise with an error. 22 | */ 23 | cancel?: "reject" | "default" | "undefined" | "null" | "symbol"; 24 | }; 25 | 26 | export type TextPromptOptions = PromptCommonOptions & { 27 | /** 28 | * Specifies the prompt type as text. 29 | * @optional 30 | * @default "text" 31 | */ 32 | type?: "text"; 33 | 34 | /** 35 | * The default text value. 36 | * @optional 37 | */ 38 | default?: string; 39 | 40 | /** 41 | * A placeholder text displayed in the prompt. 42 | * @optional 43 | */ 44 | placeholder?: string; 45 | 46 | /** 47 | * The initial text value. 48 | * @optional 49 | */ 50 | initial?: string; 51 | }; 52 | 53 | export type ConfirmPromptOptions = PromptCommonOptions & { 54 | /** 55 | * Specifies the prompt type as confirm. 56 | */ 57 | type: "confirm"; 58 | 59 | /** 60 | * The initial value for the confirm prompt. 61 | * @optional 62 | */ 63 | initial?: boolean; 64 | }; 65 | 66 | export type SelectPromptOptions = PromptCommonOptions & { 67 | /** 68 | * Specifies the prompt type as select. 69 | */ 70 | type: "select"; 71 | 72 | /** 73 | * The initial value for the select prompt. 74 | * @optional 75 | */ 76 | initial?: string; 77 | 78 | /** 79 | * The options to select from. See {@link SelectOption}. 80 | */ 81 | options: (string | SelectOption)[]; 82 | }; 83 | 84 | export type MultiSelectOptions = PromptCommonOptions & { 85 | /** 86 | * Specifies the prompt type as multiselect. 87 | */ 88 | type: "multiselect"; 89 | 90 | /** 91 | * The options to select from. See {@link SelectOption}. 92 | */ 93 | initial?: string[]; 94 | 95 | /** 96 | * The options to select from. See {@link SelectOption}. 97 | */ 98 | options: (string | SelectOption)[]; 99 | 100 | /** 101 | * Whether the prompt requires at least one selection. 102 | */ 103 | required?: boolean; 104 | }; 105 | 106 | /** 107 | * Defines a combined type for all prompt options. 108 | */ 109 | export type PromptOptions = 110 | | TextPromptOptions 111 | | ConfirmPromptOptions 112 | | SelectPromptOptions 113 | | MultiSelectOptions; 114 | 115 | type inferPromptReturnType = 116 | T extends TextPromptOptions 117 | ? string 118 | : T extends ConfirmPromptOptions 119 | ? boolean 120 | : T extends SelectPromptOptions 121 | ? T["options"][number] extends SelectOption 122 | ? T["options"][number]["value"] 123 | : T["options"][number] 124 | : T extends MultiSelectOptions 125 | ? T["options"] 126 | : unknown; 127 | 128 | type inferPromptCancalReturnType = T extends { 129 | cancel: "reject"; 130 | } 131 | ? never 132 | : T extends { cancel: "default" } 133 | ? inferPromptReturnType 134 | : T extends { cancel: "undefined" } 135 | ? undefined 136 | : T extends { cancel: "null" } 137 | ? null 138 | : T extends { cancel: "symbol" } 139 | ? typeof kCancel 140 | : inferPromptReturnType /* default */; 141 | 142 | /** 143 | * Asynchronously prompts the user for input based on specified options. 144 | * Supports text, confirm, select and multi-select prompts. 145 | * 146 | * @param {string} message - The message to display in the prompt. 147 | * @param {PromptOptions} [opts={}] - The prompt options. See {@link PromptOptions}. 148 | * @returns {Promise>} - A promise that resolves with the user's response, the type of which is inferred from the options. See {@link inferPromptReturnType}. 149 | */ 150 | export async function prompt< 151 | _ = any, 152 | __ = any, 153 | T extends PromptOptions = TextPromptOptions, 154 | >( 155 | message: string, 156 | opts: PromptOptions = {}, 157 | ): Promise | inferPromptCancalReturnType> { 158 | const handleCancel = (value: unknown) => { 159 | if ( 160 | typeof value !== "symbol" || 161 | value.toString() !== "Symbol(clack:cancel)" 162 | ) { 163 | return value; 164 | } 165 | 166 | switch (opts.cancel) { 167 | case "reject": { 168 | const error = new Error("Prompt cancelled."); 169 | error.name = "ConsolaPromptCancelledError"; 170 | if (Error.captureStackTrace) { 171 | Error.captureStackTrace(error, prompt); 172 | } 173 | throw error; 174 | } 175 | case "undefined": { 176 | return undefined; 177 | } 178 | case "null": { 179 | return null; 180 | } 181 | case "symbol": { 182 | return kCancel; 183 | } 184 | default: 185 | case "default": { 186 | return (opts as TextPromptOptions).default ?? opts.initial; 187 | } 188 | } 189 | }; 190 | 191 | if (!opts.type || opts.type === "text") { 192 | return (await text({ 193 | message, 194 | defaultValue: opts.default, 195 | placeholder: opts.placeholder, 196 | initialValue: opts.initial as string, 197 | }).then(handleCancel)) as any; 198 | } 199 | 200 | if (opts.type === "confirm") { 201 | return (await confirm({ 202 | message, 203 | initialValue: opts.initial, 204 | }).then(handleCancel)) as any; 205 | } 206 | 207 | if (opts.type === "select") { 208 | return (await select({ 209 | message, 210 | options: opts.options.map((o) => 211 | typeof o === "string" ? { value: o, label: o } : o, 212 | ), 213 | initialValue: opts.initial, 214 | }).then(handleCancel)) as any; 215 | } 216 | 217 | if (opts.type === "multiselect") { 218 | return (await multiselect({ 219 | message, 220 | options: opts.options.map((o) => 221 | typeof o === "string" ? { value: o, label: o } : o, 222 | ), 223 | required: opts.required, 224 | initialValues: opts.initial, 225 | }).then(handleCancel)) as any; 226 | } 227 | 228 | throw new Error(`Unknown prompt type: ${opts.type}`); 229 | } 230 | -------------------------------------------------------------------------------- /src/reporters/basic.ts: -------------------------------------------------------------------------------- 1 | import { formatWithOptions } from "node:util"; 2 | import type { 3 | LogObject, 4 | ConsolaReporter, 5 | FormatOptions, 6 | ConsolaOptions, 7 | } from "../types"; 8 | import { parseStack } from "../utils/error"; 9 | import { writeStream } from "../utils/stream"; 10 | 11 | const bracket = (x: string) => (x ? `[${x}]` : ""); 12 | 13 | export class BasicReporter implements ConsolaReporter { 14 | formatStack(stack: string, message: string, opts: FormatOptions) { 15 | const indent = " ".repeat((opts?.errorLevel || 0) + 1); 16 | return indent + parseStack(stack, message).join(`\n${indent}`); 17 | } 18 | 19 | formatError(err: any, opts: FormatOptions): string { 20 | const message = err.message ?? formatWithOptions(opts, err); 21 | const stack = err.stack ? this.formatStack(err.stack, message, opts) : ""; 22 | 23 | const level = opts?.errorLevel || 0; 24 | const causedPrefix = level > 0 ? `${" ".repeat(level)}[cause]: ` : ""; 25 | const causedError = err.cause 26 | ? "\n\n" + this.formatError(err.cause, { ...opts, errorLevel: level + 1 }) 27 | : ""; 28 | 29 | return causedPrefix + message + "\n" + stack + causedError; 30 | } 31 | 32 | formatArgs(args: any[], opts: FormatOptions) { 33 | const _args = args.map((arg) => { 34 | if (arg && typeof arg.stack === "string") { 35 | return this.formatError(arg, opts); 36 | } 37 | return arg; 38 | }); 39 | 40 | // Only supported with Node >= 10 41 | // https://nodejs.org/api/util.html#util_util_inspect_object_options 42 | return formatWithOptions(opts, ..._args); 43 | } 44 | 45 | formatDate(date: Date, opts: FormatOptions) { 46 | return opts.date ? date.toLocaleTimeString() : ""; 47 | } 48 | 49 | filterAndJoin(arr: any[]) { 50 | return arr.filter(Boolean).join(" "); 51 | } 52 | 53 | formatLogObj(logObj: LogObject, opts: FormatOptions) { 54 | const message = this.formatArgs(logObj.args, opts); 55 | 56 | if (logObj.type === "box") { 57 | return ( 58 | "\n" + 59 | [ 60 | bracket(logObj.tag), 61 | logObj.title && logObj.title, 62 | ...message.split("\n"), 63 | ] 64 | .filter(Boolean) 65 | .map((l) => " > " + l) 66 | .join("\n") + 67 | "\n" 68 | ); 69 | } 70 | 71 | return this.filterAndJoin([ 72 | bracket(logObj.type), 73 | bracket(logObj.tag), 74 | message, 75 | ]); 76 | } 77 | 78 | log(logObj: LogObject, ctx: { options: ConsolaOptions }) { 79 | const line = this.formatLogObj(logObj, { 80 | columns: (ctx.options.stdout as any).columns || 0, 81 | ...ctx.options.formatOptions, 82 | }); 83 | 84 | return writeStream( 85 | line + "\n", 86 | logObj.level < 2 87 | ? ctx.options.stderr || process.stderr 88 | : ctx.options.stdout || process.stdout, 89 | ); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/reporters/browser.ts: -------------------------------------------------------------------------------- 1 | import { LogObject } from "../types"; 2 | 3 | export class BrowserReporter { 4 | options: any; 5 | defaultColor: string; 6 | levelColorMap: Record; 7 | typeColorMap: Record; 8 | 9 | constructor(options: any) { 10 | this.options = { ...options }; 11 | 12 | this.defaultColor = "#7f8c8d"; // Gray 13 | this.levelColorMap = { 14 | 0: "#c0392b", // Red 15 | 1: "#f39c12", // Yellow 16 | 3: "#00BCD4", // Cyan 17 | }; 18 | this.typeColorMap = { 19 | success: "#2ecc71", // Green 20 | }; 21 | } 22 | 23 | _getLogFn(level: number) { 24 | if (level < 1) { 25 | return (console as any).__error || console.error; 26 | } 27 | if (level === 1) { 28 | return (console as any).__warn || console.warn; 29 | } 30 | return (console as any).__log || console.log; 31 | } 32 | 33 | log(logObj: LogObject) { 34 | const consoleLogFn = this._getLogFn(logObj.level); 35 | 36 | // Type 37 | const type = logObj.type === "log" ? "" : logObj.type; 38 | 39 | // Tag 40 | const tag = logObj.tag || ""; 41 | 42 | // Styles 43 | const color = 44 | this.typeColorMap[logObj.type] || 45 | this.levelColorMap[logObj.level] || 46 | this.defaultColor; 47 | const style = ` 48 | background: ${color}; 49 | border-radius: 0.5em; 50 | color: white; 51 | font-weight: bold; 52 | padding: 2px 0.5em; 53 | `; 54 | 55 | const badge = `%c${[tag, type].filter(Boolean).join(":")}`; 56 | 57 | // Log to the console 58 | if (typeof logObj.args[0] === "string") { 59 | consoleLogFn( 60 | `${badge}%c ${logObj.args[0]}`, 61 | style, 62 | // Empty string as style resets to default console style 63 | "", 64 | ...logObj.args.slice(1), 65 | ); 66 | } else { 67 | consoleLogFn(badge, style, ...logObj.args); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/reporters/fancy.ts: -------------------------------------------------------------------------------- 1 | import _stringWidth from "string-width"; 2 | import isUnicodeSupported from "is-unicode-supported"; 3 | import { colors } from "../utils/color"; 4 | import { parseStack } from "../utils/error"; 5 | import { FormatOptions, LogObject } from "../types"; 6 | import { LogLevel, LogType } from "../constants"; 7 | import { BoxOpts, box } from "../utils/box"; 8 | import { stripAnsi } from "../utils"; 9 | import { BasicReporter } from "./basic"; 10 | 11 | export const TYPE_COLOR_MAP: { [k in LogType]?: string } = { 12 | info: "cyan", 13 | fail: "red", 14 | success: "green", 15 | ready: "green", 16 | start: "magenta", 17 | }; 18 | 19 | export const LEVEL_COLOR_MAP: { [k in LogLevel]?: string } = { 20 | 0: "red", 21 | 1: "yellow", 22 | }; 23 | 24 | const unicode = isUnicodeSupported(); 25 | const s = (c: string, fallback: string) => (unicode ? c : fallback); 26 | const TYPE_ICONS: { [k in LogType]?: string } = { 27 | error: s("✖", "×"), 28 | fatal: s("✖", "×"), 29 | ready: s("✔", "√"), 30 | warn: s("⚠", "‼"), 31 | info: s("ℹ", "i"), 32 | success: s("✔", "√"), 33 | debug: s("⚙", "D"), 34 | trace: s("→", "→"), 35 | fail: s("✖", "×"), 36 | start: s("◐", "o"), 37 | log: "", 38 | }; 39 | 40 | function stringWidth(str: string) { 41 | // https://github.com/unjs/consola/issues/204 42 | const hasICU = typeof Intl === "object"; 43 | if (!hasICU || !Intl.Segmenter) { 44 | return stripAnsi(str).length; 45 | } 46 | return _stringWidth(str); 47 | } 48 | 49 | export class FancyReporter extends BasicReporter { 50 | formatStack(stack: string, message: string, opts?: FormatOptions) { 51 | const indent = " ".repeat((opts?.errorLevel || 0) + 1); 52 | return ( 53 | `\n${indent}` + 54 | parseStack(stack, message) 55 | .map( 56 | (line) => 57 | " " + 58 | line 59 | .replace(/^at +/, (m) => colors.gray(m)) 60 | .replace(/\((.+)\)/, (_, m) => `(${colors.cyan(m)})`), 61 | ) 62 | .join(`\n${indent}`) 63 | ); 64 | } 65 | 66 | formatType(logObj: LogObject, isBadge: boolean, opts: FormatOptions) { 67 | const typeColor = 68 | (TYPE_COLOR_MAP as any)[logObj.type] || 69 | (LEVEL_COLOR_MAP as any)[logObj.level] || 70 | "gray"; 71 | 72 | if (isBadge) { 73 | return getBgColor(typeColor)( 74 | colors.black(` ${logObj.type.toUpperCase()} `), 75 | ); 76 | } 77 | 78 | const _type = 79 | typeof (TYPE_ICONS as any)[logObj.type] === "string" 80 | ? (TYPE_ICONS as any)[logObj.type] 81 | : (logObj as any).icon || logObj.type; 82 | 83 | return _type ? getColor(typeColor)(_type) : ""; 84 | } 85 | 86 | formatLogObj(logObj: LogObject, opts: FormatOptions) { 87 | const [message, ...additional] = this.formatArgs(logObj.args, opts).split( 88 | "\n", 89 | ); 90 | 91 | if (logObj.type === "box") { 92 | return box( 93 | characterFormat( 94 | message + (additional.length > 0 ? "\n" + additional.join("\n") : ""), 95 | ), 96 | { 97 | title: logObj.title 98 | ? characterFormat(logObj.title as string) 99 | : undefined, 100 | style: logObj.style as BoxOpts["style"], 101 | }, 102 | ); 103 | } 104 | 105 | const date = this.formatDate(logObj.date, opts); 106 | const coloredDate = date && colors.gray(date); 107 | 108 | const isBadge = (logObj.badge as boolean) ?? logObj.level < 2; 109 | const type = this.formatType(logObj, isBadge, opts); 110 | 111 | const tag = logObj.tag ? colors.gray(logObj.tag) : ""; 112 | 113 | let line; 114 | const left = this.filterAndJoin([type, characterFormat(message)]); 115 | const right = this.filterAndJoin(opts.columns ? [tag, coloredDate] : [tag]); 116 | const space = 117 | (opts.columns || 0) - stringWidth(left) - stringWidth(right) - 2; 118 | 119 | line = 120 | space > 0 && (opts.columns || 0) >= 80 121 | ? left + " ".repeat(space) + right 122 | : (right ? `${colors.gray(`[${right}]`)} ` : "") + left; 123 | 124 | line += characterFormat( 125 | additional.length > 0 ? "\n" + additional.join("\n") : "", 126 | ); 127 | 128 | if (logObj.type === "trace") { 129 | const _err = new Error("Trace: " + logObj.message); 130 | line += this.formatStack(_err.stack || "", _err.message); 131 | } 132 | 133 | return isBadge ? "\n" + line + "\n" : line; 134 | } 135 | } 136 | 137 | function characterFormat(str: string) { 138 | return ( 139 | str 140 | // highlight backticks 141 | .replace(/`([^`]+)`/gm, (_, m) => colors.cyan(m)) 142 | // underline underscores 143 | .replace(/\s+_([^_]+)_\s+/gm, (_, m) => ` ${colors.underline(m)} `) 144 | ); 145 | } 146 | 147 | function getColor(color = "white") { 148 | return (colors as any)[color] || colors.white; 149 | } 150 | 151 | function getBgColor(color = "bgWhite") { 152 | return ( 153 | (colors as any)[`bg${color[0].toUpperCase()}${color.slice(1)}`] || 154 | colors.bgWhite 155 | ); 156 | } 157 | -------------------------------------------------------------------------------- /src/shared.ts: -------------------------------------------------------------------------------- 1 | export { LogLevels, LogTypes } from "./constants"; 2 | export { Consola } from "./consola"; 3 | 4 | export type * from "./types"; 5 | export type { ConsolaInstance } from "./consola"; 6 | export type { LogLevel, LogType } from "./constants"; 7 | export type { 8 | PromptOptions, 9 | ConfirmPromptOptions, 10 | MultiSelectOptions, 11 | SelectPromptOptions, 12 | TextPromptOptions, 13 | } from "./prompt"; 14 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type { LogLevel, LogType } from "./constants"; 2 | 3 | export interface ConsolaOptions { 4 | /** 5 | * An array of ConsolaReporter instances used to handle and output log messages. 6 | */ 7 | reporters: ConsolaReporter[]; 8 | 9 | /** 10 | * A record mapping LogType to InputLogObject, defining the log configuration for each log type. 11 | * See {@link LogType} and {@link InputLogObject}. 12 | */ 13 | types: Record; 14 | 15 | /** 16 | * The minimum log level to output. See {@link LogLevel}. 17 | */ 18 | level: LogLevel; 19 | 20 | /** 21 | * Default properties applied to all log messages unless overridden. See {@link InputLogObject}. 22 | */ 23 | defaults: InputLogObject; 24 | 25 | /** 26 | * The maximum number of times a log message can be repeated within a given timeframe. 27 | */ 28 | throttle: number; 29 | 30 | /** 31 | * The minimum time in milliseconds that must elapse before a throttled log message can be logged again. 32 | */ 33 | throttleMin: number; 34 | 35 | /** 36 | * The Node.js writable stream for standard output. See {@link NodeJS.WriteStream}. 37 | * @optional 38 | */ 39 | stdout?: NodeJS.WriteStream; 40 | 41 | /** 42 | * The Node.js writeable stream for standard error output. See {@link NodeJS.WriteStream}. 43 | * @optional 44 | */ 45 | stderr?: NodeJS.WriteStream; 46 | 47 | /** 48 | * A function that allows you to mock log messages for testing purposes. 49 | * @optional 50 | */ 51 | mockFn?: (type: LogType, defaults: InputLogObject) => (...args: any) => void; 52 | 53 | /** 54 | * Custom prompt function to use. It can be undefined. 55 | * @optional 56 | */ 57 | prompt?: typeof import("./prompt").prompt | undefined; 58 | 59 | /** 60 | * Configuration options for formatting log messages. See {@link FormatOptions}. 61 | */ 62 | formatOptions: FormatOptions; 63 | } 64 | 65 | /** 66 | * @see https://nodejs.org/api/util.html#util_util_inspect_object_showhidden_depth_colors 67 | */ 68 | export interface FormatOptions { 69 | /** 70 | * The maximum number of columns to output, affects formatting. 71 | * @optional 72 | */ 73 | columns?: number; 74 | 75 | /** 76 | * Whether to include timestamp information in log messages. 77 | * @optional 78 | */ 79 | date?: boolean; 80 | 81 | /** 82 | * Whether to use colors in the output. 83 | * @optional 84 | */ 85 | colors?: boolean; 86 | 87 | /** 88 | * Specifies whether or not the output should be compact. Accepts a boolean or numeric level of compactness. 89 | * @optional 90 | */ 91 | compact?: boolean | number; 92 | 93 | /** 94 | * Error cause level. 95 | */ 96 | errorLevel?: number; 97 | 98 | /** 99 | * Allows additional custom formatting options. 100 | */ 101 | [key: string]: unknown; 102 | } 103 | 104 | export interface InputLogObject { 105 | /** 106 | * The logging level of the message. See {@link LogLevel}. 107 | * @optional 108 | */ 109 | level?: LogLevel; 110 | 111 | /** 112 | * A string tag to categorise or identify the log message. 113 | * @optional 114 | */ 115 | tag?: string; 116 | 117 | /** 118 | * The type of log message, which affects how it's processed and displayed. See {@link LogType}. 119 | * @optional 120 | */ 121 | type?: LogType; 122 | 123 | /** 124 | * The main log message text. 125 | * @optional 126 | */ 127 | message?: string; 128 | 129 | /** 130 | * Additional text or texts to be logged with the message. 131 | * @optional 132 | */ 133 | additional?: string | string[]; 134 | 135 | /** 136 | * Additional arguments to be logged with the message. 137 | * @optional 138 | */ 139 | args?: any[]; 140 | 141 | /** 142 | * The date and time when the log message was created. 143 | * @optional 144 | */ 145 | date?: Date; 146 | } 147 | 148 | export interface LogObject extends InputLogObject { 149 | /** 150 | * The logging level of the message, overridden if required. See {@link LogLevel}. 151 | */ 152 | level: LogLevel; 153 | 154 | /** 155 | * The type of log message, overridden if required. See {@link LogType}. 156 | */ 157 | type: LogType; 158 | 159 | /** 160 | * A string tag to categorise or identify the log message, overridden if necessary. 161 | */ 162 | tag: string; 163 | 164 | /** 165 | * Additional arguments to be logged with the message, overridden if necessary. 166 | */ 167 | args: any[]; 168 | 169 | /** 170 | * The date and time the log message was created, overridden if necessary. 171 | */ 172 | date: Date; 173 | 174 | /** 175 | * Allows additional custom properties to be set on the log object. 176 | */ 177 | [key: string]: unknown; 178 | } 179 | 180 | export interface ConsolaReporter { 181 | /** 182 | * Defines how a log message is processed and displayed by this reporter. 183 | * @param logObj The LogObject containing the log information to process. See {@link LogObject}. 184 | * @param ctx An object containing context information such as options. See {@link ConsolaOptions}. 185 | */ 186 | log: ( 187 | logObj: LogObject, 188 | ctx: { 189 | options: ConsolaOptions; 190 | }, 191 | ) => void; 192 | } 193 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | export * from "./utils/box"; 2 | export * from "./utils/color"; 3 | export { 4 | stripAnsi, 5 | centerAlign, 6 | rightAlign, 7 | leftAlign, 8 | align, 9 | } from "./utils/string"; 10 | export { 11 | type TreeItemObject, 12 | type TreeItem, 13 | type TreeOptions, 14 | formatTree, 15 | } from "./utils/tree"; 16 | -------------------------------------------------------------------------------- /src/utils/box.ts: -------------------------------------------------------------------------------- 1 | import { getColor } from "./color"; 2 | import { stripAnsi } from "./string"; 3 | 4 | export type BoxBorderStyle = { 5 | /** 6 | * Top left corner 7 | * @example `┌` 8 | * @example `╔` 9 | * @example `╓` 10 | */ 11 | tl: string; 12 | /** 13 | * Top right corner 14 | * @example `┐` 15 | * @example `╗` 16 | * @example `╖` 17 | */ 18 | tr: string; 19 | /** 20 | * Bottom left corner 21 | * @example `└` 22 | * @example `╚` 23 | * @example `╙` 24 | */ 25 | bl: string; 26 | /** 27 | * Bottom right corner 28 | * @example `┘` 29 | * @example `╝` 30 | * @example `╜` 31 | */ 32 | br: string; 33 | /** 34 | * Horizontal line 35 | * @example `─` 36 | * @example `═` 37 | * @example `─` 38 | */ 39 | h: string; 40 | /** 41 | * Vertical line 42 | * @example `│` 43 | * @example `║` 44 | * @example `║` 45 | */ 46 | v: string; 47 | }; 48 | 49 | const boxStylePresets: Record = { 50 | solid: { 51 | tl: "┌", 52 | tr: "┐", 53 | bl: "└", 54 | br: "┘", 55 | h: "─", 56 | v: "│", 57 | }, 58 | double: { 59 | tl: "╔", 60 | tr: "╗", 61 | bl: "╚", 62 | br: "╝", 63 | h: "═", 64 | v: "║", 65 | }, 66 | doubleSingle: { 67 | tl: "╓", 68 | tr: "╖", 69 | bl: "╙", 70 | br: "╜", 71 | h: "─", 72 | v: "║", 73 | }, 74 | doubleSingleRounded: { 75 | tl: "╭", 76 | tr: "╮", 77 | bl: "╰", 78 | br: "╯", 79 | h: "─", 80 | v: "║", 81 | }, 82 | singleThick: { 83 | tl: "┏", 84 | tr: "┓", 85 | bl: "┗", 86 | br: "┛", 87 | h: "━", 88 | v: "┃", 89 | }, 90 | singleDouble: { 91 | tl: "╒", 92 | tr: "╕", 93 | bl: "╘", 94 | br: "╛", 95 | h: "═", 96 | v: "│", 97 | }, 98 | singleDoubleRounded: { 99 | tl: "╭", 100 | tr: "╮", 101 | bl: "╰", 102 | br: "╯", 103 | h: "═", 104 | v: "│", 105 | }, 106 | rounded: { 107 | tl: "╭", 108 | tr: "╮", 109 | bl: "╰", 110 | br: "╯", 111 | h: "─", 112 | v: "│", 113 | }, 114 | }; 115 | 116 | export type BoxStyle = { 117 | /** 118 | * The border color 119 | * @default 'white' 120 | */ 121 | borderColor: 122 | | "black" 123 | | "red" 124 | | "green" 125 | | "yellow" 126 | | "blue" 127 | | "magenta" 128 | | "cyan" 129 | | "white" 130 | | "gray" 131 | | "blackBright" 132 | | "redBright" 133 | | "greenBright" 134 | | "yellowBright" 135 | | "blueBright" 136 | | "magentaBright" 137 | | "cyanBright" 138 | | "whiteBright"; 139 | 140 | /** 141 | * The border style 142 | * @default 'solid' 143 | * @example 'single-double-rounded' 144 | * @example 145 | * ```ts 146 | * { 147 | * tl: '┌', 148 | * tr: '┐', 149 | * bl: '└', 150 | * br: '┘', 151 | * h: '─', 152 | * v: '│', 153 | * } 154 | * ``` 155 | */ 156 | borderStyle: BoxBorderStyle | keyof typeof boxStylePresets; 157 | 158 | /** 159 | * The vertical alignment of the text 160 | * @default 'center' 161 | */ 162 | valign: "top" | "center" | "bottom"; 163 | 164 | /** 165 | * The padding of the box 166 | * @default 2 167 | */ 168 | padding: number; 169 | 170 | /** 171 | * The left margin of the box 172 | * @default 1 173 | */ 174 | marginLeft: number; 175 | 176 | /** 177 | * The top margin of the box 178 | * @default 1 179 | */ 180 | marginTop: number; 181 | 182 | /** 183 | * The top margin of the box 184 | * @default 1 185 | */ 186 | marginBottom: number; 187 | }; 188 | 189 | /** 190 | * The border options of the box 191 | */ 192 | export type BoxOpts = { 193 | /** 194 | * Title that will be displayed on top of the box 195 | * @example 'Hello World' 196 | * @example 'Hello {name}' 197 | */ 198 | title?: string; 199 | 200 | style?: Partial; 201 | }; 202 | 203 | /** 204 | * The default style applied to a box if no custom style is specified. See {@link BoxStyle}. 205 | */ 206 | const defaultStyle: BoxStyle = { 207 | borderColor: "white", 208 | borderStyle: "rounded", 209 | valign: "center", 210 | padding: 2, 211 | marginLeft: 1, 212 | marginTop: 1, 213 | marginBottom: 1, 214 | }; 215 | 216 | /** 217 | * Creates a styled box with text content, customisable via options. 218 | * @param {string} text - The text to display in the box. 219 | * @param {BoxOpts} [_opts={}] - Optional settings for the appearance and behaviour of the box. See {@link BoxOpts}. 220 | * @returns {string} The formatted box as a string, ready for printing or logging. 221 | */ 222 | export function box(text: string, _opts: BoxOpts = {}) { 223 | const opts = { 224 | ..._opts, 225 | style: { 226 | ...defaultStyle, 227 | ..._opts.style, 228 | }, 229 | }; 230 | 231 | // Split the text into lines 232 | const textLines = text.split("\n"); 233 | 234 | // Create the box 235 | const boxLines = []; 236 | 237 | // Get the characters for the box and colorize 238 | const _color = getColor(opts.style.borderColor); 239 | const borderStyle = { 240 | ...(typeof opts.style.borderStyle === "string" 241 | ? boxStylePresets[ 242 | opts.style.borderStyle as keyof typeof boxStylePresets 243 | ] || boxStylePresets.solid 244 | : opts.style.borderStyle), 245 | }; 246 | if (_color) { 247 | for (const key in borderStyle) { 248 | borderStyle[key as keyof typeof borderStyle] = _color( 249 | borderStyle[key as keyof typeof borderStyle], 250 | ); 251 | } 252 | } 253 | 254 | // Calculate the width and height of the box 255 | const paddingOffset = 256 | opts.style.padding % 2 === 0 ? opts.style.padding : opts.style.padding + 1; 257 | const height = textLines.length + paddingOffset; 258 | const width = 259 | Math.max( 260 | ...textLines.map((line) => stripAnsi(line).length), 261 | opts.title ? stripAnsi(opts.title).length : 0, 262 | ) + paddingOffset; 263 | const widthOffset = width + paddingOffset; 264 | 265 | const leftSpace = 266 | opts.style.marginLeft > 0 ? " ".repeat(opts.style.marginLeft) : ""; 267 | 268 | // Top line 269 | if (opts.style.marginTop > 0) { 270 | boxLines.push("".repeat(opts.style.marginTop)); 271 | } 272 | // Include the title if it exists with borders 273 | if (opts.title) { 274 | const title = _color ? _color(opts.title) : opts.title; 275 | const left = borderStyle.h.repeat( 276 | Math.floor((width - stripAnsi(opts.title).length) / 2), 277 | ); 278 | const right = borderStyle.h.repeat( 279 | width - 280 | stripAnsi(opts.title).length - 281 | stripAnsi(left).length + 282 | paddingOffset, 283 | ); 284 | boxLines.push( 285 | `${leftSpace}${borderStyle.tl}${left}${title}${right}${borderStyle.tr}`, 286 | ); 287 | } else { 288 | boxLines.push( 289 | `${leftSpace}${borderStyle.tl}${borderStyle.h.repeat(widthOffset)}${ 290 | borderStyle.tr 291 | }`, 292 | ); 293 | } 294 | 295 | // Middle lines 296 | const valignOffset = 297 | opts.style.valign === "center" 298 | ? Math.floor((height - textLines.length) / 2) 299 | : opts.style.valign === "top" // eslint-disable-line unicorn/no-nested-ternary 300 | ? height - textLines.length - paddingOffset 301 | : height - textLines.length; 302 | 303 | for (let i = 0; i < height; i++) { 304 | if (i < valignOffset || i >= valignOffset + textLines.length) { 305 | // Empty line 306 | boxLines.push( 307 | `${leftSpace}${borderStyle.v}${" ".repeat(widthOffset)}${ 308 | borderStyle.v 309 | }`, 310 | ); 311 | } else { 312 | // Text line 313 | const line = textLines[i - valignOffset]; 314 | const left = " ".repeat(paddingOffset); 315 | const right = " ".repeat(width - stripAnsi(line).length); 316 | boxLines.push( 317 | `${leftSpace}${borderStyle.v}${left}${line}${right}${borderStyle.v}`, 318 | ); 319 | } 320 | } 321 | 322 | // Bottom line 323 | boxLines.push( 324 | `${leftSpace}${borderStyle.bl}${borderStyle.h.repeat(widthOffset)}${ 325 | borderStyle.br 326 | }`, 327 | ); 328 | if (opts.style.marginBottom > 0) { 329 | boxLines.push("".repeat(opts.style.marginBottom)); 330 | } 331 | 332 | return boxLines.join("\n"); 333 | } 334 | -------------------------------------------------------------------------------- /src/utils/color.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Based on https://github.com/jorgebucaran/colorette 3 | * Read LICENSE file for more information 4 | * https://github.com/jorgebucaran/colorette/blob/20fc196d07d0f87c61e0256eadd7831c79b24108/index.js 5 | */ 6 | 7 | import * as tty from "node:tty"; 8 | 9 | // TODO: Migrate to std-env 10 | const { 11 | env = {}, 12 | argv = [], 13 | platform = "", 14 | } = typeof process === "undefined" ? {} : process; 15 | const isDisabled = "NO_COLOR" in env || argv.includes("--no-color"); 16 | const isForced = "FORCE_COLOR" in env || argv.includes("--color"); 17 | const isWindows = platform === "win32"; 18 | const isDumbTerminal = env.TERM === "dumb"; 19 | const isCompatibleTerminal = 20 | tty && tty.isatty && tty.isatty(1) && env.TERM && !isDumbTerminal; 21 | const isCI = 22 | "CI" in env && 23 | ("GITHUB_ACTIONS" in env || "GITLAB_CI" in env || "CIRCLECI" in env); 24 | 25 | /** 26 | * Determines support for terminal colours based on the environment and capabilities of the terminal. 27 | * @type {boolean} isColorSupported - Indicates whether colour support is enabled in the terminal. 28 | */ 29 | const isColorSupported = 30 | !isDisabled && 31 | (isForced || (isWindows && !isDumbTerminal) || isCompatibleTerminal || isCI); 32 | 33 | function replaceClose( 34 | index: number, 35 | string: string, 36 | close: string, 37 | replace: string, 38 | head = string.slice(0, Math.max(0, index)) + replace, 39 | tail = string.slice(Math.max(0, index + close.length)), 40 | next = tail.indexOf(close), 41 | ): string { 42 | return head + (next < 0 ? tail : replaceClose(next, tail, close, replace)); 43 | } 44 | 45 | function clearBleed( 46 | index: number, 47 | string: string, 48 | open: string, 49 | close: string, 50 | replace: string, 51 | ) { 52 | return index < 0 53 | ? open + string + close 54 | : open + replaceClose(index, string, close, replace) + close; 55 | } 56 | 57 | function filterEmpty( 58 | open: string, 59 | close: string, 60 | replace = open, 61 | at = open.length + 1, 62 | ) { 63 | return (string: string) => 64 | string || !(string === "" || string === undefined) 65 | ? clearBleed( 66 | ("" + string).indexOf(close, at), 67 | string, 68 | open, 69 | close, 70 | replace, 71 | ) 72 | : ""; 73 | } 74 | 75 | function init(open: number, close: number, replace?: string) { 76 | return filterEmpty(`\u001B[${open}m`, `\u001B[${close}m`, replace); 77 | } 78 | 79 | const colorDefs = { 80 | reset: init(0, 0), 81 | bold: init(1, 22, "\u001B[22m\u001B[1m"), 82 | dim: init(2, 22, "\u001B[22m\u001B[2m"), 83 | italic: init(3, 23), 84 | underline: init(4, 24), 85 | inverse: init(7, 27), 86 | hidden: init(8, 28), 87 | strikethrough: init(9, 29), 88 | black: init(30, 39), 89 | red: init(31, 39), 90 | green: init(32, 39), 91 | yellow: init(33, 39), 92 | blue: init(34, 39), 93 | magenta: init(35, 39), 94 | cyan: init(36, 39), 95 | white: init(37, 39), 96 | gray: init(90, 39), 97 | bgBlack: init(40, 49), 98 | bgRed: init(41, 49), 99 | bgGreen: init(42, 49), 100 | bgYellow: init(43, 49), 101 | bgBlue: init(44, 49), 102 | bgMagenta: init(45, 49), 103 | bgCyan: init(46, 49), 104 | bgWhite: init(47, 49), 105 | blackBright: init(90, 39), 106 | redBright: init(91, 39), 107 | greenBright: init(92, 39), 108 | yellowBright: init(93, 39), 109 | blueBright: init(94, 39), 110 | magentaBright: init(95, 39), 111 | cyanBright: init(96, 39), 112 | whiteBright: init(97, 39), 113 | bgBlackBright: init(100, 49), 114 | bgRedBright: init(101, 49), 115 | bgGreenBright: init(102, 49), 116 | bgYellowBright: init(103, 49), 117 | bgBlueBright: init(104, 49), 118 | bgMagentaBright: init(105, 49), 119 | bgCyanBright: init(106, 49), 120 | bgWhiteBright: init(107, 49), 121 | }; 122 | 123 | export type ColorName = keyof typeof colorDefs; 124 | export type ColorFunction = (text: string | number) => string; 125 | 126 | /** 127 | * Creates an object that maps colour names to their respective colour functions, 128 | * based on whether or not colour support is enabled. 129 | * @param {boolean} [useColor=isColorSupported] - Specifies whether to use colour functions or fallback to plain strings. 130 | * @returns {Record} An object where keys are colour names and values are functions to apply those colours. See {@link ColorFunction}. 131 | */ 132 | function createColors(useColor = isColorSupported) { 133 | return useColor 134 | ? colorDefs 135 | : Object.fromEntries(Object.keys(colorDefs).map((key) => [key, String])); 136 | } 137 | 138 | /** 139 | * An object containing functions for colouring text. Each function corresponds to a terminal colour. See {@link ColorName} for available colours. 140 | */ 141 | export const colors = createColors() as Record; 142 | 143 | /** 144 | * Gets a colour function by name, with an option for a fallback colour if the requested colour is not found. 145 | * @param {ColorName} color - The name of the colour function to get. See {@link ColorName}. 146 | * @param {ColorName} [fallback="reset"] - The name of the fallback colour function if the requested colour is not found. See {@link ColorName}. 147 | * @returns {ColorFunction} The colour function that corresponds to the requested colour, or the fallback colour function. See {@link ColorFunction}. 148 | */ 149 | export function getColor( 150 | color: ColorName, 151 | fallback: ColorName = "reset", 152 | ): ColorFunction { 153 | return colors[color] || colors[fallback]; 154 | } 155 | 156 | /** 157 | * Applies a specified colour to a given text string or number. 158 | * @param {ColorName} color - The colour to apply. See {@link ColorName}. 159 | * @param {string | number} text - The text to colour. 160 | * @returns {string} The coloured text. 161 | */ 162 | export function colorize(color: ColorName, text: string | number): string { 163 | return getColor(color)(text); 164 | } 165 | -------------------------------------------------------------------------------- /src/utils/error.ts: -------------------------------------------------------------------------------- 1 | import { sep } from "node:path"; 2 | 3 | /** 4 | * Parses a stack trace string and normalises its paths by removing the current working directory and the "file://" protocol. 5 | * @param {string} stack - The stack trace string. 6 | * @returns {string[]} An array of stack trace lines with normalised paths. 7 | */ 8 | export function parseStack(stack: string, message: string) { 9 | const cwd = process.cwd() + sep; 10 | 11 | const lines = stack 12 | .split("\n") 13 | .splice(message.split("\n").length) 14 | .map((l) => l.trim().replace("file://", "").replace(cwd, "")); 15 | 16 | return lines; 17 | } 18 | -------------------------------------------------------------------------------- /src/utils/format.ts: -------------------------------------------------------------------------------- 1 | import { vsprintf } from "printj"; 2 | 3 | // Predefined rules for replacing format arguments 4 | const FORMAT_ARGS = [ 5 | ["additional", 5], 6 | ["message", 4], 7 | ["type", 2], 8 | ["date", 1], 9 | ["tag", 3], 10 | ]; // .sort((a, b) => b[0].length - a[0].length) 11 | 12 | // Caches compiled format strings for reuse 13 | const _compileCache: any = {}; 14 | // process.on('beforeExit', () => { console.log(_compileCache) }) 15 | 16 | /** 17 | * Compiles a format string by replacing placeholders with appropriate position indices. 18 | * Caches compiled formats for efficiency. 19 | * @param {string} format - The format string containing the placeholders to replace. 20 | * @returns {string} The compiled format string with placeholders replaced by positional indices. 21 | */ 22 | export function compileFormat(format: string) { 23 | if (_compileCache[format]) { 24 | return _compileCache[format]; 25 | } 26 | 27 | let _format = format; 28 | for (const arg of FORMAT_ARGS) { 29 | _format = _format.replace( 30 | new RegExp("([%-])" + arg[0], "g"), 31 | "$1" + arg[1], 32 | ); 33 | } 34 | 35 | _compileCache[format] = _format; 36 | return _format; 37 | } 38 | 39 | /** 40 | * Formats a string according to a custom format, using vsprintf for string formatting. 41 | * @param {string} format - The custom format string. 42 | * @param {any[]} argv - The arguments to format into the string. 43 | * @returns {string} The formatted string. 44 | */ 45 | export function formatString(format: string, argv: any) { 46 | return vsprintf(compileFormat(format), argv); 47 | } 48 | -------------------------------------------------------------------------------- /src/utils/log.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Checks if the given argument is a simple JavaScript object. 3 | * @param {any} obj - The object to test. 4 | * @returns {boolean} `true` if the argument is a plain object, otherwise `false`. 5 | */ 6 | export function isPlainObject(obj: any) { 7 | return Object.prototype.toString.call(obj) === "[object Object]"; 8 | } 9 | 10 | /** 11 | * Determines whether the given argument is a protocol object. A log object must be a simple object and 12 | * must contain either a 'message' or 'args' field, but not a 'stack' field. 13 | * @param {any} arg - The argument to check. 14 | * @returns {boolean} `true` if the argument is a log object according to the specified criteria, otherwise `false`. 15 | */ 16 | export function isLogObj(arg: any) { 17 | // Should be plain object 18 | if (!isPlainObject(arg)) { 19 | return false; 20 | } 21 | 22 | // Should contains either 'message' or 'args' field 23 | if (!arg.message && !arg.args) { 24 | return false; 25 | } 26 | 27 | // Handle non-standard error objects 28 | if (arg.stack) { 29 | return false; 30 | } 31 | 32 | return true; 33 | } 34 | -------------------------------------------------------------------------------- /src/utils/stream.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Writes data to a specified NodeJS writable stream. This function supports streams that have a custom 3 | * `__write' method, and will fall back to the default `write' method if `__write' is not present. 4 | * 5 | * @param {any} data - The data to write to the stream. This can be a string, a buffer, or any data type 6 | * supported by the stream's `write' or `__write' method. 7 | * @param {NodeJS.WriteStream} stream - The writable stream to write the data to. This stream 8 | * must implement the `write' method, and can optionally implement a custom `__write' method. 9 | * @returns {boolean} `true` if the data has been completely processed by the write operation, 10 | * indicating that further writes can be performed immediately. Returns `false` if the data is 11 | * buffered by the stream, indicating that the `drain` event should be waited for before writing 12 | * more data. 13 | */ 14 | export function writeStream(data: any, stream: NodeJS.WriteStream) { 15 | const write = (stream as any).__write || stream.write; 16 | return write.call(stream, data); 17 | } 18 | -------------------------------------------------------------------------------- /src/utils/string.ts: -------------------------------------------------------------------------------- 1 | const ansiRegex = [ 2 | String.raw`[\u001B\u009B][[\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\d\/#&.:=?%@~_]+)*|[a-zA-Z\d]+(?:;[-a-zA-Z\d\/#&.:=?%@~_]*)*)?\u0007)`, 3 | String.raw`(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~]))`, 4 | ].join("|"); 5 | 6 | /** 7 | * Removes ANSI escape codes from a given string. This is particularly useful for 8 | * processing text that contains formatting codes, such as colours or styles, so that the 9 | * the raw text without any visual formatting. 10 | * 11 | * @param {string} text - The text string from which to strip the ANSI escape codes. 12 | * @returns {string} The text without ANSI escape codes. 13 | */ 14 | export function stripAnsi(text: string) { 15 | return text.replace(new RegExp(ansiRegex, "g"), ""); 16 | } 17 | 18 | /** 19 | * Centers a string within a specified total width, padding it with spaces or another specified character. 20 | * If the string is longer than the total width, it is returned as is. 21 | * 22 | * @param {string} str - The string to centre. 23 | * @param {number} len - The total width in which to centre the string. 24 | * @param {string} [space=" "] - The character to use for padding. Defaults to a space. 25 | * @returns {string} The centred string. 26 | */ 27 | export function centerAlign(str: string, len: number, space = " ") { 28 | const free = len - str.length; 29 | if (free <= 0) { 30 | return str; 31 | } 32 | const freeLeft = Math.floor(free / 2); 33 | let _str = ""; 34 | for (let i = 0; i < len; i++) { 35 | _str += 36 | i < freeLeft || i >= freeLeft + str.length ? space : str[i - freeLeft]; 37 | } 38 | return _str; 39 | } 40 | 41 | /** 42 | * Right-justifies a string within a given total width, padding it with whitespace or another specified character. 43 | * If the string is longer than the total width, it is returned as is. 44 | * 45 | * @param {string} str - The string to right-justify. 46 | * @param {number} len - The total width to align the string. 47 | * @param {string} [space=" "] - The character to use for padding. Defaults to a space. 48 | * @returns {string} The right-justified string. 49 | */ 50 | export function rightAlign(str: string, len: number, space = " ") { 51 | const free = len - str.length; 52 | if (free <= 0) { 53 | return str; 54 | } 55 | let _str = ""; 56 | for (let i = 0; i < len; i++) { 57 | _str += i < free ? space : str[i - free]; 58 | } 59 | return _str; 60 | } 61 | 62 | /** 63 | * Left-aligns a string within a given total width, padding it with whitespace or another specified character on the right. 64 | * If the string is longer than the total width, it is returned as is. 65 | * 66 | * @param {string} str - The string to align left. 67 | * @param {number} len - The total width to align the string. 68 | * @param {string} [space=" "] - The character to use for padding. Defaults to a space. 69 | * @returns {string} The left-justified string. 70 | */ 71 | export function leftAlign(str: string, len: number, space = " ") { 72 | let _str = ""; 73 | for (let i = 0; i < len; i++) { 74 | _str += i < str.length ? str[i] : space; 75 | } 76 | return _str; 77 | } 78 | 79 | /** 80 | * Aligns a string (left, right, or centre) within a given total width, padding it with spaces or another specified character. 81 | * If the string is longer than the total width, it is returned as is. This function acts as a wrapper for individual alignment functions. 82 | * 83 | * @param {"left" | "right" | "centre"} alignment - The desired alignment of the string. 84 | * @param {string} str - The string to align. 85 | * @param {number} len - The total width in which to align the string. 86 | * @param {string} [space=" "] - The character to use for padding. Defaults to a space. 87 | * @returns {string} The aligned string, according to the given alignment. 88 | */ 89 | export function align( 90 | alignment: "left" | "right" | "center", 91 | str: string, 92 | len: number, 93 | space = " ", 94 | ) { 95 | switch (alignment) { 96 | case "left": { 97 | return leftAlign(str, len, space); 98 | } 99 | case "right": { 100 | return rightAlign(str, len, space); 101 | } 102 | case "center": { 103 | return centerAlign(str, len, space); 104 | } 105 | default: { 106 | return str; 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/utils/tree.ts: -------------------------------------------------------------------------------- 1 | import { type ColorName, colorize } from "./color"; 2 | 3 | export type TreeItemObject = { 4 | /** 5 | * Text of the item 6 | */ 7 | text: string; 8 | 9 | /** 10 | * Children of the item 11 | */ 12 | children?: TreeItem[]; 13 | 14 | /** 15 | * Color of the item 16 | */ 17 | color?: ColorName; 18 | }; 19 | 20 | export type TreeItem = string | TreeItemObject; 21 | 22 | export type TreeOptions = { 23 | /** 24 | * Color of the tree 25 | */ 26 | color?: ColorName; 27 | 28 | /** 29 | * Prefix of the tree 30 | * 31 | * @default " " 32 | */ 33 | prefix?: string; 34 | 35 | /** 36 | * The max depth of tree 37 | */ 38 | maxDepth?: number; 39 | 40 | /** 41 | * Ellipsis of the tree 42 | * 43 | * @default "..." 44 | */ 45 | ellipsis?: string; 46 | }; 47 | 48 | /** 49 | * Formats a hierarchical list of items into a string representing a tree structure. 50 | * Each item in the tree can be a simple string or an object defining the text of the item, 51 | * optional children, and colour. The tree structure can be customised with options 52 | * Specify the overall colour and the prefix used for indentation and tree lines. 53 | * 54 | * @param {TreeItem[]} items - An array of items to include in the tree. Each item can be 55 | * either a string or an object with `text', `children' and `colour' properties. 56 | * @param {TreeOptions} [options] - Optional settings to customise the appearance of the tree, including 57 | * the colour of the tree text and the prefix for branches. See {@link TreeOptions}. 58 | * @returns {string} The formatted tree as a string, ready for printing to the console or elsewhere. 59 | */ 60 | export function formatTree(items: TreeItem[], options?: TreeOptions): string { 61 | options = { 62 | prefix: " ", 63 | ellipsis: "...", 64 | ...options, 65 | }; 66 | 67 | const tree = _buildTree(items, options).join(""); 68 | if (options && options.color) { 69 | return colorize(options.color, tree); 70 | } 71 | 72 | return tree; 73 | } 74 | 75 | function _buildTree(items: TreeItem[], options?: TreeOptions): string[] { 76 | const chunks: string[] = []; 77 | const total = items.length - 1; 78 | for (let i = 0; i <= total; i++) { 79 | const item = items[i]; 80 | const isItemString = typeof item === "string"; 81 | const isLimit = options?.maxDepth != null && options.maxDepth <= 0; 82 | if (isLimit) { 83 | const ellipsis = `${options.prefix}${options.ellipsis}\n`; 84 | return [ 85 | isItemString 86 | ? ellipsis 87 | : 88 | (item.color 89 | ? colorize(item.color, ellipsis) 90 | : ellipsis), // prettier-ignore 91 | ]; 92 | } 93 | const isLast = i === total; 94 | const prefix = isLast ? `${options?.prefix}└─` : `${options?.prefix}├─`; 95 | if (isItemString) { 96 | chunks.push(`${prefix}${item}\n`); 97 | } else { 98 | const log = `${prefix}${item.text}\n`; 99 | chunks.push(item.color ? colorize(item.color, log) : log); 100 | 101 | if (item.children) { 102 | const _tree = _buildTree(item.children, { 103 | ...options, 104 | maxDepth: 105 | options?.maxDepth == null ? undefined : options.maxDepth - 1, 106 | prefix: `${options?.prefix}${isLast ? " " : "│ "}`, 107 | }); 108 | chunks.push(..._tree); 109 | } 110 | } 111 | } 112 | 113 | return chunks; 114 | } 115 | -------------------------------------------------------------------------------- /test/consola.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, test, expect } from "vitest"; 2 | import { ConsolaReporter, LogLevels, LogObject, createConsola } from "../src"; 3 | 4 | describe("consola", () => { 5 | test("can set level", () => { 6 | const consola = createConsola(); 7 | expect(consola.level).toBe(1); 8 | 9 | for (let i = 0; i <= 5; i++) { 10 | consola.level = i; 11 | expect(consola.level).toBe(i); 12 | } 13 | }); 14 | 15 | test("silent log level does't print logs", async () => { 16 | const logs: LogObject[] = []; 17 | const TestReporter: ConsolaReporter = { 18 | log(logObj) { 19 | logs.push(logObj); 20 | }, 21 | }; 22 | 23 | const consola = createConsola({ 24 | throttle: 100, 25 | level: LogLevels.silent, 26 | reporters: [TestReporter], 27 | }); 28 | 29 | for (let i = 0; i < 10; i++) { 30 | consola.log("SPAM"); 31 | } 32 | 33 | await wait(200); 34 | expect(logs.length).toBe(0); 35 | }); 36 | 37 | test("can see spams without ending log", async () => { 38 | const logs: LogObject[] = []; 39 | const TestReporter: ConsolaReporter = { 40 | log(logObj) { 41 | logs.push(logObj); 42 | }, 43 | }; 44 | 45 | const consola = createConsola({ 46 | throttle: 100, 47 | level: LogLevels.info, 48 | reporters: [TestReporter], 49 | }); 50 | for (let i = 0; i < 10; i++) { 51 | consola.log("SPAM"); 52 | } 53 | await wait(300); 54 | expect(logs.length).toBe(7); 55 | // 6 + Last one indicating it repeated 4 56 | 57 | expect(logs.at(-1)!.args).toEqual(["SPAM", "(repeated 4 times)"]); 58 | }); 59 | }); 60 | 61 | function wait(delay) { 62 | return new Promise((resolve) => { 63 | setTimeout(resolve, delay); 64 | }); 65 | } 66 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "esModuleInterop": true, 7 | "strict": true, 8 | "types": ["vitest/globals", "node"] 9 | }, 10 | "include": ["src"] 11 | } 12 | -------------------------------------------------------------------------------- /utils.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./dist/utils"; 2 | --------------------------------------------------------------------------------