├── .editorconfig
├── .github
├── FUNDING.yml
├── dependabot.yml
└── workflows
│ └── bevry.yml
├── .gitignore
├── .npmignore
├── .prettierignore
├── CONTRIBUTING.md
├── HISTORY.md
├── LICENSE.md
├── README.md
├── SECURITY.md
├── index.cjs
├── package-lock.json
├── package.json
├── source
├── index.ts
├── logger.ts
├── test.ts
├── transform.ts
└── transforms
│ ├── browser.ts
│ ├── filter.ts
│ └── human.ts
├── test.cjs
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # 2023 June 22
2 | # https://github.com/bevry/base
3 |
4 | root = true
5 |
6 | [*]
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = false
11 | indent_style = tab
12 |
13 | [{*.mk,*.py}]
14 | indent_style = tab
15 | indent_size = 4
16 |
17 | [*.md]
18 | indent_style = space
19 | indent_size = 4
20 |
21 | [{*.json,*.lsrules,*.yaml,*.yml,*.bowerrc,*.babelrc,*.code-workspace}]
22 | indent_style = space
23 | indent_size = 2
24 |
25 | [{*.json,*.lsrules}]
26 | insert_final_newline = true
27 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [balupton]
2 | patreon: bevry
3 | open_collective: bevry
4 | ko_fi: balupton
5 | liberapay: bevry
6 | tidelift: npm/caterpillar
7 | custom: ['https://bevry.me/fund']
8 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: github-actions
4 | directory: /
5 | schedule:
6 | interval: weekly
7 | day: sunday
8 | time: '00:00'
9 | timezone: Australia/Perth
10 | - package-ecosystem: npm
11 | directory: /
12 | schedule:
13 | interval: weekly
14 | day: sunday
15 | time: '00:00'
16 | timezone: Australia/Perth
17 | open-pull-requests-limit: 0
18 |
--------------------------------------------------------------------------------
/.github/workflows/bevry.yml:
--------------------------------------------------------------------------------
1 | name: bevry
2 | 'on':
3 | - push
4 | - pull_request
5 | jobs:
6 | test:
7 | strategy:
8 | matrix:
9 | os:
10 | - ubuntu-latest
11 | - macos-latest
12 | - windows-latest
13 | node:
14 | - '16'
15 | - '18'
16 | - '20'
17 | - '21'
18 | runs-on: ${{ matrix.os }}
19 | continue-on-error: ${{ contains('macos-latest windows-latest', matrix.os) }}
20 | steps:
21 | - uses: actions/checkout@v4
22 | - name: Install Deno
23 | uses: denoland/setup-deno@v2
24 | with:
25 | deno-version: vx.x.x
26 | - name: Install desired Node.js version
27 | uses: actions/setup-node@v4
28 | with:
29 | node-version: '20'
30 | - name: Verify Node.js Versions
31 | run: >-
32 | printf '%s' 'node: ' && node --version && printf '%s' 'npm: ' && npm
33 | --version && node -e 'console.log(process.versions)'
34 | - run: npm run our:setup
35 | - run: npm run our:compile
36 | - run: npm run our:verify
37 | - name: Install targeted Node.js
38 | if: ${{ matrix.node != 20 }}
39 | uses: actions/setup-node@v4
40 | with:
41 | node-version: ${{ matrix.node }}
42 | - name: Verify Node.js Versions
43 | run: >-
44 | printf '%s' 'node: ' && node --version && printf '%s' 'npm: ' && npm
45 | --version && node -e 'console.log(process.versions)'
46 | - run: npm test
47 | publish:
48 | if: ${{ github.event_name == 'push' }}
49 | needs: test
50 | runs-on: ubuntu-latest
51 | steps:
52 | - uses: actions/checkout@v4
53 | - name: Install Deno
54 | uses: denoland/setup-deno@v2
55 | with:
56 | deno-version: vx.x.x
57 | - name: Install desired Node.js version
58 | uses: actions/setup-node@v4
59 | with:
60 | node-version: '20'
61 | - name: Verify Node.js Versions
62 | run: >-
63 | printf '%s' 'node: ' && node --version && printf '%s' 'npm: ' && npm
64 | --version && node -e 'console.log(process.versions)'
65 | - run: npm run our:setup
66 | - run: npm run our:compile
67 | - run: npm run our:meta
68 | - name: publish to npm
69 | uses: bevry-actions/npm@v1.1.7
70 | with:
71 | npmAuthToken: ${{ secrets.NPM_AUTH_TOKEN }}
72 | npmBranchTag: ':next'
73 | - name: publish to surge
74 | uses: bevry-actions/surge@v1.1.0
75 | with:
76 | surgeLogin: ${{ secrets.SURGE_LOGIN }}
77 | surgeToken: ${{ secrets.SURGE_TOKEN }}
78 | automerge:
79 | permissions:
80 | contents: write
81 | pull-requests: write
82 | runs-on: ubuntu-latest
83 | if: github.actor == 'dependabot[bot]'
84 | steps:
85 | - name: Enable auto-merge for Dependabot PRs
86 | run: gh pr merge --auto --squash "$PR_URL"
87 | env:
88 | PR_URL: ${{github.event.pull_request.html_url}}
89 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
90 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # 2020 June 3
2 | # https://github.com/bevry/base
3 |
4 | # System Files
5 | **/.DS_Store
6 |
7 | # Temp Files
8 | **/.docpad.db
9 | **/*.log
10 | **/*.cpuprofile
11 | **/*.heapsnapshot
12 |
13 | # Editor Files
14 | .c9/
15 | .vscode/
16 |
17 | # Yarn Files
18 | .yarn/*
19 | !.yarn/releases
20 | !.yarn/plugins
21 | !.yarn/sdks
22 | !.yarn/versions
23 | .pnp.*
24 | .pnp/
25 |
26 | # Private Files
27 | .env
28 | .idea
29 | .cake_task_cache
30 |
31 | # Build Caches
32 | build/
33 | bower_components/
34 | node_modules/
35 | .next/
36 |
37 | # -------------------------------------
38 | # CDN Inclusions, Git Exclusions
39 |
40 | # Build Outputs
41 | **/out.*
42 | **/*.out.*
43 | **/out/
44 | **/output/
45 | *compiled*
46 | edition*/
47 | coffeejs/
48 | coffee/
49 | es5/
50 | es2015/
51 | esnext/
52 | docs/
53 |
54 | # =====================================
55 | # CUSTOM
56 |
57 | # None
58 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # 2020 May 5
2 | # https://github.com/bevry/base
3 |
4 | # System Files
5 | **/.DS_Store
6 |
7 | # Temp Files
8 | **/.docpad.db
9 | **/*.log
10 | **/*.cpuprofile
11 | **/*.heapsnapshot
12 |
13 | # Editor Files
14 | .c9/
15 | .vscode/
16 |
17 | # Private Files
18 | .env
19 | .idea
20 | .cake_task_cache
21 |
22 | # Build Caches
23 | build/
24 | components/
25 | bower_components/
26 | node_modules/
27 | .pnp/
28 | .pnp.js
29 |
30 | # Ecosystem Files
31 | .dependabout
32 | .github
33 |
34 | # -------------------------------------
35 | # CDN Inclusions, Package Exclusions
36 |
37 | # Documentation Files
38 | docs/
39 | guides/
40 | BACKERS.md
41 | CONTRIBUTING.md
42 | HISTORY.md
43 |
44 | # Development Files
45 | web/
46 | **/example*
47 | **/test*
48 | .babelrc*
49 | .editorconfig
50 | .eslintrc*
51 | .jshintrc
52 | .jscrc
53 | coffeelint*
54 | .travis*
55 | nakefile*
56 | Cakefile
57 | Makefile
58 |
59 | # Other Package Definitions
60 | template.js
61 | component.json
62 | bower.json
63 |
64 | # =====================================
65 | # CUSTOM MODIFICATIONS
66 |
67 | # None
68 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # 2023 November 13
2 | # https://github.com/bevry/base
3 |
4 | # VCS Files
5 | .git
6 | .svn
7 | .hg
8 |
9 | # System Files
10 | **/.DS_Store
11 |
12 | # Temp Files
13 | **/.docpad.db
14 | **/*.log
15 | **/*.cpuprofile
16 | **/*.heapsnapshot
17 |
18 | # Yarn Files
19 | .yarn/*
20 | !.yarn/releases
21 | !.yarn/plugins
22 | !.yarn/sdks
23 | !.yarn/versions
24 | .pnp.*
25 | .pnp/
26 |
27 | # Build Caches
28 | build/
29 | components/
30 | bower_components/
31 | node_modules/
32 |
33 | # Build Outputs
34 | **/*.cjs
35 | **/*.mjs
36 | **/out.*
37 | **/*.out.*
38 | **/out/
39 | **/output/
40 | *compiled*
41 | edition*/
42 | coffeejs/
43 | coffee/
44 | es5/
45 | es2015/
46 | esnext/
47 | docs/
48 |
49 | # Development Files
50 | test/
51 | **/*fixtures*
52 |
53 | # Ecosystem Caches
54 | .trunk/*/
55 |
56 | # =====================================
57 | # CUSTOM
58 |
59 | # None
60 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 |
5 |
6 | # Before You Post!
7 |
8 | ## Support
9 |
10 | We offer support through our [Official Support Channels](https://bevry.me/support). Do not use GitHub Issues for support, your issue will be closed.
11 |
12 | ## Contribute
13 |
14 | Our [Contributing Guide](https://bevry.me/contribute) contains useful tips and suggestions for how to contribute to this project, it's worth the read.
15 |
16 | ## Development
17 |
18 | ### Setup
19 |
20 | 1. [Install Node.js](https://bevry.me/install/node)
21 |
22 | 1. Fork the project and clone your fork - [guide](https://help.github.com/articles/fork-a-repo/)
23 |
24 | 1. Setup the project for development
25 |
26 | ```bash
27 | npm run our:setup
28 | ```
29 |
30 | ### Developing
31 |
32 | 1. Compile changes
33 |
34 | ```bash
35 | npm run our:compile
36 | ```
37 |
38 | 1. Run tests
39 |
40 | ```bash
41 | npm test
42 | ```
43 |
44 | ### Publishing
45 |
46 | Follow these steps in order to implement your changes/improvements into your desired project:
47 |
48 | #### Preparation
49 |
50 | 1. Make sure your changes are on their own branch that is branched off from master.
51 |
52 | 1. You can do this by: `git checkout master; git checkout -b your-new-branch`
53 | 1. And push the changes up by: `git push origin your-new-branch`
54 |
55 | 1. Ensure all tests pass:
56 |
57 | ```bash
58 | npm test
59 | ```
60 |
61 | > If possible, add tests for your change, if you don't know how, mention this in your pull request
62 |
63 | 1. Ensure the project is ready for publishing:
64 |
65 | ```
66 | npm run our:release:prepare
67 | ```
68 |
69 | #### Pull Request
70 |
71 | To send your changes for the project owner to merge in:
72 |
73 | 1. Submit your pull request
74 | 1. When submitting, if the original project has a `dev` or `integrate` branch, use that as the target branch for your pull request instead of the default `master`
75 | 1. By submitting a pull request you agree for your changes to have the same license as the original plugin
76 |
77 | #### Publish
78 |
79 | To publish your changes as the project owner:
80 |
81 | 1. Switch to the master branch:
82 |
83 | ```bash
84 | git checkout master
85 | ```
86 |
87 | 1. Merge in the changes of the feature branch (if applicable)
88 |
89 | 1. Increment the version number in the `package.json` file according to the [semantic versioning](http://semver.org) standard, that is:
90 |
91 | 1. `x.0.0` MAJOR version when you make incompatible API changes (note: DocPad plugins must use v2 as the major version, as v2 corresponds to the current DocPad v6.x releases)
92 | 1. `x.y.0` MINOR version when you add functionality in a backwards-compatible manner
93 | 1. `x.y.z` PATCH version when you make backwards-compatible bug fixes
94 |
95 | 1. Add an entry to the changelog following the format of the previous entries, an example of this is:
96 |
97 | ```markdown
98 | ## v6.29.0 2013 April 1
99 |
100 | - Progress on [issue #474](https://github.com/docpad/docpad/issues/474)
101 | - DocPad will now set permissions based on the process's ability
102 | - Thanks to [Avi Deitcher](https://github.com/deitch), [Stephan Lough](https://github.com/stephanlough) for [issue #165](https://github.com/docpad/docpad/issues/165)
103 | - Updated dependencies
104 | ```
105 |
106 | 1. Commit the changes with the commit title set to something like `v6.29.0. Bugfix. Improvement.` and commit description set to the changelog entry
107 |
108 | 1. Ensure the project is ready for publishing:
109 |
110 | ```
111 | npm run our:release:prepare
112 | ```
113 |
114 | 1. Prepare the release and publish it to npm and git:
115 |
116 | ```bash
117 | npm run our:release
118 | ```
119 |
--------------------------------------------------------------------------------
/HISTORY.md:
--------------------------------------------------------------------------------
1 | # History
2 |
3 | ## v8.2.0 2023 December 29
4 |
5 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
6 | - Thank you to the sponsors: [Andrew Nesbitt](https://nesbitt.io), [Balsa](https://balsa.com), [Codecov](https://codecov.io), [Poonacha Medappa](https://poonachamedappa.com), [Rob Morris](https://github.com/Rob-Morris), [Sentry](https://sentry.io), [Syntax](https://syntax.fm)
7 |
8 | ## v8.1.0 2023 December 27
9 |
10 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
11 | - Thank you to the sponsors: [Andrew Nesbitt](https://nesbitt.io), [Balsa](https://balsa.com), [Codecov](https://codecov.io/), [Poonacha Medappa](https://poonachamedappa.com), [Rob Morris](https://github.com/Rob-Morris), [Sentry](https://sentry.io), [Syntax](https://syntax.fm)
12 |
13 | ## v8.0.0 2023 December 6
14 |
15 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
16 | - Minimum required Node.js version changed from `node: >=6` to `node: >=4` adapting to ecosystem changes
17 |
18 | ## v7.0.0 2023 November 24
19 |
20 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
21 | - Minimum required Node.js version changed from `node: >=10` to `node: >=6` adapting to ecosystem changes
22 |
23 | ## v6.12.0 2023 November 21
24 |
25 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
26 |
27 | ## v6.11.0 2023 November 15
28 |
29 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
30 |
31 | ## v6.10.0 2023 November 14
32 |
33 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
34 |
35 | ## v6.9.0 2023 November 14
36 |
37 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
38 | - Updated license from [`MIT`](http://spdx.org/licenses/MIT.html) to [`Artistic-2.0`](http://spdx.org/licenses/Artistic-2.0.html)
39 |
40 | ## v6.8.0 2021 July 30
41 |
42 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
43 |
44 | ## v6.7.0 2021 July 29
45 |
46 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
47 |
48 | ## v6.6.0 2020 October 29
49 |
50 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
51 |
52 | ## v6.5.0 2020 September 4
53 |
54 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
55 |
56 | ## v6.4.0 2020 August 18
57 |
58 | - Updated for [`get-current-line` v6](https://github.com/bevry/get-current-line), which also returns the character position of the line
59 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
60 |
61 | ## v6.3.0 2020 August 18
62 |
63 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
64 |
65 | ## v6.2.0 2020 August 18
66 |
67 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
68 |
69 | ## v6.1.0 2020 August 4
70 |
71 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
72 |
73 | ## v6.0.2 2020 July 22
74 |
75 | - Updated Transform documentation and renamed `Writeable` internal type to `Pipeable` to reflect its purpose better
76 |
77 | ## v6.0.1 2020 July 22
78 |
79 | - Updated dependencies, fixes Node.js due to missing `semver` dependency under `editions`
80 | - Closes [issue #80](https://github.com/bevry/caterpillar/issues/80)
81 |
82 | ## v6.0.0 2020 July 24
83 |
84 | - Breaking Changes: Caterpillar has been rewritten for performance, ease of use, and deno compatibility (now it is compatible with Node.js, Deno, and Web Browsers)
85 | - The Caterpillar Transforms by Bevry, are now embedded into the `caterpillar` package:
86 | - `caterpillar-filter` is now `import { Filter } from 'caterpillar'`
87 | - `caterpillar-human` is now `import { Human } from 'caterpillar'`
88 | - `caterpillar-browser` is now `import { Browser } from 'caterpillar'`
89 | - `*.create()` aliases for `new *()` are now removed, please just use `new *(config)`
90 | - Each Caterpillar Transform now maintains its own configuration, which is specified via their constructor
91 | - As such, instead of doing `new *().setConfig(opts)` now jsut do `new *(opts)`
92 | - the default log level is now a configuration option, rather than an entry in the levels map
93 | - `level` configuration option has been renamed to `filterLevel`, which must now be specified directly on the filter transform
94 | - the logger transform now accepts a new `lineLevel` configuration option, which will limit fetching line info for only log levels equal to or below that the `lineLevel` value, by default it is `-1` which disables fetching line info
95 | - This is a dramatic performance improvement for large applications, as fetching line levels for every log entry, even ones filtered out, was not performant
96 | - Closes [issue #16](https://github.com/bevry/caterpillar/issues/16)
97 | - Caterpillar Transforms are no longer Node.js Streams, as using them was a major performance overhead
98 | - We can still pipe to Caterpillar Transforms as well as to Node.js streams and WHATWG/Deno streams
99 | - Closes [issue #17](https://github.com/bevry/caterpillar/issues/17)
100 | - Add `error`, `warn`, `info`, `debug` aliases to the logger
101 | - Thanks to [Kirill Chernyshov](https://github.com/DeLaGuardo) for [issue #12](https://github.com/bevry/caterpillar/issues/12)
102 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
103 |
104 | ## v5.15.0 2020 July 22
105 |
106 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
107 |
108 | ## v5.14.0 2020 July 22
109 |
110 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
111 |
112 | ## v5.13.0 2020 July 3
113 |
114 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
115 |
116 | ## v5.12.0 2020 July 3
117 |
118 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
119 |
120 | ## v5.11.0 2020 June 25
121 |
122 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
123 |
124 | ## v5.10.0 2020 June 21
125 |
126 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
127 |
128 | ## v5.9.0 2020 June 21
129 |
130 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
131 |
132 | ## v5.8.0 2020 June 20
133 |
134 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
135 |
136 | ## v5.7.0 2020 June 20
137 |
138 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
139 |
140 | ## v5.6.0 2020 June 10
141 |
142 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
143 |
144 | ## v5.5.0 2020 June 10
145 |
146 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
147 |
148 | ## v5.4.0 2020 May 22
149 |
150 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
151 |
152 | ## v5.3.0 2020 May 21
153 |
154 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
155 |
156 | ## v5.2.0 2020 May 11
157 |
158 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
159 |
160 | ## v5.1.2 2020 May 8
161 |
162 | - Added Logger as a default export, for better compat with the filters
163 |
164 | ## v5.1.1 2020 May 8
165 |
166 | - Fix some types on the Transform class
167 |
168 | ## v5.1.0 2020 May 8
169 |
170 | - Merge source code into a single file, and export the various types
171 |
172 | ## v5.0.0 2020 May 8
173 |
174 | - Converted from JavaScript to TypeScript, no functionality changes here
175 | - Extracted the current line functionality into [get-current-line](https://github.com/bevry/get-current-line), which uses [a different means of calculating the offset](https://github.com/bevry/get-current-line/blob/master/HISTORY.md#v500-2020-may-8) which **you should refer to if you ever used custom offsets**
176 | - Extracted the log level functionality into [rfc-log-levels](https://github.com/bevry/rfc-log-levels), existing functionality is retained
177 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
178 | - Minimum required node version changed from `node: >=8` to `node: >=10` to keep up with mandatory ecosystem changes
179 |
180 | ## v4.0.0 2019 December 1
181 |
182 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
183 | - Minimum required node version changed from `node: >=0.10` to `node: >=8` to keep up with mandatory ecosystem changes
184 |
185 | ## v3.3.0 2019 November 13
186 |
187 | - Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
188 |
189 | ## v3.2.0 2019 January 1
190 |
191 | - Updated [base files](https://github.com/bevry/base) and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)
192 |
193 | ## v3.1.2 2018 September 3
194 |
195 | - Updated base files and [editions](https://github.com/bevry/editions) using [boundation](https://github.com/bevry/boundation)
196 |
197 | ## v3.1.1 2018 August 19
198 |
199 | - Readded support for node 0.10
200 |
201 | ## v3.1.0 2018 August 17
202 |
203 | - Now uses [rfc-log-levels](https://github.com/bevry/log-levels) for the initial log levels
204 | - Moved type linting from flow to jsdoc & typescript, which also results in better documentation for you, and visual studio code intellisense`
205 | - Updated base files and [editions](https://github.com/bevry/editions) using [boundation](https://github.com/bevry/boundation)
206 |
207 | ## v3.0.1 2016 October 20
208 |
209 | - Fixed flow type errors with newer flow versions
210 |
211 | ## v3.0.0 2016 May 4
212 |
213 | - Converted from CoffeeScript to JavaScript
214 | - `.createLogger()` and `.createTransform()` now removed in favour of `Logger.create()` and `Transform.create()`
215 | - `require('caterpillar').create()` alias added
216 | - Logger no longer inherits from Transform
217 |
218 | ## v2.0.9 2015 February 18
219 |
220 | - Fixed an issue when fetching `(new Error()).stack` would fail
221 | - More robust stack parsing
222 |
223 | ## v2.0.8 2015 February 7
224 |
225 | - Updated dependencies
226 |
227 | ## v2.0.7 2013 December 12
228 |
229 | - Use native streams if available, otherwise fallback to [readable-stream](https://npmjs.org/package/readable-stream)
230 | - Repackaged
231 |
232 | ## v2.0.6 2013 October 23
233 |
234 | - `Logger:log` is now permantely bound to the logger instance, for easy passing around
235 |
236 | ## v2.0.5 2013 October 23
237 |
238 | - Added `create` API to make life easier when doing one liners
239 | - Project meta data files are now maintained by [Projectz](https://github.com/bevry/projectz)
240 | - Updated dependencies
241 |
242 | ## v2.0.4 2013 July 23
243 |
244 | - Added `lineOffset` configuration offset to allow you to detect the correct line of the reporting when using wrappers
245 | - Updated dependencies
246 |
247 | ## v2.0.3 2013 May 19
248 |
249 | - iOS support (iOS devices do not have `new Error().stack`)
250 |
251 | ## v2.0.2 2013 May 7
252 |
253 | - Fixed defaulting the log level - Closes [issue #6](https://github.com/bevry/caterpillar/issues/6) reported by [Erik Dasque](https://github.com/edasque)
254 |
255 | ## v2.0.1 2013 April 25
256 |
257 | - Node 0.8 support
258 |
259 | ## v2.0.0 2013 April 25
260 |
261 | - Rewrote using streams
262 |
263 | ## v1.1.4 2013 March 25
264 |
265 | - Repackaged
266 |
267 | ## v1.1.3 2012 October 18
268 |
269 | - Updated cli-color from 0.1 to 0.2
270 | - Make cli-color an optional dependency
271 |
272 | ## v1.1.2 2012 August 10
273 |
274 | - Rejigged directory structure
275 | - Re-added markdown files to npm distribution as they are required for the npm website
276 |
277 | ## v1.1.1 2012 May 4
278 |
279 | - Fixed dependency overwrite
280 |
281 | ## v1.1.0 2012 May 4
282 |
283 | - Caterpillar now pre-compiles, so the coffee-script dependency is no longer needed
284 |
285 | ## v1.0.0 2012 February 11
286 |
287 | - Modularised
288 | - Added [docco](http://jashkenas.github.com/docco/) docs
289 | - Debug line is now only outputted if the log level is 7
290 | - Added `setLevel(level)`
291 | - Added `History.md`
292 | - Added new screenshots
293 | - `cli-color` dependency now accepts revisions
294 |
295 | ## v0.1 2011 September 5
296 |
297 | - Initial commit
298 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # License
4 |
5 | Unless stated otherwise all works are:
6 |
7 | - Copyright © [Benjamin Lupton](https://balupton.com)
8 |
9 | and licensed under:
10 |
11 | - [Artistic License 2.0](http://spdx.org/licenses/Artistic-2.0.html)
12 |
13 | ## The Artistic License 2.0
14 |
15 |
16 | Copyright (c) 2000-2006, The Perl Foundation.
17 |
18 | Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
19 |
20 | Preamble
21 |
22 | This license establishes the terms under which a given free software Package may be copied, modified, distributed, and/or redistributed. The intent is that the Copyright Holder maintains some artistic control over the development of that Package while still keeping the Package available as open source and free software.
23 |
24 | You are always permitted to make arrangements wholly outside of this license directly with the Copyright Holder of a given Package. If the terms of this license do not permit the full use that you propose to make of the Package, you should contact the Copyright Holder and seek a different licensing arrangement.
25 |
26 | Definitions
27 |
28 | "Copyright Holder" means the individual(s) or organization(s) named in the copyright notice for the entire Package.
29 |
30 | "Contributor" means any party that has contributed code or other material to the Package, in accordance with the Copyright Holder's procedures.
31 |
32 | "You" and "your" means any person who would like to copy, distribute, or modify the Package.
33 |
34 | "Package" means the collection of files distributed by the Copyright Holder, and derivatives of that collection and/or of those files. A given Package may consist of either the Standard Version, or a Modified Version.
35 |
36 | "Distribute" means providing a copy of the Package or making it accessible to anyone else, or in the case of a company or organization, to others outside of your company or organization.
37 |
38 | "Distributor Fee" means any fee that you charge for Distributing this Package or providing support for this Package to another party. It does not mean licensing fees.
39 |
40 | "Standard Version" refers to the Package if it has not been modified, or has been modified only in ways explicitly requested by the Copyright Holder.
41 |
42 | "Modified Version" means the Package, if it has been changed, and such changes were not explicitly requested by the Copyright Holder.
43 |
44 | "Original License" means this Artistic License as Distributed with the Standard Version of the Package, in its current version or as it may be modified by The Perl Foundation in the future.
45 |
46 | "Source" form means the source code, documentation source, and configuration files for the Package.
47 |
48 | "Compiled" form means the compiled bytecode, object code, binary, or any other form resulting from mechanical transformation or translation of the Source form.
49 |
50 | Permission for Use and Modification Without Distribution
51 |
52 | (1) You are permitted to use the Standard Version and create and use Modified Versions for any purpose without restriction, provided that you do not Distribute the Modified Version.
53 |
54 | Permissions for Redistribution of the Standard Version
55 |
56 | (2) You may Distribute verbatim copies of the Source form of the Standard Version of this Package in any medium without restriction, either gratis or for a Distributor Fee, provided that you duplicate all of the original copyright notices and associated disclaimers. At your discretion, such verbatim copies may or may not include a Compiled form of the Package.
57 |
58 | (3) You may apply any bug fixes, portability changes, and other modifications made available from the Copyright Holder. The resulting Package will still be considered the Standard Version, and as such will be subject to the Original License.
59 |
60 | Distribution of Modified Versions of the Package as Source
61 |
62 | (4) You may Distribute your Modified Version as Source (either gratis or for a Distributor Fee, and with or without a Compiled form of the Modified Version) provided that you clearly document how it differs from the Standard Version, including, but not limited to, documenting any non-standard features, executables, or modules, and provided that you do at least ONE of the following:
63 |
64 | (a) make the Modified Version available to the Copyright Holder of the Standard Version, under the Original License, so that the Copyright Holder may include your modifications in the Standard Version.
65 | (b) ensure that installation of your Modified Version does not prevent the user installing or running the Standard Version. In addition, the Modified Version must bear a name that is different from the name of the Standard Version.
66 | (c) allow anyone who receives a copy of the Modified Version to make the Source form of the Modified Version available to others under
67 |
68 | (i) the Original License or
69 | (ii) a license that permits the licensee to freely copy, modify and redistribute the Modified Version using the same licensing terms that apply to the copy that the licensee received, and requires that the Source form of the Modified Version, and of any works derived from it, be made freely available in that license fees are prohibited but Distributor Fees are allowed.
70 |
71 | Distribution of Compiled Forms of the Standard Version or Modified Versions without the Source
72 |
73 | (5) You may Distribute Compiled forms of the Standard Version without the Source, provided that you include complete instructions on how to get the Source of the Standard Version. Such instructions must be valid at the time of your distribution. If these instructions, at any time while you are carrying out such distribution, become invalid, you must provide new instructions on demand or cease further distribution. If you provide valid instructions or cease distribution within thirty days after you become aware that the instructions are invalid, then you do not forfeit any of your rights under this license.
74 |
75 | (6) You may Distribute a Modified Version in Compiled form without the Source, provided that you comply with Section 4 with respect to the Source of the Modified Version.
76 |
77 | Aggregating or Linking the Package
78 |
79 | (7) You may aggregate the Package (either the Standard Version or Modified Version) with other packages and Distribute the resulting aggregation provided that you do not charge a licensing fee for the Package. Distributor Fees are permitted, and licensing fees for other components in the aggregation are permitted. The terms of this license apply to the use and Distribution of the Standard or Modified Versions as included in the aggregation.
80 |
81 | (8) You are permitted to link Modified and Standard Versions with other works, to embed the Package in a larger work of your own, or to build stand-alone binary or bytecode versions of applications that include the Package, and Distribute the result without restriction, provided the result does not expose a direct interface to the Package.
82 |
83 | Items That are Not Considered Part of a Modified Version
84 |
85 | (9) Works (including, but not limited to, modules and scripts) that merely extend or make use of the Package, do not, by themselves, cause the Package to be a Modified Version. In addition, such works are not considered parts of the Package itself, and are not subject to the terms of this license.
86 |
87 | General Provisions
88 |
89 | (10) Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license.
90 |
91 | (11) If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license.
92 |
93 | (12) This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder.
94 |
95 | (13) This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed.
96 |
97 | (14) Disclaimer of Warranty:
98 | THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Caterpillar
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Caterpillar is the ultimate logging system for Deno, Node.js, and Web Browsers. Log levels are implemented to the RFC standard. Log entries can be filtered and piped to various streams, including coloured output to the terminal, the browser's console, and debug files. You can even write your own transforms.
30 |
31 |
32 |
33 |
34 | ## Usage
35 |
36 | [Complete API Documentation.](http://master.caterpillar.bevry.surge.sh/docs/)
37 |
38 | ### Examples
39 |
40 | - [Deno Example](https://repl.it/@balupton/caterpillar-deno)
41 | - [Node.js Example](https://repl.it/@balupton/caterpillar-node)
42 | - [Web Browser Example](https://repl.it/@balupton/caterpillar-browser)
43 | - [Writing a Custom Transform](https://repl.it/@balupton/caterpillar-custom-transform)
44 |
45 | ### Overview
46 |
47 | The RFC Log Levels are provided by the [`rfc-log-levels` package](https://github.com/bevry/rfc-log-levels) which follows [RFC 3164 - The BSD Syslog Protocol](http://www.faqs.org/rfcs/rfc3164.html).
48 |
49 | [Log Entries](http://master.caterpillar.bevry.surge.sh/docs/interfaces/logentry.html) that are within the [lineLevel](http://master.caterpillar.bevry.surge.sh/docs/classes/logger.html#linelevel) range, will have their line information fetched using the [`get-current-line` package](https://github.com/bevry/get-current-line).
50 |
51 | The [`Logger`](http://master.caterpillar.bevry.surge.sh/docs/classes/logger.html) is what you write your log messages to, which you then pipe to destinations and transforms.
52 |
53 | The [`Filter` transport](http://master.caterpillar.bevry.surge.sh/docs/classes/filter.html) is used to filter out log levels that we do not want to pass onto the next destination.
54 |
55 | The [`Human` transport](http://master.caterpillar.bevry.surge.sh/docs/classes/human.html) is used to convert the Log Entries into a human readable and colourful output.
56 |
57 | The [`Browser` transport](https://github.com/bevry/caterpillar/blob/master/source/transforms/browser.ts) is used to send the human output, including colours, to the Web Browser console.
58 |
59 | The [`Transform`](http://master.caterpillar.bevry.surge.sh/docs/classes/transform.html) is used to write your own transforms, and is what all the others are based from.
60 |
61 | ### Node.js Guide
62 |
63 | To get started for Node.js, setup a new Node.js project for this guide and install Caterpillar.
64 |
65 | ```bash
66 | mkdir caterpillar-guide
67 | cd caterpillar-guide
68 | npm init
69 | npm install --save caterpillar
70 | touch index.js
71 | ```
72 |
73 | Then edit our `index.js` file with the following, that will output all the log messages in JSON format to stdout, and can be run via `node index.js`:
74 |
75 | ```javascript
76 | const { Logger } = require('caterpillar')
77 | const logger = new Logger()
78 |
79 | logger.pipe(process.stdout)
80 |
81 | logger.log('warn', 'this is a warning, which is level', 4)
82 | logger.warn('this is a warning, which is level', 4)
83 | logger.log('debug', 'this is a debug message, which is level', 7)
84 | logger.warn('this is a debug message, which is level', 7)
85 | ```
86 |
87 | Outputting in JSON format is not a nice experience, instead we can do better by using the [`Human` transport](http://master.caterpillar.bevry.surge.sh/docs/classes/human.html) such that it is human readable.
88 |
89 | ```javascript
90 | const { Logger, Human } = require('caterpillar')
91 | const logger = new Logger()
92 |
93 | logger.pipe(new Human()).pipe(process.stdout)
94 |
95 | logger.log('warn', 'this is a warning, which is level', 4)
96 | logger.warn('this is a warning, which is level', 4)
97 | logger.log('debug', 'this is a debug message, which is level', 7)
98 | logger.warn('this is a debug message, which is level', 7)
99 | ```
100 |
101 | However, perhaps we want to still store the JSON format for querying later. We can pipe the human format to stdout as before, but we can pipe the raw output to a debug file.
102 |
103 | ```javascript
104 | const { Logger, Human } = require('caterpillar')
105 | const logger = new Logger()
106 |
107 | const { createWriteStream } = require('fs')
108 | logger.pipe(createWriteStream('./debug.log'))
109 |
110 | logger.pipe(new Human()).pipe(process.stdout)
111 |
112 | logger.log('warn', 'this is a warning, which is level', 4)
113 | logger.warn('this is a warning, which is level', 4)
114 | logger.log('debug', 'this is a debug message, which is level', 7)
115 | logger.warn('this is a debug message, which is level', 7)
116 | ```
117 |
118 | Now let's stay for some reason, we want to capitalise all the log messages that are warning levels and higher, we can do this by making our own transport by extending the [`Transform`](http://master.caterpillar.bevry.surge.sh/docs/classes/transform.html).
119 |
120 | ```javascript
121 | const { Logger, Transform, Human } = require('caterpillar')
122 | const logger = new Logger()
123 |
124 | const { createWriteStream } = require('fs')
125 | logger.pipe(createWriteStream('./debug.log'))
126 |
127 | class Uppercase extends Transform {
128 | format(entry) {
129 | if (entry.levelNumber <= 4) {
130 | entry.args.forEach(function (value, index) {
131 | if (typeof value === 'string') {
132 | entry.args[index] = value.toUpperCase()
133 | }
134 | })
135 | }
136 | return entry
137 | }
138 | }
139 |
140 | logger.pipe(new Uppercase()).pipe(new Human()).pipe(process.stdout)
141 |
142 | logger.log('warn', 'this is a warning, which is level', 4)
143 | logger.warn('this is a warning, which is level', 4)
144 | logger.log('debug', 'this is a debug message, which is level', 7)
145 | logger.warn('this is a debug message, which is level', 7)
146 | ```
147 |
148 | Futhermore, the user probably doesn't need to see debug messages, even though they are useful for debugging. We can filter out the debug messages for the user, but maintain them for the `debug.log` file by applying the [`Filter` transport](http://master.caterpillar.bevry.surge.sh/docs/classes/filter.html) to the pipe that goes to stdout.
149 |
150 | ```javascript
151 | const { Logger, Transform, Filter, Human } = require('caterpillar')
152 | const logger = new Logger()
153 |
154 | const { createWriteStream } = require('fs')
155 | logger.pipe(createWriteStream('./debug.log'))
156 |
157 | class Uppercase extends Transform {
158 | format(entry) {
159 | if (entry.levelNumber <= 4) {
160 | entry.args.forEach(function (value, index) {
161 | if (typeof value === 'string') {
162 | entry.args[index] = value.toUpperCase()
163 | }
164 | })
165 | }
166 | return entry
167 | }
168 | }
169 |
170 | logger
171 | .pipe(new Filter({ filterLevel: 5 }))
172 | .pipe(new Uppercase())
173 | .pipe(new Human())
174 | .pipe(process.stdout)
175 |
176 | logger.log('warn', 'this is a warning, which is level', 4)
177 | logger.warn('this is a warning, which is level', 4)
178 | logger.log('debug', 'this is a debug message, which is level', 7)
179 | logger.warn('this is a debug message, which is level', 7)
180 | ```
181 |
182 | As fetching line information is computationally expensive process, for large applications for performance we probably only want to fetch the line information for messages that we actually show to the user. As such, we should make the [`filterLevel`](http://master.caterpillar.bevry.surge.sh/docs/classes/filter.html#filterlevel) and the [`lineLevel`](http://master.caterpillar.bevry.surge.sh/docs/classes/logger.html#linelevel) the same.
183 |
184 | ```javascript
185 | const { Logger, Transform, Filter, Human } = require('caterpillar')
186 | const level = 5
187 | const logger = new Logger({ lineLevel: level })
188 |
189 | const { createWriteStream } = require('fs')
190 | logger.pipe(createWriteStream('./debug.log'))
191 |
192 | class Uppercase extends Transform {
193 | format(entry) {
194 | if (entry.levelNumber <= 4) {
195 | entry.args.forEach(function (value, index) {
196 | if (typeof value === 'string') {
197 | entry.args[index] = value.toUpperCase()
198 | }
199 | })
200 | }
201 | return entry
202 | }
203 | }
204 |
205 | logger
206 | .pipe(new Filter({ filterLevel: 5 }))
207 | .pipe(new Uppercase())
208 | .pipe(new Human())
209 | .pipe(process.stdout)
210 |
211 | logger.log('warn', 'this is a warning, which is level', 4)
212 | logger.warn('this is a warning, which is level', 4)
213 | logger.log('debug', 'this is a debug message, which is level', 7)
214 | logger.warn('this is a debug message, which is level', 7)
215 | ```
216 |
217 | Finally, if we are using Caterpillar in web browser environments, instead of Node.js, instead of doing:
218 |
219 | ```javascript
220 | const { Logger, Transform, Filter, Human } = require('caterpillar')
221 | // ...
222 | logger.pipe(new Human()).pipe(process.stdout)
223 | // ...
224 | ```
225 |
226 | We would pipe to the Browser transform instead of to stdout.
227 |
228 | ```javascript
229 | const { Logger, Transform, Filter, Human, Browser } = require('caterpillar')
230 | // ...
231 | logger.pipe(new Human()).pipe(new Browser())
232 | // ...
233 | ```
234 |
235 | With this, you now have enough information to leverage the cross-platform power of Caterpillar for most purposes, and the power to write your own custom transforms which can be published as their own packages and shared.
236 |
237 |
238 |
239 | ## Install
240 |
241 | ### [npm](https://npmjs.com "npm is a package manager for javascript")
242 |
243 | - Install: `npm install --save caterpillar`
244 | - Import: `import * as pkg from ('caterpillar')`
245 | - Require: `const pkg = require('caterpillar')`
246 |
247 | ### [Deno](https://deno.land "Deno is a secure runtime for JavaScript and TypeScript, it is an alternative for Node.js")
248 |
249 | ``` typescript
250 | import * as pkg from 'https://unpkg.com/caterpillar@^8.2.0/edition-deno/index.ts'
251 | ```
252 | ### [Skypack](https://www.skypack.dev "Skypack is a JavaScript Delivery Network for modern web apps")
253 |
254 | ``` html
255 |
258 | ```
259 | ### [unpkg](https://unpkg.com "unpkg is a fast, global content delivery network for everything on npm")
260 |
261 | ``` html
262 |
265 | ```
266 | ### [jspm](https://jspm.io "Native ES Modules CDN")
267 |
268 | ``` html
269 |
272 | ```
273 | ### [Editions](https://editions.bevry.me "Editions are the best way to produce and consume packages you care about.")
274 |
275 | This package is published with the following editions:
276 | - `caterpillar` aliases `caterpillar/index.cjs` which uses the [Editions Autoloader](https://github.com/bevry/editions "You can use the Editions Autoloader to autoload the appropriate edition for your consumers environment") to automatically select the correct edition for the consumer's environment
277 | - `caterpillar/source/index.ts` is [TypeScript](https://www.typescriptlang.org/ "TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.") source code with [Import](https://babeljs.io/docs/learn-es2015/#modules "ECMAScript Modules") for modules
278 | - `caterpillar/edition-browsers/index.js` is [TypeScript](https://www.typescriptlang.org/ "TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.") compiled against [ES2022](https://en.wikipedia.org/wiki/ES2022 "ECMAScript 2022") for web browsers with [Import](https://babeljs.io/docs/learn-es2015/#modules "ECMAScript Modules") for modules
279 | - `caterpillar/edition-es2022/index.js` is [TypeScript](https://www.typescriptlang.org/ "TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.") compiled against [ES2022](https://en.wikipedia.org/wiki/ES2022 "ECMAScript 2022") for [Node.js](https://nodejs.org "Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine") 14 || 16 || 18 || 20 || 21 with [Require](https://nodejs.org/dist/latest-v5.x/docs/api/modules.html "Node/CJS Modules") for modules
280 | - `caterpillar/edition-es2017/index.js` is [TypeScript](https://www.typescriptlang.org/ "TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.") compiled against [ES2017](https://en.wikipedia.org/wiki/ES2017 "ECMAScript 2017") for [Node.js](https://nodejs.org "Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine") 8 || 10 || 12 || 14 || 16 || 18 || 20 || 21 with [Require](https://nodejs.org/dist/latest-v5.x/docs/api/modules.html "Node/CJS Modules") for modules
281 | - `caterpillar/edition-es2015/index.js` is [TypeScript](https://www.typescriptlang.org/ "TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.") compiled against [ES2015](https://babeljs.io/docs/en/learn#ecmascript-2015-features "ECMAScript 2015") for [Node.js](https://nodejs.org "Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine") 6 || 8 || 10 || 12 || 14 || 16 || 18 || 20 || 21 with [Require](https://nodejs.org/dist/latest-v5.x/docs/api/modules.html "Node/CJS Modules") for modules
282 | - `caterpillar/edition-es5/index.js` is [TypeScript](https://www.typescriptlang.org/ "TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.") compiled against ES5 for [Node.js](https://nodejs.org "Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine") 4 || 6 || 8 || 10 || 12 || 14 || 16 with [Require](https://nodejs.org/dist/latest-v5.x/docs/api/modules.html "Node/CJS Modules") for modules
283 | - `caterpillar/edition-es2017-esm/index.js` is [TypeScript](https://www.typescriptlang.org/ "TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.") compiled against [ES2017](https://en.wikipedia.org/wiki/ES2017 "ECMAScript 2017") for [Node.js](https://nodejs.org "Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine") 12 || 14 || 16 || 18 || 20 || 21 with [Import](https://babeljs.io/docs/learn-es2015/#modules "ECMAScript Modules") for modules
284 | - `caterpillar/edition-types/index.d.ts` is [TypeScript](https://www.typescriptlang.org/ "TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.") compiled Types with [Import](https://babeljs.io/docs/learn-es2015/#modules "ECMAScript Modules") for modules
285 | - `caterpillar/edition-deno/index.ts` is [TypeScript](https://www.typescriptlang.org/ "TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.") source code made to be compatible with [Deno](https://deno.land "Deno is a secure runtime for JavaScript and TypeScript, it is an alternative to Node.js")
286 |
287 |
288 |
289 |
290 |
291 | ## History
292 |
293 | [Discover the release history by heading on over to the `HISTORY.md` file.](https://github.com/bevry/caterpillar/blob/HEAD/HISTORY.md#files)
294 |
295 |
296 |
297 |
298 |
299 | ## Backers
300 |
301 | ### Code
302 |
303 | [Discover how to contribute via the `CONTRIBUTING.md` file.](https://github.com/bevry/caterpillar/blob/HEAD/CONTRIBUTING.md#files)
304 |
305 | #### Authors
306 |
307 | - [Benjamin Lupton](https://balupton.com) — Accelerating collaborative wisdom.
308 |
309 | #### Maintainers
310 |
311 | - [Benjamin Lupton](https://balupton.com) — Accelerating collaborative wisdom.
312 |
313 | #### Contributors
314 |
315 | - [Benjamin Lupton](https://github.com/balupton) — [view contributions](https://github.com/bevry/caterpillar/commits?author=balupton "View the GitHub contributions of Benjamin Lupton on repository bevry/caterpillar")
316 | - [t-visualappeal](https://github.com/t-visualappeal) — [view contributions](https://github.com/bevry/caterpillar/commits?author=t-visualappeal "View the GitHub contributions of t-visualappeal on repository bevry/caterpillar")
317 | - [Tim Helfensdörfer](https://github.com/thelfensdrfer) — [view contributions](https://github.com/bevry/caterpillar/commits?author=thelfensdrfer "View the GitHub contributions of Tim Helfensdörfer on repository bevry/caterpillar")
318 |
319 | ### Finances
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 | #### Sponsors
331 |
332 | - [Andrew Nesbitt](https://nesbitt.io) — Software engineer and researcher
333 | - [Balsa](https://balsa.com) — We're Balsa, and we're building tools for builders.
334 | - [Codecov](https://codecov.io) — Empower developers with tools to improve code quality and testing.
335 | - [Poonacha Medappa](https://poonachamedappa.com)
336 | - [Rob Morris](https://github.com/Rob-Morris)
337 | - [Sentry](https://sentry.io) — Real-time crash reporting for your web apps, mobile apps, and games.
338 | - [Syntax](https://syntax.fm) — Syntax Podcast
339 |
340 | #### Donors
341 |
342 | - [Andrew Nesbitt](https://nesbitt.io)
343 | - [Armen Mkrtchian](https://mogoni.dev)
344 | - [Balsa](https://balsa.com)
345 | - [Chad](https://opencollective.com/chad8)
346 | - [Codecov](https://codecov.io)
347 | - [dr.dimitru](https://veliovgroup.com)
348 | - [Elliott Ditman](https://elliottditman.com)
349 | - [entroniq](https://gitlab.com/entroniq)
350 | - [GitHub](https://github.com/about)
351 | - [Hunter Beast](https://cryptoquick.com)
352 | - [Jean-Luc Geering](https://github.com/jlgeering)
353 | - [Michael Duane Mooring](https://mdm.cc)
354 | - [Michael Harry Scepaniak](https://michaelscepaniak.com)
355 | - [Mohammed Shah](https://github.com/smashah)
356 | - [Mr. Henry](https://mrhenry.be)
357 | - [Nermal](https://arjunaditya.vercel.app)
358 | - [Pleo](https://pleo.io)
359 | - [Poonacha Medappa](https://poonachamedappa.com)
360 | - [Rob Morris](https://github.com/Rob-Morris)
361 | - [Robert de Forest](https://github.com/rdeforest)
362 | - [Sentry](https://sentry.io)
363 | - [ServieJS](https://github.com/serviejs)
364 | - [Skunk Team](https://skunk.team)
365 | - [Syntax](https://syntax.fm)
366 | - [WriterJohnBuck](https://github.com/WriterJohnBuck)
367 |
368 |
369 |
370 |
371 |
372 | ## License
373 |
374 | Unless stated otherwise all works are:
375 |
376 | - Copyright © [Benjamin Lupton](https://balupton.com)
377 |
378 | and licensed under:
379 |
380 | - [Artistic License 2.0](http://spdx.org/licenses/Artistic-2.0.html)
381 |
382 |
383 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Security Practices
4 |
5 | This project meets standardized secure software development practices, including 2FA for all members, password managers with monitoring, secure secret retrieval instead of storage. [Learn about our practices.](https://tidelift.com/funding/github/npm/caterpillar)
6 |
7 | ## Supported Versions
8 |
9 | This project uses [Bevry's automated tooling](https://github.com/bevry/boundation) to deliver the latest updates, fixes, and improvements inside the latest release while still maintaining widespread ecosystem compatibility.
10 |
11 | [Refer to supported ecosystem versions: `Editions` section in `README.md`](https://github.com/bevry/caterpillar/blob/master/README.md#Editions)
12 |
13 | [Refer to automated support of ecosystem versions: `boundation` entries in `HISTORY.md`](https://github.com/bevry/caterpillar/blob/master/HISTORY.md)
14 |
15 | Besides testing and verification, out CI also [auto-merges](https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions) [Dependabot security updates](https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/about-dependabot-security-updates) and [auto-publishes](https://github.com/bevry-actions/npm) successful builds of the [`master` branch](https://github.com/bevry/wait/actions?query=branch%3Amaster) to the [`next` version tag](https://www.npmjs.com/package/caterpillar?activeTab=versions), offering immediate resolutions before scheduled maintenance releases.
16 |
17 | ## Reporting a Vulnerability
18 |
19 | [Report the vulnerability to the project owners.](https://github.com/bevry/caterpillar/security/advisories)
20 |
21 | [Report the vulnerability to Tidelift.](https://tidelift.com/security)
22 |
--------------------------------------------------------------------------------
/index.cjs:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // auto-generated by boundation, do not update manually
3 | /** @type {typeof import("./edition-types/index.d.ts") } */
4 | module.exports = require('editions').requirePackage(__dirname, require, 'index.js')
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Caterpillar",
3 | "name": "caterpillar",
4 | "version": "8.2.0",
5 | "license": "Artistic-2.0",
6 | "description": "Caterpillar is the ultimate logging system for Deno, Node.js, and Web Browsers. Log levels are implemented to the RFC standard. Log entries can be filtered and piped to various streams, including coloured output to the terminal, the browser's console, and debug files. You can even write your own transforms.",
7 | "homepage": "https://github.com/bevry/caterpillar",
8 | "funding": "https://bevry.me/fund",
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/bevry/caterpillar.git"
12 | },
13 | "bugs": {
14 | "url": "https://github.com/bevry/caterpillar/issues"
15 | },
16 | "keywords": [
17 | "browser",
18 | "caterpillar",
19 | "console",
20 | "debug",
21 | "deno",
22 | "deno-edition",
23 | "deno-entry",
24 | "denoland",
25 | "dom",
26 | "es2015",
27 | "es2017",
28 | "es2022",
29 | "es5",
30 | "log",
31 | "logger",
32 | "logging",
33 | "module",
34 | "node",
35 | "stream",
36 | "transform",
37 | "typed",
38 | "types",
39 | "typescript"
40 | ],
41 | "badges": {
42 | "list": [
43 | "githubworkflow",
44 | "npmversion",
45 | "npmdownloads",
46 | "---",
47 | "githubsponsors",
48 | "thanksdev",
49 | "patreon",
50 | "liberapay",
51 | "buymeacoffee",
52 | "opencollective",
53 | "crypto",
54 | "paypal",
55 | "---",
56 | "discord",
57 | "twitch"
58 | ],
59 | "config": {
60 | "githubWorkflow": "bevry",
61 | "githubSponsorsUsername": "balupton",
62 | "thanksdevGithubUsername": "bevry",
63 | "buymeacoffeeUsername": "balupton",
64 | "cryptoURL": "https://bevry.me/crypto",
65 | "flattrUsername": "balupton",
66 | "liberapayUsername": "bevry",
67 | "opencollectiveUsername": "bevry",
68 | "patreonUsername": "bevry",
69 | "paypalURL": "https://bevry.me/paypal",
70 | "wishlistURL": "https://bevry.me/wishlist",
71 | "discordServerID": "1147436445783560193",
72 | "discordServerInvite": "nQuXddV7VP",
73 | "twitchUsername": "balupton",
74 | "githubUsername": "bevry",
75 | "githubRepository": "caterpillar",
76 | "githubSlug": "bevry/caterpillar",
77 | "npmPackageName": "caterpillar"
78 | }
79 | },
80 | "author": "Benjamin Lupton (https://balupton.com) (https://github.com/balupton)",
81 | "authors": [
82 | "Benjamin Lupton (https://balupton.com) (https://github.com/balupton): Accelerating collaborative wisdom."
83 | ],
84 | "maintainers": [
85 | "Benjamin Lupton (https://balupton.com) (https://github.com/balupton): Accelerating collaborative wisdom."
86 | ],
87 | "contributors": [
88 | "Benjamin Lupton (https://balupton.com) (https://github.com/balupton)",
89 | "t-visualappeal (https://github.com/t-visualappeal)",
90 | "Tim Helfensdörfer (https://thelfensdrfer.de) (https://github.com/thelfensdrfer)"
91 | ],
92 | "sponsors": [
93 | "Andrew Nesbitt (https://nesbitt.io) (https://github.com/andrew): Software engineer and researcher",
94 | "Balsa (https://balsa.com) (https://github.com/balsa): We're Balsa, and we're building tools for builders.",
95 | "Codecov (https://codecov.io) (https://github.com/codecov): Empower developers with tools to improve code quality and testing.",
96 | "Poonacha Medappa (https://poonachamedappa.com) (https://github.com/km-Poonacha)",
97 | "Rob Morris (https://github.com/Rob-Morris)",
98 | "Sentry (https://sentry.io) (https://github.com/getsentry): Real-time crash reporting for your web apps, mobile apps, and games.",
99 | "Syntax (https://syntax.fm) (https://github.com/syntaxfm): Syntax Podcast"
100 | ],
101 | "donors": [
102 | "Andrew Nesbitt (https://nesbitt.io) (https://github.com/andrew)",
103 | "Armen Mkrtchian (https://mogoni.dev) (https://github.com/Armenm)",
104 | "Balsa (https://balsa.com) (https://github.com/balsa)",
105 | "Chad (https://opencollective.com/chad8)",
106 | "Codecov (https://codecov.io) (https://github.com/codecov)",
107 | "dr.dimitru (https://veliovgroup.com) (https://github.com/dr-dimitru)",
108 | "Elliott Ditman (https://elliottditman.com) (https://github.com/elliottditman)",
109 | "entroniq (https://gitlab.com/entroniq) (https://thanks.dev/d/gl/entroniq)",
110 | "GitHub (https://github.com/about) (https://github.com/github)",
111 | "Hunter Beast (https://cryptoquick.com) (https://github.com/cryptoquick)",
112 | "Jean-Luc Geering (https://github.com/jlgeering) (https://opencollective.com/jlgeering) (https://twitter.com/jlgeering)",
113 | "Michael Duane Mooring (https://mdm.cc) (https://github.com/mikeumus) (https://opencollective.com/mikeumus) (https://twitter.com/mikeumus)",
114 | "Michael Harry Scepaniak (https://michaelscepaniak.com) (https://github.com/hispanic)",
115 | "Mohammed Shah (https://github.com/smashah) (https://thanks.dev/d/gh/smashah) (https://twitter.com/smashah)",
116 | "Mr. Henry (https://mrhenry.be) (https://github.com/mrhenry)",
117 | "Nermal (https://arjunaditya.vercel.app) (https://github.com/nermalcat69)",
118 | "Pleo (https://pleo.io) (https://github.com/pleo-io)",
119 | "Poonacha Medappa (https://poonachamedappa.com) (https://github.com/km-Poonacha)",
120 | "Rob Morris (https://github.com/Rob-Morris)",
121 | "Robert de Forest (https://github.com/rdeforest)",
122 | "Sentry (https://sentry.io) (https://github.com/getsentry)",
123 | "ServieJS (https://github.com/serviejs) (https://thanks.dev/d/gh/serviejs)",
124 | "Skunk Team (https://skunk.team) (https://github.com/skunkteam)",
125 | "Syntax (https://syntax.fm) (https://github.com/syntaxfm)",
126 | "WriterJohnBuck (https://github.com/WriterJohnBuck)"
127 | ],
128 | "engines": {
129 | "node": ">=4"
130 | },
131 | "editions": [
132 | {
133 | "description": "TypeScript source code with Import for modules",
134 | "directory": "source",
135 | "entry": "index.ts",
136 | "tags": [
137 | "source",
138 | "typescript",
139 | "import"
140 | ],
141 | "engines": false
142 | },
143 | {
144 | "description": "TypeScript compiled against ES2022 for web browsers with Import for modules",
145 | "directory": "edition-browsers",
146 | "entry": "index.js",
147 | "tags": [
148 | "compiled",
149 | "javascript",
150 | "import"
151 | ],
152 | "engines": {
153 | "node": false,
154 | "browsers": "defaults"
155 | }
156 | },
157 | {
158 | "description": "TypeScript compiled against ES2022 for Node.js 14 || 16 || 18 || 20 || 21 with Require for modules",
159 | "directory": "edition-es2022",
160 | "entry": "index.js",
161 | "tags": [
162 | "compiled",
163 | "javascript",
164 | "es2022",
165 | "require"
166 | ],
167 | "engines": {
168 | "node": "14 || 16 || 18 || 20 || 21",
169 | "browsers": false
170 | }
171 | },
172 | {
173 | "description": "TypeScript compiled against ES2017 for Node.js 8 || 10 || 12 || 14 || 16 || 18 || 20 || 21 with Require for modules",
174 | "directory": "edition-es2017",
175 | "entry": "index.js",
176 | "tags": [
177 | "compiled",
178 | "javascript",
179 | "es2017",
180 | "require"
181 | ],
182 | "engines": {
183 | "node": "8 || 10 || 12 || 14 || 16 || 18 || 20 || 21",
184 | "browsers": false
185 | }
186 | },
187 | {
188 | "description": "TypeScript compiled against ES2015 for Node.js 6 || 8 || 10 || 12 || 14 || 16 || 18 || 20 || 21 with Require for modules",
189 | "directory": "edition-es2015",
190 | "entry": "index.js",
191 | "tags": [
192 | "compiled",
193 | "javascript",
194 | "es2015",
195 | "require"
196 | ],
197 | "engines": {
198 | "node": "6 || 8 || 10 || 12 || 14 || 16 || 18 || 20 || 21",
199 | "browsers": false
200 | }
201 | },
202 | {
203 | "description": "TypeScript compiled against ES5 for Node.js 4 || 6 || 8 || 10 || 12 || 14 || 16 with Require for modules",
204 | "directory": "edition-es5",
205 | "entry": "index.js",
206 | "tags": [
207 | "compiled",
208 | "javascript",
209 | "es5",
210 | "require"
211 | ],
212 | "engines": {
213 | "node": "4 || 6 || 8 || 10 || 12 || 14 || 16",
214 | "browsers": false
215 | }
216 | },
217 | {
218 | "description": "TypeScript compiled against ES2017 for Node.js 12 || 14 || 16 || 18 || 20 || 21 with Import for modules",
219 | "directory": "edition-es2017-esm",
220 | "entry": "index.js",
221 | "tags": [
222 | "compiled",
223 | "javascript",
224 | "es2017",
225 | "import"
226 | ],
227 | "engines": {
228 | "node": "12 || 14 || 16 || 18 || 20 || 21",
229 | "browsers": false
230 | }
231 | },
232 | {
233 | "description": "TypeScript compiled Types with Import for modules",
234 | "directory": "edition-types",
235 | "entry": "index.d.ts",
236 | "tags": [
237 | "compiled",
238 | "types",
239 | "import"
240 | ],
241 | "engines": false
242 | },
243 | {
244 | "description": "TypeScript source code made to be compatible with Deno",
245 | "directory": "edition-deno",
246 | "entry": "index.ts",
247 | "tags": [
248 | "typescript",
249 | "import",
250 | "deno"
251 | ],
252 | "engines": {
253 | "deno": true,
254 | "browsers": true
255 | }
256 | }
257 | ],
258 | "types": "edition-types/index.d.ts",
259 | "type": "module",
260 | "main": "index.cjs",
261 | "exports": {
262 | "node": {
263 | "types": "./edition-types/index.d.ts",
264 | "import": "./edition-es2017-esm/index.js",
265 | "default": "./index.cjs",
266 | "require": "./edition-es2022/index.js"
267 | },
268 | "browser": {
269 | "types": "./edition-types/index.d.ts",
270 | "import": "./edition-browsers/index.js"
271 | }
272 | },
273 | "deno": "edition-deno/index.ts",
274 | "browser": "edition-browsers/index.js",
275 | "module": "edition-browsers/index.js",
276 | "dependencies": {
277 | "@bevry/ansi": "^6.9.0",
278 | "editions": "^6.21.0",
279 | "get-current-line": "^7.3.0",
280 | "rfc-log-levels": "^4.2.0"
281 | },
282 | "devDependencies": {
283 | "@types/node": "^20.10.5",
284 | "@typescript-eslint/eslint-plugin": "^6.16.0",
285 | "@typescript-eslint/parser": "^6.16.0",
286 | "assert-helpers": "^11.12.0",
287 | "eslint": "^8.56.0",
288 | "eslint-config-bevry": "^5.3.0",
289 | "eslint-config-prettier": "^9.1.0",
290 | "eslint-plugin-prettier": "^5.1.2",
291 | "kava": "^7.8.0",
292 | "make-deno-edition": "^2.2.0",
293 | "prettier": "^3.1.1",
294 | "projectz": "^4.1.1",
295 | "typedoc": "^0.25.4",
296 | "typescript": "5.3.3",
297 | "valid-directory": "^4.8.0",
298 | "valid-module": "^2.6.0"
299 | },
300 | "scripts": {
301 | "our:clean": "rm -rf ./docs ./edition* ./es2015 ./es5 ./out ./.next",
302 | "our:compile": "npm run our:compile:deno && npm run our:compile:edition-browsers && npm run our:compile:edition-es2015 && npm run our:compile:edition-es2017 && npm run our:compile:edition-es2017-esm && npm run our:compile:edition-es2022 && npm run our:compile:edition-es5 && npm run our:compile:edition-types",
303 | "our:compile:deno": "make-deno-edition --attempt",
304 | "our:compile:edition-browsers": "tsc --module ESNext --target ES2022 --outDir ./edition-browsers --project tsconfig.json && ( test ! -d edition-browsers/source || ( mv edition-browsers/source edition-temp && rm -rf edition-browsers && mv edition-temp edition-browsers ) )",
305 | "our:compile:edition-es2015": "tsc --module commonjs --target ES2015 --outDir ./edition-es2015 --project tsconfig.json && ( test ! -d edition-es2015/source || ( mv edition-es2015/source edition-temp && rm -rf edition-es2015 && mv edition-temp edition-es2015 ) ) && printf '%s' '{\"type\": \"commonjs\"}' > edition-es2015/package.json",
306 | "our:compile:edition-es2017": "tsc --module commonjs --target ES2017 --outDir ./edition-es2017 --project tsconfig.json && ( test ! -d edition-es2017/source || ( mv edition-es2017/source edition-temp && rm -rf edition-es2017 && mv edition-temp edition-es2017 ) ) && printf '%s' '{\"type\": \"commonjs\"}' > edition-es2017/package.json",
307 | "our:compile:edition-es2017-esm": "tsc --module ESNext --target ES2017 --outDir ./edition-es2017-esm --project tsconfig.json && ( test ! -d edition-es2017-esm/source || ( mv edition-es2017-esm/source edition-temp && rm -rf edition-es2017-esm && mv edition-temp edition-es2017-esm ) ) && printf '%s' '{\"type\": \"module\"}' > edition-es2017-esm/package.json",
308 | "our:compile:edition-es2022": "tsc --module commonjs --target ES2022 --outDir ./edition-es2022 --project tsconfig.json && ( test ! -d edition-es2022/source || ( mv edition-es2022/source edition-temp && rm -rf edition-es2022 && mv edition-temp edition-es2022 ) ) && printf '%s' '{\"type\": \"commonjs\"}' > edition-es2022/package.json",
309 | "our:compile:edition-es5": "tsc --module commonjs --target ES5 --outDir ./edition-es5 --project tsconfig.json && ( test ! -d edition-es5/source || ( mv edition-es5/source edition-temp && rm -rf edition-es5 && mv edition-temp edition-es5 ) ) && printf '%s' '{\"type\": \"commonjs\"}' > edition-es5/package.json",
310 | "our:compile:edition-types": "tsc --emitDeclarationOnly --declaration --declarationMap --declarationDir ./edition-types --project tsconfig.json && ( test ! -d edition-types/source || ( mv edition-types/source edition-temp && rm -rf edition-types && mv edition-temp edition-types ) )",
311 | "our:deploy": "printf '%s\n' 'no need for this project'",
312 | "our:meta": "npm run our:meta:docs && npm run our:meta:projectz",
313 | "our:meta:docs": "npm run our:meta:docs:typedoc",
314 | "our:meta:docs:typedoc": "rm -rf ./docs && typedoc --exclude '**/+(*test*|node_modules)' --excludeExternals --out ./docs ./source",
315 | "our:meta:projectz": "projectz --offline",
316 | "our:release": "npm run our:release:prepare && npm run our:release:check-changelog && npm run our:release:check-dirty && npm run our:release:tag && npm run our:release:push",
317 | "our:release:check-changelog": "cat ./HISTORY.md | grep \"v$npm_package_version\" || (printf '%s\n' \"add a changelog entry for v$npm_package_version\" && exit -1)",
318 | "our:release:check-dirty": "git diff --exit-code",
319 | "our:release:prepare": "npm run our:clean && npm run our:compile && npm run our:test && npm run our:meta",
320 | "our:release:push": "git push origin && git push origin --tags",
321 | "our:release:tag": "export MESSAGE=$(cat ./HISTORY.md | sed -n \"/## v$npm_package_version/,/##/p\" | sed 's/## //' | awk 'NR>1{print buf}{buf = $0}') && test \"$MESSAGE\" || (printf '%s\n' 'proper changelog entry not found' && exit -1) && git tag \"v$npm_package_version\" -am \"$MESSAGE\"",
322 | "our:setup": "npm run our:setup:install",
323 | "our:setup:install": "npm install",
324 | "our:test": "npm run our:verify && npm test",
325 | "our:verify": "npm run our:verify:eslint && npm run our:verify:module && npm run our:verify:prettier",
326 | "our:verify:eslint": "eslint --fix --ignore-pattern '**/*.d.ts' --ignore-pattern '**/vendor/' --ignore-pattern '**/node_modules/' --ext .mjs,.js,.jsx,.ts,.tsx ./source",
327 | "our:verify:module": "valid-module",
328 | "our:verify:prettier": "prettier --write .",
329 | "test": "node ./test.cjs"
330 | },
331 | "boundation": {
332 | "dom": true
333 | },
334 | "eslintConfig": {
335 | "extends": [
336 | "bevry"
337 | ],
338 | "rules": {
339 | "class-methods-use-this": "off"
340 | }
341 | },
342 | "prettier": {
343 | "semi": false,
344 | "singleQuote": true,
345 | "trailingComma": "es5",
346 | "endOfLine": "lf"
347 | }
348 | }
349 |
--------------------------------------------------------------------------------
/source/index.ts:
--------------------------------------------------------------------------------
1 | export * from './transform.js'
2 | export * from './logger.js'
3 | export * from './transforms/filter.js'
4 | export * from './transforms/human.js'
5 | export * from './transforms/browser.js'
6 |
--------------------------------------------------------------------------------
/source/logger.ts:
--------------------------------------------------------------------------------
1 | import getLogLevel, { rfcLogLevels, LevelInfo, LevelsMap } from 'rfc-log-levels'
2 | import getCurrentLine, { Offset, Location } from 'get-current-line'
3 | import { Transform } from './transform.js'
4 |
5 | /** The log entry that Caterpillar creates and forwards to its transforms */
6 | export interface LogEntry extends LevelInfo, Location {
7 | /** the iso string of when the log occured */
8 | date: string
9 | /** all the arguments that were after the log level */
10 | args: any[]
11 | }
12 |
13 | /** Configuration for the Caterpillar Logger */
14 | export interface LoggerOptions {
15 | /** Use to override the default value of {@link Logger.lineOffset} */
16 | lineOffset?: Offset
17 |
18 | /** Use to override the default value of {@link Logger.levels} */
19 | levels?: LevelsMap
20 |
21 | /** Use to override the default value of {@link Logger.defaultLevelInfo} */
22 | defaultLevel?: number | string
23 |
24 | /** Use to override the default value of {@link Logger.lineLevel} */
25 | lineLevel?: number
26 | }
27 |
28 | /**
29 | * Logger.
30 | * This is what we write to.
31 | * @example Creation
32 | * ``` javascript
33 | * // Via class
34 | * import { Logger } from 'caterpillar'
35 | * const logger = new Logger()
36 | * ```
37 | */
38 | export class Logger extends Transform {
39 | /**
40 | * The configuration to use for the line offset.
41 | * This defaults to any file path that includes `logger`, and any method that includes the word `log`.
42 | */
43 | public lineOffset: Offset = {
44 | file: /logger/i,
45 | method: /log/i,
46 | }
47 |
48 | /**
49 | * The mapping of log level names to log level numbers.
50 | * Defaults to the RFC Log Level configuration.
51 | */
52 | public levels: LevelsMap = rfcLogLevels
53 |
54 | /**
55 | * The log level information to use when the log level was unable to be determined.
56 | * Defaults to the info log level.
57 | */
58 | public defaultLevelInfo!: LevelInfo
59 |
60 | /** Set the default level info via a level number or name. */
61 | public set defaultLevel(value: number | string) {
62 | const levelInfo = this.getLogLevel(value)
63 | if (levelInfo == null) {
64 | throw new Error(
65 | `caterpillar: the intended value of ${value} for the default log level not found in the configured levels`
66 | )
67 | }
68 | this.defaultLevelInfo = levelInfo
69 | }
70 |
71 | /**
72 | * Only fetch line information for entries that have a log level equal to, or below this number.
73 | * You should only specify this if you need it, as fFetching line information for thousands of log entries, which is typical in large applications, will slow your application down dramatically.
74 | * If not specified, defaults to `-Infinity` which effect is to ignore gathering line information for all log levels.
75 | */
76 | public lineLevel: number = -Infinity
77 |
78 | /** Create our instance and apply our configuraiton options. */
79 | constructor(opts?: LoggerOptions) {
80 | super()
81 |
82 | // options
83 | if (opts?.lineOffset != null) this.lineOffset = opts.lineOffset
84 | if (opts?.levels != null) this.levels = opts.levels
85 | if (opts?.lineLevel != null) this.lineLevel = opts.lineLevel
86 |
87 | // options: default level
88 | this.defaultLevel = opts?.defaultLevel ?? 'info'
89 |
90 | // dereference
91 | this.levels = Object.assign({}, this.levels)
92 | }
93 |
94 | /** Alias for {@link getLogLevel} using the configured logger levels as reference. */
95 | getLogLevel(value: number | string) {
96 | return getLogLevel(value, this.levels)
97 | }
98 |
99 | /** Takes an arguments array and tranforms it into a log entry. */
100 | format(args: any): LogEntry {
101 | // fetch the level
102 | const level = args.shift()
103 | let levelInfo =
104 | level === 'default' ? this.defaultLevelInfo : this.getLogLevel(level)
105 | if (levelInfo == null) {
106 | // fallback to the default log level
107 | levelInfo = this.defaultLevelInfo
108 | // as the level (first param) was not actually a level, put it back
109 | args.unshift(level)
110 | }
111 |
112 | // fetch the date
113 | const date = new Date().toISOString()
114 |
115 | // fetch the line information
116 | const lineInfo =
117 | levelInfo.levelNumber <= this.lineLevel
118 | ? getCurrentLine(this.lineOffset)
119 | : {
120 | line: -1,
121 | char: -1,
122 | method: '',
123 | file: '',
124 | }
125 |
126 | // put it all together
127 | return Object.assign({ date, args }, levelInfo, lineInfo)
128 | }
129 |
130 | /**
131 | * Log the arguments into the logger stream as formatted data with debugging information.
132 | * Such that our transformers can deal with it intelligently.
133 | *
134 | * @example Inputs
135 | * ``` javascript
136 | * logger.log('note', 'this is working swell')
137 | * ```
138 | * ``` javascript
139 | * logger.log('this', 'worked', 'swell')
140 | * ```
141 | *
142 | * @example Results
143 | * ``` json
144 | * {
145 | * "args": ["this is working swell"],
146 | * "date": "2013-04-25T10:18:25.722Z",
147 | * "levelNumber": 5,
148 | * "levelName": "notice",
149 | * "line": "59",
150 | * "method": "Object.",
151 | * "file": "/Users/balupton/some-project/calling-file.js"
152 | * }
153 | * ```
154 | * ``` json
155 | * {
156 | * "args": ["this", "worked", "well"],
157 | * "date": "2013-04-25T10:18:26.539Z",
158 | * "levelNumber": 6,
159 | * "levelName": "info",
160 | * "line": "60",
161 | * "method": "Object.",
162 | * "file": "/Users/balupton/some-project/calling-file.js"
163 | * }
164 | * ```
165 | */
166 | log(...args: any) {
167 | this.write(args)
168 | }
169 |
170 | /** Alias for log which prefixes the error log level */
171 | error(...args: any) {
172 | this.write(['error', ...args])
173 | }
174 |
175 | /** Alias for log which prefixes the warn log level */
176 | warn(...args: any) {
177 | this.write(['warn', ...args])
178 | }
179 |
180 | /** Alias for log which prefixes the info log level */
181 | info(...args: any) {
182 | this.write(['info', ...args])
183 | }
184 |
185 | /** Alias for log which prefixes the debug log level */
186 | debug(...args: any) {
187 | this.write(['debug', ...args])
188 | }
189 | }
190 |
191 | export default Logger
192 |
--------------------------------------------------------------------------------
/source/test.ts:
--------------------------------------------------------------------------------
1 | import { Logger, Filter, Human, Browser, LogEntry } from './index.js'
2 | import { PassThrough } from 'stream'
3 | import kava from 'kava'
4 | import { equal, deepEqual } from 'assert-helpers'
5 | import { ok } from 'assert'
6 |
7 | // Prepare
8 | function cleanChangingLogger(item: any) {
9 | item = JSON.parse(item)
10 | item.date = item.date.replace(
11 | /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/,
12 | 'date'
13 | )
14 | try {
15 | if (item.file.includes('test.js') === false)
16 | ok(false, 'file info was not as expected')
17 | if (item.method.includes('testCaller') === false)
18 | ok(false, 'method info was not as expected')
19 | if (item.line === -1) ok(false, 'line info was not found')
20 | if (item.char === -1) ok(false, 'char info was not found')
21 | } catch (err) {
22 | console.error(item)
23 | throw err
24 | }
25 | item.file = 'file'
26 | item.line = 'line'
27 | item.char = 'char'
28 | item.method = 'method'
29 | return item
30 | }
31 | function cleanChangingHuman(item: string) {
32 | item = item
33 | .replace(/\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3}Z\]/, 'date')
34 | .replace(/\[.+?:\d+:\d+\]/, 'file:line:char')
35 | .replace(/\[.+?\]/, 'method')
36 | return item
37 | }
38 |
39 | // Test
40 | kava.suite('caterpillar', function (suite) {
41 | suite('logger', function (suite, test) {
42 | const logger = new Logger({ lineLevel: 7 })
43 | const output = new PassThrough()
44 | const actual: string[] = []
45 | const expected: string[] = [
46 | '{"date":"2013-05-07T11:12:43.982Z","args":["this is emergency and is level 0"],"levelNumber":0,"levelName":"emergency","line":"1","char":"20","method":"testCaller","file":"my/test.js"}',
47 | '{"date":"2013-05-07T11:12:43.986Z","args":["this is alert and is level 1"],"levelNumber":1,"levelName":"alert","line":"1","char":"20","method":"testCaller","file":"my/test.js"}',
48 | '{"date":"2013-05-07T11:12:43.987Z","args":["this is critical and is level 2"],"levelNumber":2,"levelName":"critical","line":"1","char":"20","method":"testCaller","file":"my/test.js"}',
49 | '{"date":"2013-05-07T11:12:43.987Z","args":["this is error and is level 3"],"levelNumber":3,"levelName":"error","line":"1","char":"20","method":"testCaller","file":"my/test.js"}',
50 | '{"date":"2013-05-07T11:12:43.988Z","args":["this is warning and is level 4"],"levelNumber":4,"levelName":"warning","line":"1","char":"20","method":"testCaller","file":"my/test.js"}',
51 | '{"date":"2013-05-07T11:12:43.988Z","args":["this is notice and is level 5"],"levelNumber":5,"levelName":"notice","line":"1","char":"20","method":"testCaller","file":"my/test.js"}',
52 | '{"date":"2013-05-07T11:12:43.989Z","args":["this is info and is level 6"],"levelNumber":6,"levelName":"info","line":"1","char":"20","method":"testCaller","file":"my/test.js"}',
53 | '{"date":"2013-05-07T11:12:43.990Z","args":["this is debug and is level 7"],"levelNumber":7,"levelName":"debug","line":"1","char":"20","method":"testCaller","file":"my/test.js"}',
54 | '{"date":"2013-05-07T11:12:43.991Z","args":["this is emerg and is level 0"],"levelNumber":0,"levelName":"emergency","line":"1","char":"20","method":"testCaller","file":"my/test.js"}',
55 | '{"date":"2013-05-07T11:12:43.991Z","args":["this is crit and is level 2"],"levelNumber":2,"levelName":"critical","line":"1","char":"20","method":"testCaller","file":"my/test.js"}',
56 | '{"date":"2013-05-07T11:12:43.992Z","args":["this is err and is level 3"],"levelNumber":3,"levelName":"error","line":"1","char":"20","method":"testCaller","file":"my/test.js"}',
57 | '{"date":"2013-05-07T11:12:43.992Z","args":["this is warn and is level 4"],"levelNumber":4,"levelName":"warning","line":"1","char":"20","method":"testCaller","file":"my/test.js"}',
58 | '{"date":"2013-05-07T11:12:43.992Z","args":["this is note and is level 5"],"levelNumber":5,"levelName":"notice","line":"1","char":"20","method":"testCaller","file":"my/test.js"}',
59 | '{"date":"2013-05-07T11:12:43.995Z","args":["this is unknown and is level 6"],"levelNumber":6,"levelName":"info","line":"1","char":"20","method":"testCaller","file":"my/test.js"}',
60 | ]
61 |
62 | output.on('data', function (chunk) {
63 | actual.push(chunk.toString())
64 | })
65 |
66 | test('should pipe correctly', function () {
67 | logger.pipe(output)
68 | })
69 |
70 | test('should log messages', function testCaller() {
71 | const levels = logger.levels
72 | for (const name in levels) {
73 | if (levels.hasOwnProperty(name)) {
74 | const number = levels[name]
75 | const message = `this is ${name} and is level ${number}`
76 | logger.log(name, message)
77 | }
78 | }
79 | logger.log('this is unknown and is level 6')
80 | })
81 |
82 | test('should provide the expected output', function (done) {
83 | output.on('end', function () {
84 | const actualCleaned = actual.map(cleanChangingLogger)
85 | const expectedCleaned = expected.map(cleanChangingLogger)
86 | console.dir(actualCleaned)
87 | console.dir(expectedCleaned)
88 | equal(actualCleaned.length, expectedCleaned.length, 'lengths')
89 | actualCleaned.forEach(function (result, index) {
90 | deepEqual(result, expectedCleaned[index], 'results')
91 | })
92 | done()
93 | })
94 | logger.end()
95 | })
96 | })
97 |
98 | suite('filter', function (suite, test) {
99 | const logger = new Logger()
100 | const filter = new Filter({ filterLevel: 5 })
101 | const output = new PassThrough()
102 | const result: LogEntry[] = []
103 |
104 | output.on('data', function (chunk) {
105 | result.push(JSON.parse(chunk.toString()))
106 | })
107 |
108 | test('should pipe correctly', function () {
109 | logger.pipe(filter).pipe(output)
110 | })
111 |
112 | test('should log messages', function testCaller() {
113 | logger.log(5, 'first')
114 | logger.log(6, 'second') // this one should be excluded
115 | logger.log(5, 'third')
116 | })
117 |
118 | test('should provide the expected output', function (done) {
119 | output.on('end', function () {
120 | equal(result.length, 2, 'length')
121 | equal(result[0].args[0], 'first')
122 | equal(result[1].args[0], 'third')
123 | done()
124 | })
125 | logger.end()
126 | })
127 | })
128 |
129 | suite('human', function (suite) {
130 | suite('instantiation', function (suite, test) {
131 | test('should instantiate correctly', function () {
132 | const human = new Human()
133 | equal(human.color, true, 'default color was applied correctly')
134 | })
135 | test('should instantiate correctly, with config', function () {
136 | const human = new Human({ color: false })
137 | equal(human.color, false, 'custom color was applied correctly')
138 | })
139 | })
140 |
141 | function addSuite(
142 | name: string,
143 | config: { color?: boolean; lineLevel?: number },
144 | expected: string[],
145 | cleaner?: typeof cleanChangingHuman
146 | ) {
147 | suite(name, function (suite, test) {
148 | const logger = new Logger(config)
149 | const human = new Human(config)
150 | const output = new PassThrough()
151 | let actual: string[] = []
152 | if (cleaner) expected = expected.map(cleaner)
153 |
154 | output.on('data', function (chunk) {
155 | actual.push(chunk.toString())
156 | })
157 |
158 | test('should pipe correctly', function () {
159 | logger.pipe(human).pipe(output)
160 | })
161 |
162 | test('should log messages', function () {
163 | const levels = logger.levels
164 | Object.keys(levels).forEach(function testCaller(name) {
165 | const code = levels[name]
166 | const message = `this is ${name} and is level ${code}`
167 | logger.log(name, message)
168 | })
169 | })
170 |
171 | test('should provide the expected output', function (done) {
172 | output.on('end', function () {
173 | if (cleaner) actual = actual.map(cleaner)
174 | equal(actual.length, expected.length, 'length was expected')
175 | actual.forEach(function (result, index) {
176 | equal(result, expected[index], 'result was expected')
177 | })
178 | done()
179 | })
180 | logger.end()
181 | })
182 | })
183 | }
184 |
185 | addSuite('logging without colors', { color: false }, [
186 | 'emergency: this is emergency and is level 0\n',
187 | 'alert: this is alert and is level 1\n',
188 | 'critical: this is critical and is level 2\n',
189 | 'error: this is error and is level 3\n',
190 | 'warning: this is warning and is level 4\n',
191 | 'notice: this is notice and is level 5\n',
192 | 'info: this is info and is level 6\n',
193 | 'debug: this is debug and is level 7\n',
194 | 'emergency: this is emerg and is level 0\n',
195 | 'critical: this is crit and is level 2\n',
196 | 'error: this is err and is level 3\n',
197 | 'warning: this is warn and is level 4\n',
198 | 'notice: this is note and is level 5\n',
199 | ])
200 |
201 | addSuite('logging with colors', {}, [
202 | '\u001b[31memergency:\u001b[39m this is emergency and is level 0\n',
203 | '\u001b[31malert:\u001b[39m this is alert and is level 1\n',
204 | '\u001b[31mcritical:\u001b[39m this is critical and is level 2\n',
205 | '\u001b[31merror:\u001b[39m this is error and is level 3\n',
206 | '\u001b[33mwarning:\u001b[39m this is warning and is level 4\n',
207 | '\u001b[33mnotice:\u001b[39m this is notice and is level 5\n',
208 | '\u001b[32minfo:\u001b[39m this is info and is level 6\n',
209 | '\u001b[32mdebug:\u001b[39m this is debug and is level 7\n',
210 | '\u001b[31memergency:\u001b[39m this is emerg and is level 0\n',
211 | '\u001b[31mcritical:\u001b[39m this is crit and is level 2\n',
212 | '\u001b[31merror:\u001b[39m this is err and is level 3\n',
213 | '\u001b[33mwarning:\u001b[39m this is warn and is level 4\n',
214 | '\u001b[33mnotice:\u001b[39m this is note and is level 5\n',
215 | ])
216 |
217 | addSuite(
218 | 'logging with colors',
219 | { lineLevel: 7 },
220 | [
221 | '\u001b[31memergency:\u001b[39m this is emergency and is level 0\n \u001b[2m→ [2013-05-06 20:39:46.119] [my/test.js:1:20] [testCaller]\u001b[22m\n',
222 | '\u001b[31malert:\u001b[39m this is alert and is level 1\n \u001b[2m→ [2013-05-06 20:39:46.120] [my/test.js:1:20] [testCaller]\u001b[22m\n',
223 | '\u001b[31mcritical:\u001b[39m this is critical and is level 2\n \u001b[2m→ [2013-05-06 20:39:46.120] [my/test.js:1:20] [testCaller]\u001b[22m\n',
224 | '\u001b[31merror:\u001b[39m this is error and is level 3\n \u001b[2m→ [2013-05-06 20:39:46.121] [my/test.js:1:20] [testCaller]\u001b[22m\n',
225 | '\u001b[33mwarning:\u001b[39m this is warning and is level 4\n \u001b[2m→ [2013-05-06 20:39:46.121] [my/test.js:1:20] [testCaller]\u001b[22m\n',
226 | '\u001b[33mnotice:\u001b[39m this is notice and is level 5\n \u001b[2m→ [2013-05-06 20:39:46.122] [my/test.js:1:20] [testCaller]\u001b[22m\n',
227 | '\u001b[32minfo:\u001b[39m this is info and is level 6\n \u001b[2m→ [2013-05-06 20:39:46.122] [my/test.js:1:20] [testCaller]\u001b[22m\n',
228 | '\u001b[32mdebug:\u001b[39m this is debug and is level 7\n \u001b[2m→ [2013-05-06 20:39:46.123] [my/test.js:1:20] [testCaller]\u001b[22m\n',
229 | '\u001b[31memergency:\u001b[39m this is emerg and is level 0\n \u001b[2m→ [2013-05-06 20:39:46.123] [my/test.js:1:20] [testCaller]\u001b[22m\n',
230 | '\u001b[31mcritical:\u001b[39m this is crit and is level 2\n \u001b[2m→ [2013-05-06 20:39:46.124] [my/test.js:1:20] [testCaller]\u001b[22m\n',
231 | '\u001b[31merror:\u001b[39m this is err and is level 3\n \u001b[2m→ [2013-05-06 20:39:46.124] [my/test.js:1:20] [testCaller]\u001b[22m\n',
232 | '\u001b[33mwarning:\u001b[39m this is warn and is level 4\n \u001b[2m→ [2013-05-06 20:39:46.125] [my/test.js:1:20] [testCaller]\u001b[22m\n',
233 | '\u001b[33mnotice:\u001b[39m this is note and is level 5\n \u001b[2m→ [2013-05-06 20:39:46.126] [my/test.js:1:20] [testCaller]\u001b[22m\n',
234 | ],
235 | cleanChangingHuman
236 | )
237 | })
238 |
239 | // Test
240 | suite('human', function (suite) {
241 | suite('instantiation', function (suite, test) {
242 | test('should instantiate correctly', function () {
243 | const browser = new Browser()
244 | equal(browser.color, true, 'default color was applied correctly')
245 | })
246 |
247 | test('should instantiate correctly, with config', function () {
248 | const browser = new Browser({ color: false })
249 | equal(browser.color, false, 'custom color was applied correctly')
250 | })
251 | })
252 |
253 | function addSuite(
254 | name: string,
255 | config: { color?: boolean; lineLevel?: number },
256 | expected: string[],
257 | cleaner?: typeof cleanChangingHuman
258 | ) {
259 | suite(name, function (suite, test) {
260 | const logger = new Logger(config)
261 | const human = new Human(config)
262 | const browser = new Browser(config)
263 | const output = new PassThrough()
264 | let actual: string[] = []
265 | if (cleaner) expected = expected.map(cleaner)
266 |
267 | output.on('data', function (chunk) {
268 | actual.push(chunk.toString())
269 | })
270 |
271 | test('should pipe correctly', function () {
272 | logger.pipe(human).pipe(browser).pipe(output)
273 | })
274 |
275 | test('should log messages', function () {
276 | const levels = logger.levels
277 | Object.keys(levels).forEach(function testCaller(name) {
278 | const code = levels[name]
279 | const message = `this is ${name} and is level ${code}`
280 | logger.log(name, message)
281 | })
282 | })
283 |
284 | test('should provide the expected output', function (done) {
285 | output.on('end', function () {
286 | if (cleaner) actual = actual.map(cleaner)
287 | equal(actual.length, expected.length, 'length was expected')
288 | actual.forEach(function (result, index) {
289 | equal(result, expected[index], 'result was expected')
290 | })
291 | done()
292 | })
293 | logger.end()
294 | })
295 | })
296 | }
297 |
298 | addSuite(
299 | 'logging without colors in debug mode',
300 | { color: false, lineLevel: 7 },
301 | [
302 | '["emergency: this is emergency and is level 0\\n → [2013-05-06 20:41:13.973] [my/test.js:1:20] [testCaller]"]',
303 | '["alert: this is alert and is level 1\\n → [2013-05-06 20:41:13.978] [my/test.js:1:20] [testCaller]"]',
304 | '["critical: this is critical and is level 2\\n → [2013-05-06 20:41:13.978] [my/test.js:1:20] [testCaller]"]',
305 | '["error: this is error and is level 3\\n → [2013-05-06 20:41:13.979] [my/test.js:1:20] [testCaller]"]',
306 | '["warning: this is warning and is level 4\\n → [2013-05-06 20:41:13.979] [my/test.js:1:20] [testCaller]"]',
307 | '["notice: this is notice and is level 5\\n → [2013-05-06 20:41:13.980] [my/test.js:1:20] [testCaller]"]',
308 | '["info: this is info and is level 6\\n → [2013-05-06 20:41:13.980] [my/test.js:1:20] [testCaller]"]',
309 | '["debug: this is debug and is level 7\\n → [2013-05-06 20:41:13.981] [my/test.js:1:20] [testCaller]"]',
310 | '["emergency: this is emerg and is level 0\\n → [2013-05-06 20:41:13.982] [my/test.js:1:20] [testCaller]"]',
311 | '["critical: this is crit and is level 2\\n → [2013-05-06 20:41:13.982] [my/test.js:1:20] [testCaller]"]',
312 | '["error: this is err and is level 3\\n → [2013-05-06 20:41:13.982] [my/test.js:1:20] [testCaller]"]',
313 | '["warning: this is warn and is level 4\\n → [2013-05-06 20:41:13.983] [my/test.js:1:20] [testCaller]"]',
314 | '["notice: this is note and is level 5\\n → [2013-05-06 20:41:13.983] [my/test.js:1:20] [testCaller]"]',
315 | ],
316 | cleanChangingHuman
317 | )
318 |
319 | addSuite(
320 | 'logging with colors in debug mode',
321 | { lineLevel: 7 },
322 | [
323 | '["%c%s%c this is emergency and is level 0\\n %c%s%c","color:red","emergency:","color:default; font:default; text-decoration:default","color:lightGray","→ [2013-05-06 21:17:14.550] [my/test.js:1:20] [testCaller]","color:default; font:default; text-decoration:default"]',
324 | '["%c%s%c this is alert and is level 1\\n %c%s%c","color:red","alert:","color:default; font:default; text-decoration:default","color:lightGray","→ [2013-05-06 21:17:14.551] [my/test.js:1:20] [testCaller]","color:default; font:default; text-decoration:default"]',
325 | '["%c%s%c this is critical and is level 2\\n %c%s%c","color:red","critical:","color:default; font:default; text-decoration:default","color:lightGray","→ [2013-05-06 21:17:14.551] [my/test.js:1:20] [testCaller]","color:default; font:default; text-decoration:default"]',
326 | '["%c%s%c this is error and is level 3\\n %c%s%c","color:red","error:","color:default; font:default; text-decoration:default","color:lightGray","→ [2013-05-06 21:17:14.552] [my/test.js:1:20] [testCaller]","color:default; font:default; text-decoration:default"]',
327 | '["%c%s%c this is warning and is level 4\\n %c%s%c","color:orange","warning:","color:default; font:default; text-decoration:default","color:lightGray","→ [2013-05-06 21:17:14.552] [my/test.js:1:20] [testCaller]","color:default; font:default; text-decoration:default"]',
328 | '["%c%s%c this is notice and is level 5\\n %c%s%c","color:orange","notice:","color:default; font:default; text-decoration:default","color:lightGray","→ [2013-05-06 21:17:14.553] [my/test.js:1:20] [testCaller]","color:default; font:default; text-decoration:default"]',
329 | '["%c%s%c this is info and is level 6\\n %c%s%c","color:green","info:","color:default; font:default; text-decoration:default","color:lightGray","→ [2013-05-06 21:17:14.553] [my/test.js:1:20] [testCaller]","color:default; font:default; text-decoration:default"]',
330 | '["%c%s%c this is debug and is level 7\\n %c%s%c","color:green","debug:","color:default; font:default; text-decoration:default","color:lightGray","→ [2013-05-06 21:17:14.554] [my/test.js:1:20] [testCaller]","color:default; font:default; text-decoration:default"]',
331 | '["%c%s%c this is emerg and is level 0\\n %c%s%c","color:red","emergency:","color:default; font:default; text-decoration:default","color:lightGray","→ [2013-05-06 21:17:14.554] [my/test.js:1:20] [testCaller]","color:default; font:default; text-decoration:default"]',
332 | '["%c%s%c this is crit and is level 2\\n %c%s%c","color:red","critical:","color:default; font:default; text-decoration:default","color:lightGray","→ [2013-05-06 21:17:14.555] [my/test.js:1:20] [testCaller]","color:default; font:default; text-decoration:default"]',
333 | '["%c%s%c this is err and is level 3\\n %c%s%c","color:red","error:","color:default; font:default; text-decoration:default","color:lightGray","→ [2013-05-06 21:17:14.555] [my/test.js:1:20] [testCaller]","color:default; font:default; text-decoration:default"]',
334 | '["%c%s%c this is warn and is level 4\\n %c%s%c","color:orange","warning:","color:default; font:default; text-decoration:default","color:lightGray","→ [2013-05-06 21:17:14.556] [my/test.js:1:20] [testCaller]","color:default; font:default; text-decoration:default"]',
335 | '["%c%s%c this is note and is level 5\\n %c%s%c","color:orange","notice:","color:default; font:default; text-decoration:default","color:lightGray","→ [2013-05-06 21:17:14.556] [my/test.js:1:20] [testCaller]","color:default; font:default; text-decoration:default"]',
336 | ],
337 | cleanChangingHuman
338 | )
339 | })
340 | })
341 |
--------------------------------------------------------------------------------
/source/transform.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Caterpillar supports piping to anything that supports this interface.
3 | * Which includes:
4 | * - {@link Transform Caterpillar Transforms}
5 | * - [Deno Writer Streams](https://doc.deno.land/https/github.com/denoland/deno/releases/latest/download/lib.deno.d.ts#Deno.Writer), e.g.
6 | * - [Deno.stdout](https://doc.deno.land/https/github.com/denoland/deno/releases/latest/download/lib.deno.d.ts#Deno.stdout)
7 | * - [Node.js Writable Streams](https://nodejs.org/dist/latest-v14.x/docs/api/stream.html#stream_writable_streams), e.g.
8 | * - [process.stdout](https://nodejs.org/dist/latest-v14.x/docs/api/process.html#process_process_stdout)
9 | * - [fs.createWriteStream](https://nodejs.org/dist/latest-v14.x/docs/api/fs.html#fs_fs_createwritestream_path_options)
10 | * - [WhatWG Writable Streams](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream)
11 | */
12 | export interface Pipeable {
13 | write(chunk: any): any
14 | end?(cb?: () => void): void
15 | close?(): Promise | void
16 | }
17 |
18 | /**
19 | * Caterpillar Transform Class.
20 | * Provides the methods needed to provide a pipable Caterpillar Transform.
21 | * Such that all you need to do is write your {@link Transform.format} method.
22 | * It can pipe to anything that provides a {@link Pipeable.write} method.
23 | * @example [Writing a Custom Transform](https://repl.it/@balupton/caterpillar-custom-transform)
24 | */
25 | export class Transform implements Pipeable {
26 | /** Where is this Transform piping to? */
27 | private pipes: Array = []
28 |
29 | /**
30 | * Format the received log entry representation.
31 | * Your transformer should extend this.
32 | */
33 | format(message: any): any {
34 | return message
35 | }
36 |
37 | /** Pipe future log entries into a caterpillar transform or a stream. */
38 | pipe(to: T) {
39 | this.pipes.push(to)
40 | return to
41 | }
42 |
43 | /** Maintain a write queue such that multiple Deno writes do not stall */
44 | private writer = Promise.resolve()
45 |
46 | /** Write to the child pipes. */
47 | write(chunk: any) {
48 | // format now, so that we have the correct stack
49 | const data = this.format(chunk)
50 | // exclude filtered entries
51 | if (data == null) return this.writer
52 | // now delegate back to the pipe
53 | this.writer = this.writer.then(async () => {
54 | // pipe to child transforms and streams
55 | for (const pipe of this.pipes) {
56 | if (pipe instanceof Transform) {
57 | // compatibility with caterpillar transforms
58 | await pipe.write(data)
59 | } else {
60 | const str = typeof data === 'string' ? data : JSON.stringify(data)
61 | // requires typescript dom lib to define TextEncoder global
62 | if (typeof TextEncoder !== 'undefined') {
63 | // compatibility with deno and later node streams
64 | await pipe.write(new TextEncoder().encode(str))
65 | } else {
66 | // compatibility with earlier node streams
67 | await pipe.write(str)
68 | }
69 | }
70 | }
71 | })
72 | return this.writer
73 | }
74 |
75 | /** Close the child pipes. */
76 | async close(): Promise {
77 | await Promise.all(
78 | this.pipes.map((pipe) => {
79 | if (pipe.close) {
80 | return pipe.close()
81 | } else if (pipe.end) {
82 | return new Promise(function (resolve) {
83 | pipe.end!(resolve)
84 | })
85 | } else {
86 | return Promise.resolve()
87 | }
88 | })
89 | )
90 | }
91 |
92 | /* Callback alias for close */
93 | end(cb?: () => void) {
94 | const p = this.close()
95 | if (cb) p.finally(cb)
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/source/transforms/browser.ts:
--------------------------------------------------------------------------------
1 | // this cannot be located at source/brower.ts as otherwise it would become the browser entry
2 |
3 | // Imports
4 | import { Transform } from '../transform.js'
5 |
6 | /** Mapping of ANSI color codes into a CSS style */
7 | export interface Styles {
8 | [key: string]: {
9 | /** The ANSI color code used to start the style */
10 | start: string
11 | /** The ANSI color code used to end the style */
12 | end: string
13 | /** The CSS style value */
14 | value: string
15 | }
16 | }
17 |
18 | /** Configuration optons for the Caterpillar Browser Transform */
19 | export interface BrowserOptions {
20 | /** Use to override the default value of {@link Filter.color} */
21 | color?: boolean
22 | /** Use to override the default value of {@link Filter.console} */
23 | output?: boolean
24 | /** Use to override the default value of {@link Filter.styles} */
25 | styles?: Styles
26 | }
27 |
28 | /**
29 | * Convert human readable Caterpillar entries into browser compatible entries.
30 | * @example
31 | * ``` javascript
32 | * import { Logger, Human, Browser } from 'caterpillar'
33 | * const logger = new Logger()
34 | * logger.pipe(new Human()).pipe(new Browser())
35 | * logger.log('info', 'some', {data: 'oh yeah'}, 42)
36 | * ```
37 | */
38 | export class Browser extends Transform {
39 | /** Whether or not we should use color. */
40 | public color: boolean = true
41 |
42 | /** Whether or not we should write to the browser console. */
43 | public output: boolean = true
44 |
45 | /** The objects that tell our browser transform how to convert terminal colours into console colours. */
46 | public styles: Styles = {
47 | red: {
48 | start: '31',
49 | end: '39',
50 | value: 'color:red',
51 | },
52 | yellow: {
53 | start: '33',
54 | end: '39',
55 | value: 'color:orange',
56 | },
57 | green: {
58 | start: '32',
59 | end: '39',
60 | value: 'color:green',
61 | },
62 | bright: {
63 | start: '1',
64 | end: '22',
65 | value: 'font-weight:bold',
66 | },
67 | dim: {
68 | start: '2',
69 | end: '22',
70 | value: 'color:lightGray',
71 | },
72 | italic: {
73 | start: '3',
74 | end: '23',
75 | value: 'font-style:italic',
76 | },
77 | underline: {
78 | start: '4',
79 | end: '24',
80 | value: 'text-decoration:underline',
81 | },
82 | }
83 |
84 | /** Create our instance and apply our configuraiton options. */
85 | constructor(opts?: BrowserOptions) {
86 | super()
87 |
88 | // options
89 | if (opts?.color != null) this.color = opts.color
90 | if (opts?.output != null) this.output = opts.output
91 | if (opts?.styles != null) this.styles = opts.styles
92 | }
93 |
94 | /**
95 | * Convert a human readable Caterpillar entry into a format that browser consoles can understand.
96 | * And if the `write` config property is `true` (it is by default), write the result to the browser console.
97 | */
98 | format(message: string): string[] {
99 | // Prepare
100 | const { color, styles, output } = this
101 |
102 | // Replace caterpillar-human formatted entry
103 | /* eslint no-control-regex:0 */
104 | const args: string[] = []
105 | const result = message.replace(
106 | /\u001b\[([0-9]+)m(.+?)\u001b\[([0-9]+)m/g,
107 | function (match, start, content, end) {
108 | // Check
109 | if (color === false) return content
110 |
111 | // Prepare
112 | let matchedStyle, style
113 |
114 | // Find the matcing style for this combination
115 | for (const key in styles) {
116 | if (styles.hasOwnProperty(key)) {
117 | style = styles[key]
118 | if (
119 | String(style.start) === String(start) &&
120 | String(style.end) === String(end)
121 | ) {
122 | matchedStyle = style
123 | break
124 | }
125 | }
126 | }
127 |
128 | // Check
129 | if (!matchedStyle) return content
130 |
131 | // Push the style
132 | args.push(matchedStyle.value)
133 | args.push(content)
134 | args.push('color:default; font:default; text-decoration:default')
135 | return '%c%s%c'
136 | }
137 | )
138 |
139 | // Final format
140 | const parts = [result.trim()].concat(args)
141 |
142 | // Write
143 | /* eslint no-console:0 */
144 | if (output) console.log(...parts)
145 |
146 | // Return
147 | return parts
148 | }
149 | }
150 |
151 | export default Browser
152 |
--------------------------------------------------------------------------------
/source/transforms/filter.ts:
--------------------------------------------------------------------------------
1 | import { LogEntry } from '../logger.js'
2 | import { Transform } from '../transform.js'
3 |
4 | /** Configuration options for the Caterpillar Filter Transform */
5 | export interface FilterOptions {
6 | /** Use to override the default value of {@link Filter.filterLevel} */
7 | filterLevel?: number
8 | }
9 |
10 | /**
11 | * Caterpillar Filter Transform.
12 | * Filters the log entries, keeping only those equal to or below the specified `filterLevel`.
13 | * @example
14 | * ``` javascript
15 | * import { Logger, Filter } from 'caterpillar'
16 | * const logger = new Logger()
17 | * const filter = new Filter({ filterLevel: 6 })
18 | * logger.pipe(filter).pipe(process.stdout)
19 | * logger.log('info', 'this will be outputted')
20 | * logger.log('debug', 'this will be ignored')
21 | * filter.filterLevel = 5
22 | * logger.log('info', 'now even this will be ignored')
23 | * logger.log('note', 'but not this')
24 | * ```
25 | */
26 | export class Filter extends Transform {
27 | /**
28 | * Only display entries that have a log level below or equal to this number.
29 | * Defaults to `6`, which by default is the info log level.
30 | */
31 | public filterLevel: number = 6
32 |
33 | /** Create our instance and apply our configuraiton options. */
34 | constructor(opts?: FilterOptions) {
35 | super()
36 |
37 | // options
38 | if (opts?.filterLevel != null) this.filterLevel = opts.filterLevel
39 | }
40 |
41 | /** Retain only log entries that are equal to or less than the specified filter level. */
42 | format(entry: LogEntry): LogEntry | null {
43 | return entry.levelNumber <= this.filterLevel ? entry : null
44 | }
45 | }
46 |
47 | export default Filter
48 |
--------------------------------------------------------------------------------
/source/transforms/human.ts:
--------------------------------------------------------------------------------
1 | // Imports
2 | import { LogEntry } from '../logger.js'
3 | import { Transform } from '../transform.js'
4 | import { inspect } from 'util'
5 | import * as ansi from '@bevry/ansi'
6 |
7 | /**
8 | * Return the given argument.
9 | * Used for when there is no formatter.
10 | */
11 | function ansiNoop(a: string): string {
12 | return a
13 | }
14 |
15 | /** A mapping of log level numbers to their intended colours */
16 | interface LevelsToColorsMap {
17 | [logLevelNumber: string]: ansi.ANSIApplier
18 | }
19 |
20 | /** Configuration options for the Caterpillar Human Transform */
21 | export interface HumanOptions {
22 | /** Use to override the default value of {@link Human.color} */
23 | color?: boolean
24 |
25 | /** Use to override the default value of {@link Human.colors} */
26 | colors?: LevelsToColorsMap
27 | }
28 |
29 | /**
30 | * Convert Logger entries into human readable format.
31 | * @extends Transform
32 | * @example
33 | * ``` javascript
34 | * import { Logger, Human } from 'caterpillar'
35 | * const logger = new Logger()
36 | * const human = new Human()
37 | * logger.pipe(human).pipe(process.stdout)
38 | * logger.log('info', 'some', {data: 'oh yeah'}, 42)
39 | * ```
40 | */
41 | export class Human extends Transform {
42 | /** Whether or not to use colors? */
43 | public color: boolean = true
44 |
45 | /** Mapping of which log level numbers correspond to which colours */
46 | public colors: LevelsToColorsMap = {
47 | '0': 'red',
48 | '1': 'red',
49 | '2': 'red',
50 | '3': 'red',
51 | '4': 'yellow',
52 | '5': 'yellow',
53 | '6': 'green',
54 | '7': 'green',
55 | }
56 |
57 | /** Create our instance and apply our configuration options. */
58 | constructor(opts?: HumanOptions) {
59 | super()
60 |
61 | // options
62 | if (opts?.color != null) this.color = opts.color
63 | if (opts?.colors != null) this.colors = opts.colors
64 | }
65 |
66 | /** Get the color for the log level */
67 | getColor(levelNumber: number): ansi.ANSIApplier | false {
68 | // Determine
69 | const color = this.colors[levelNumber] || false
70 |
71 | // Return
72 | return color
73 | }
74 |
75 | /** Pad the left of some content if need be with the specified padding to make the content reach a certain size */
76 | padLeft(padding: string, size: number, content: string | number): string {
77 | // Prepare
78 | padding = String(padding)
79 | content = String(content)
80 |
81 | // Handle
82 | if (content.length < size) {
83 | for (let i = 0, n = size - content.length; i < n; ++i) {
84 | content = padding + content
85 | }
86 | }
87 |
88 | // Return
89 | return content
90 | }
91 |
92 | /** Convert logger entry arguments into a human readable string */
93 | formatArguments(args: any[]): string {
94 | return args
95 | .map((value) =>
96 | typeof value === 'string'
97 | ? value
98 | : inspect(value, {
99 | showHidden: false,
100 | depth: 10,
101 | colors: this.color,
102 | })
103 | )
104 | .join(' ')
105 | }
106 |
107 | /** Convert a datetime into a human readable format */
108 | formatDate(datetime: Date | number | string): string {
109 | // Prepare
110 | const now = new Date(datetime)
111 | const year = now.getFullYear()
112 | const month = this.padLeft('0', 2, now.getMonth() + 1)
113 | const date = this.padLeft('0', 2, now.getDate())
114 | const hours = this.padLeft('0', 2, now.getHours())
115 | const minutes = this.padLeft('0', 2, now.getMinutes())
116 | const seconds = this.padLeft('0', 2, now.getSeconds())
117 | const ms = this.padLeft('0', 3, now.getMilliseconds())
118 |
119 | // Apply
120 | const result = `${year}-${month}-${date} ${hours}:${minutes}:${seconds}.${ms}`
121 |
122 | // Return
123 | return result
124 | }
125 |
126 | /** Convert a logger entry into a human readable format */
127 | format(entry: LogEntry): string {
128 | // Prepare
129 | const { color } = this
130 | const useLine = entry.line !== -1
131 | let result: string
132 |
133 | // Format
134 | const format = {
135 | color: this.getColor(entry.levelNumber),
136 | timestamp: this.formatDate(entry.date),
137 | text: this.formatArguments(entry.args),
138 | }
139 |
140 | // Check
141 | if (format.text) {
142 | // Formatters
143 | const levelFormatter =
144 | (color && format.color && ansi[format.color]) || ansiNoop
145 | const lineFormatter = (useLine && color && ansi.dim) || ansiNoop
146 |
147 | // Message
148 | // @ts-ignore
149 | const levelString = levelFormatter(`${entry.levelName}:`)
150 | const entryString = format.text
151 | const messageString = `${levelString} ${entryString}`
152 |
153 | // Format
154 | if (useLine) {
155 | // Line Information
156 | const seperator = '\n '
157 | const debugString = lineFormatter(
158 | `→ [${format.timestamp}] [${entry.file}:${entry.line}:${entry.char}] [${entry.method}]`
159 | )
160 |
161 | // Result
162 | result = `${messageString}${seperator}${debugString}\n`
163 | } else {
164 | // Result
165 | result = `${messageString}\n`
166 | }
167 | } else {
168 | result = format.text
169 | }
170 |
171 | // Return
172 | return result
173 | }
174 | }
175 |
176 | export default Human
177 |
--------------------------------------------------------------------------------
/test.cjs:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // auto-generated by boundation, do not update manually
3 | /** @type {typeof import("./edition-types/test.d.ts") } */
4 | module.exports = require('editions').requirePackage(__dirname, require, 'test.js')
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "downlevelIteration": true,
5 | "esModuleInterop": true,
6 | "isolatedModules": true,
7 | "lib": ["DOM.Iterable", "DOM"],
8 | "maxNodeModuleJsDepth": 5,
9 | "module": "ESNext",
10 | "moduleResolution": "Node",
11 | "strict": true,
12 | "target": "ES2022"
13 | },
14 | "include": ["source"]
15 | }
16 |
--------------------------------------------------------------------------------