@guritso/terminal 1.2.1 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/index.cjs +1 -1
- package/lib/{cjs → dist}/terminal.cjs +66 -29
- package/lib/terminal.js +57 -27
- package/lib/utils.js +9 -2
- package/package.json +13 -9
- package/.github/workflows/node.js.yml +0 -31
- package/.github/workflows/npm-publish.yml +0 -37
- package/docs/guritso-terminal-preview.png +0 -0
- package/rollup.config.js +0 -8
- package/tests/terminal.test.js +0 -215
package/README.md
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
A terminal node utility for enhanced logging and error handling.
|
|
4
4
|
|
|
5
|
+
[](https://github.com/guritso/terminal/actions/workflows/node.js.yml)
|
|
6
|
+
[](https://github.com/guritso/terminal/actions/workflows/npm-publish.yml)
|
|
7
|
+
|
|
5
8
|
| example |
|
|
6
9
|
| ------- |
|
|
7
10
|
|  |
|
package/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
module.exports = require("./lib/
|
|
1
|
+
module.exports = require("./lib/dist/terminal.cjs");
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
var url = require('url');
|
|
4
4
|
var fs = require('fs');
|
|
5
|
+
var path = require('path');
|
|
5
6
|
|
|
6
7
|
/*!
|
|
7
8
|
* Terminal
|
|
8
|
-
* Copyright (c) 2024 @
|
|
9
|
+
* Copyright (c) 2024 @guritso
|
|
9
10
|
* @license MIT
|
|
10
11
|
*/
|
|
11
12
|
|
|
@@ -29,7 +30,14 @@ function color(txt) {
|
|
|
29
30
|
|
|
30
31
|
if (!n || !txt.includes(`%H${n}`) || isNaN(n)) continue;
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
let code = n;
|
|
34
|
+
if (n >= 40 && n <= 47) {
|
|
35
|
+
code = `90;${n}`;
|
|
36
|
+
} else if (n >= 100 && n <= 107) {
|
|
37
|
+
code = `97;${n}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const mo = `\x1b[${code}m${w.join(" ")}\x1b[0m`;
|
|
33
41
|
|
|
34
42
|
res = res.replace(a, mo);
|
|
35
43
|
}
|
|
@@ -91,7 +99,7 @@ function formatUrl(host, port) {
|
|
|
91
99
|
|
|
92
100
|
/*!
|
|
93
101
|
* Terminal
|
|
94
|
-
* Copyright (c) 2024 @
|
|
102
|
+
* Copyright (c) 2024 @guritso
|
|
95
103
|
* @license MIT
|
|
96
104
|
*/
|
|
97
105
|
|
|
@@ -111,31 +119,20 @@ function formatUrl(host, port) {
|
|
|
111
119
|
* @property {function(number): void} setVerbose
|
|
112
120
|
* @property {function(any): boolean} isError
|
|
113
121
|
* @property {Object} projectInfo
|
|
122
|
+
* @property {function(string): void} loadProjectInfo
|
|
114
123
|
*/
|
|
115
|
-
|
|
116
|
-
/** @type {Terminal} */
|
|
117
124
|
const terminal = {
|
|
118
125
|
verbose: 2,
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
126
|
+
levels: {
|
|
127
|
+
info: color("%H47 INFO %H"),
|
|
128
|
+
fail: color("%H41 FAIL %H"),
|
|
129
|
+
pass: color("%H42 PASS %H"),
|
|
130
|
+
},
|
|
124
131
|
};
|
|
125
132
|
|
|
126
133
|
const { stdout } = process;
|
|
127
134
|
|
|
128
|
-
terminal.projectInfo =
|
|
129
|
-
try {
|
|
130
|
-
const { name, version } = JSON.parse(
|
|
131
|
-
fs.readFileSync("./package.json", "utf-8")
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
return { name, version };
|
|
135
|
-
} catch (error) {
|
|
136
|
-
return { name: "unknown", version: "unknown" };
|
|
137
|
-
}
|
|
138
|
-
})();
|
|
135
|
+
terminal.projectInfo = { name: "unknown", version: "unknown" };
|
|
139
136
|
|
|
140
137
|
/**
|
|
141
138
|
* display the project info and host, port
|
|
@@ -144,15 +141,18 @@ terminal.projectInfo = (() => {
|
|
|
144
141
|
* @param {number} port - The port number to display
|
|
145
142
|
*/
|
|
146
143
|
terminal.start = function start(host, port) {
|
|
144
|
+
if (terminal.projectInfo.name === "unknown") {
|
|
145
|
+
terminal.loadProjectInfo();
|
|
146
|
+
}
|
|
147
147
|
const projectInfo = terminal.projectInfo;
|
|
148
148
|
const hostInfo = formatUrl(host, port);
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
150
|
+
const headLines = [
|
|
151
|
+
`\n%H46 name:%H%H33 ${projectInfo.name}`,
|
|
152
|
+
`%H%H31 ${projectInfo.version} %H\n`,
|
|
153
|
+
hostInfo?.url ? `%H43 host:%H %H36 ${hostInfo.url}%H\n` : "",
|
|
154
|
+
hostInfo?.port ? `%H45 port:%H %H31 ${hostInfo.port}%H\n` : "",
|
|
155
|
+
];
|
|
156
156
|
|
|
157
157
|
for (const line of headLines) {
|
|
158
158
|
stdout.write(color(line));
|
|
@@ -165,6 +165,8 @@ terminal.start = function start(host, port) {
|
|
|
165
165
|
* @param {string} data
|
|
166
166
|
*/
|
|
167
167
|
terminal.pass = function pass(data) {
|
|
168
|
+
if (data === null || data === undefined) return;
|
|
169
|
+
|
|
168
170
|
const { verbose, levels } = terminal;
|
|
169
171
|
|
|
170
172
|
if (verbose === 0) return;
|
|
@@ -212,6 +214,8 @@ terminal.log = function log(data) {
|
|
|
212
214
|
}
|
|
213
215
|
}
|
|
214
216
|
};
|
|
217
|
+
// cache
|
|
218
|
+
let errorKeywords = [];
|
|
215
219
|
|
|
216
220
|
/**
|
|
217
221
|
* Check if the data is an error
|
|
@@ -225,8 +229,10 @@ terminal.isError = (data) => {
|
|
|
225
229
|
}
|
|
226
230
|
|
|
227
231
|
if (typeof data === "string") {
|
|
228
|
-
|
|
229
|
-
|
|
232
|
+
if (!errorKeywords.length) {
|
|
233
|
+
errorKeywords = getErrorNames().map((name) => name);
|
|
234
|
+
errorKeywords.push("Error:");
|
|
235
|
+
}
|
|
230
236
|
|
|
231
237
|
return errorKeywords.some((keyword) => data.includes(keyword));
|
|
232
238
|
}
|
|
@@ -288,4 +294,35 @@ terminal.setVerbose = (verbose) => {
|
|
|
288
294
|
}
|
|
289
295
|
};
|
|
290
296
|
|
|
297
|
+
/**
|
|
298
|
+
* Restore terminal.log function
|
|
299
|
+
* @return {boolean} if true = sucess
|
|
300
|
+
*/
|
|
301
|
+
terminal.teardown = () => {
|
|
302
|
+
if (console.backup) {
|
|
303
|
+
console.error = console.backup;
|
|
304
|
+
delete console.backup;
|
|
305
|
+
return true;
|
|
306
|
+
}
|
|
307
|
+
return false;
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Load project info from package.json
|
|
312
|
+
* @param {string} [pkgPath] - Optional path to package.json
|
|
313
|
+
*/
|
|
314
|
+
terminal.loadProjectInfo = (pkgPath) => {
|
|
315
|
+
try {
|
|
316
|
+
const path$1 = pkgPath || path.resolve(process.cwd(), "package.json");
|
|
317
|
+
const pkgData = JSON.parse(fs.readFileSync(path$1, "utf-8"));
|
|
318
|
+
|
|
319
|
+
terminal.projectInfo = {
|
|
320
|
+
name: pkgData.name || "unknown",
|
|
321
|
+
version: pkgData.version || "unknown"
|
|
322
|
+
};
|
|
323
|
+
} catch (error) {
|
|
324
|
+
terminal.projectInfo = { name: "unknown", version: "unknown" };
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
|
|
291
328
|
module.exports = terminal;
|
package/lib/terminal.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* Terminal
|
|
3
|
-
* Copyright (c) 2024 @
|
|
3
|
+
* Copyright (c) 2024 @guritso
|
|
4
4
|
* @license MIT
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { color as co, getErrorNames, formatUrl } from "./utils.js";
|
|
10
10
|
import { readFileSync } from "fs";
|
|
11
|
+
import { resolve } from "path";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* @typedef {Object} Terminal
|
|
@@ -24,31 +25,20 @@ import { readFileSync } from "fs";
|
|
|
24
25
|
* @property {function(number): void} setVerbose
|
|
25
26
|
* @property {function(any): boolean} isError
|
|
26
27
|
* @property {Object} projectInfo
|
|
28
|
+
* @property {function(string): void} loadProjectInfo
|
|
27
29
|
*/
|
|
28
|
-
|
|
29
|
-
/** @type {Terminal} */
|
|
30
30
|
const terminal = {
|
|
31
31
|
verbose: 2,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
levels: {
|
|
33
|
+
info: co("%H47 INFO %H"),
|
|
34
|
+
fail: co("%H41 FAIL %H"),
|
|
35
|
+
pass: co("%H42 PASS %H"),
|
|
36
|
+
},
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
const { stdout } = process;
|
|
40
40
|
|
|
41
|
-
terminal.projectInfo =
|
|
42
|
-
try {
|
|
43
|
-
const { name, version } = JSON.parse(
|
|
44
|
-
readFileSync("./package.json", "utf-8")
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
return { name, version };
|
|
48
|
-
} catch (error) {
|
|
49
|
-
return { name: "unknown", version: "unknown" };
|
|
50
|
-
}
|
|
51
|
-
})();
|
|
41
|
+
terminal.projectInfo = { name: "unknown", version: "unknown" };
|
|
52
42
|
|
|
53
43
|
/**
|
|
54
44
|
* display the project info and host, port
|
|
@@ -57,15 +47,18 @@ terminal.projectInfo = (() => {
|
|
|
57
47
|
* @param {number} port - The port number to display
|
|
58
48
|
*/
|
|
59
49
|
terminal.start = function start(host, port) {
|
|
50
|
+
if (terminal.projectInfo.name === "unknown") {
|
|
51
|
+
terminal.loadProjectInfo();
|
|
52
|
+
}
|
|
60
53
|
const projectInfo = terminal.projectInfo;
|
|
61
54
|
const hostInfo = formatUrl(host, port);
|
|
62
55
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
56
|
+
const headLines = [
|
|
57
|
+
`\n%H46 name:%H%H33 ${projectInfo.name}`,
|
|
58
|
+
`%H%H31 ${projectInfo.version} %H\n`,
|
|
59
|
+
hostInfo?.url ? `%H43 host:%H %H36 ${hostInfo.url}%H\n` : "",
|
|
60
|
+
hostInfo?.port ? `%H45 port:%H %H31 ${hostInfo.port}%H\n` : "",
|
|
61
|
+
];
|
|
69
62
|
|
|
70
63
|
for (const line of headLines) {
|
|
71
64
|
stdout.write(co(line));
|
|
@@ -78,6 +71,8 @@ terminal.start = function start(host, port) {
|
|
|
78
71
|
* @param {string} data
|
|
79
72
|
*/
|
|
80
73
|
terminal.pass = function pass(data) {
|
|
74
|
+
if (data === null || data === undefined) return;
|
|
75
|
+
|
|
81
76
|
const { verbose, levels } = terminal;
|
|
82
77
|
|
|
83
78
|
if (verbose === 0) return;
|
|
@@ -125,6 +120,8 @@ terminal.log = function log(data) {
|
|
|
125
120
|
}
|
|
126
121
|
}
|
|
127
122
|
};
|
|
123
|
+
// cache
|
|
124
|
+
let errorKeywords = []
|
|
128
125
|
|
|
129
126
|
/**
|
|
130
127
|
* Check if the data is an error
|
|
@@ -138,8 +135,10 @@ terminal.isError = (data) => {
|
|
|
138
135
|
}
|
|
139
136
|
|
|
140
137
|
if (typeof data === "string") {
|
|
141
|
-
|
|
142
|
-
|
|
138
|
+
if (!errorKeywords.length) {
|
|
139
|
+
errorKeywords = getErrorNames().map((name) => name);
|
|
140
|
+
errorKeywords.push("Error:");
|
|
141
|
+
}
|
|
143
142
|
|
|
144
143
|
return errorKeywords.some((keyword) => data.includes(keyword));
|
|
145
144
|
}
|
|
@@ -201,4 +200,35 @@ terminal.setVerbose = (verbose) => {
|
|
|
201
200
|
}
|
|
202
201
|
};
|
|
203
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Restore terminal.log function
|
|
205
|
+
* @return {boolean} if true = sucess
|
|
206
|
+
*/
|
|
207
|
+
terminal.teardown = () => {
|
|
208
|
+
if (console.backup) {
|
|
209
|
+
console.error = console.backup;
|
|
210
|
+
delete console.backup;
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
return false;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Load project info from package.json
|
|
218
|
+
* @param {string} [pkgPath] - Optional path to package.json
|
|
219
|
+
*/
|
|
220
|
+
terminal.loadProjectInfo = (pkgPath) => {
|
|
221
|
+
try {
|
|
222
|
+
const path = pkgPath || resolve(process.cwd(), "package.json");
|
|
223
|
+
const pkgData = JSON.parse(readFileSync(path, "utf-8"));
|
|
224
|
+
|
|
225
|
+
terminal.projectInfo = {
|
|
226
|
+
name: pkgData.name || "unknown",
|
|
227
|
+
version: pkgData.version || "unknown"
|
|
228
|
+
};
|
|
229
|
+
} catch (error) {
|
|
230
|
+
terminal.projectInfo = { name: "unknown", version: "unknown" };
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
204
234
|
export default terminal;
|
package/lib/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* Terminal
|
|
3
|
-
* Copyright (c) 2024 @
|
|
3
|
+
* Copyright (c) 2024 @guritso
|
|
4
4
|
* @license MIT
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -25,7 +25,14 @@ function color(txt) {
|
|
|
25
25
|
|
|
26
26
|
if (!n || !txt.includes(`%H${n}`) || isNaN(n)) continue;
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
let code = n;
|
|
29
|
+
if (n >= 40 && n <= 47) {
|
|
30
|
+
code = `90;${n}`;
|
|
31
|
+
} else if (n >= 100 && n <= 107) {
|
|
32
|
+
code = `97;${n}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const mo = `\x1b[${code}m${w.join(" ")}\x1b[0m`;
|
|
29
36
|
|
|
30
37
|
res = res.replace(a, mo);
|
|
31
38
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guritso/terminal",
|
|
3
3
|
"description": "A terminal node utility for enhanced logging and error handling",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.3",
|
|
5
5
|
"main": "index.cjs",
|
|
6
6
|
"module": "index.js",
|
|
7
7
|
"types": "index.d.ts",
|
|
@@ -29,17 +29,21 @@
|
|
|
29
29
|
"utility",
|
|
30
30
|
"backend"
|
|
31
31
|
],
|
|
32
|
-
"author": "
|
|
32
|
+
"author": "guritso",
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"jest": "^
|
|
35
|
-
"rollup": "^4.
|
|
36
|
-
},
|
|
37
|
-
"directories": {
|
|
38
|
-
"lib": "lib",
|
|
39
|
-
"test": "tests"
|
|
34
|
+
"jest": "^30.2.0",
|
|
35
|
+
"rollup": "^4.55.3"
|
|
40
36
|
},
|
|
37
|
+
"files": [
|
|
38
|
+
"index.js",
|
|
39
|
+
"index.cjs",
|
|
40
|
+
"index.d.ts",
|
|
41
|
+
"lib/",
|
|
42
|
+
"README.md",
|
|
43
|
+
"LICENSE"
|
|
44
|
+
],
|
|
41
45
|
"bugs": {
|
|
42
46
|
"url": "https://github.com/guritso/terminal/issues"
|
|
43
47
|
},
|
|
44
48
|
"homepage": "https://github.com/guritso/terminal#readme"
|
|
45
|
-
}
|
|
49
|
+
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
|
2
|
-
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
|
|
3
|
-
|
|
4
|
-
name: Node.js CI
|
|
5
|
-
|
|
6
|
-
on:
|
|
7
|
-
push:
|
|
8
|
-
branches: [ "main" ]
|
|
9
|
-
pull_request:
|
|
10
|
-
branches: [ "main" ]
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
build:
|
|
14
|
-
|
|
15
|
-
runs-on: ubuntu-latest
|
|
16
|
-
|
|
17
|
-
strategy:
|
|
18
|
-
matrix:
|
|
19
|
-
node-version: [18.x, 20.x, 22.x]
|
|
20
|
-
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
21
|
-
|
|
22
|
-
steps:
|
|
23
|
-
- uses: actions/checkout@v4
|
|
24
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
|
25
|
-
uses: actions/setup-node@v4
|
|
26
|
-
with:
|
|
27
|
-
node-version: ${{ matrix.node-version }}
|
|
28
|
-
cache: 'npm'
|
|
29
|
-
- run: npm ci
|
|
30
|
-
- run: npm run build --if-present
|
|
31
|
-
- run: npm test
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
|
|
2
|
-
# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
|
|
3
|
-
|
|
4
|
-
name: Node.js Package
|
|
5
|
-
|
|
6
|
-
on:
|
|
7
|
-
release:
|
|
8
|
-
types: [created]
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
build:
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
steps:
|
|
14
|
-
- uses: actions/checkout@v4
|
|
15
|
-
- uses: actions/setup-node@v4
|
|
16
|
-
with:
|
|
17
|
-
node-version: 22.x
|
|
18
|
-
- run: npm ci
|
|
19
|
-
- run: npm test
|
|
20
|
-
- run: npm run build --if-present
|
|
21
|
-
|
|
22
|
-
publish-npm:
|
|
23
|
-
needs: build
|
|
24
|
-
runs-on: ubuntu-latest
|
|
25
|
-
permissions:
|
|
26
|
-
contents: read
|
|
27
|
-
id-token: write
|
|
28
|
-
steps:
|
|
29
|
-
- uses: actions/checkout@v4
|
|
30
|
-
- uses: actions/setup-node@v4
|
|
31
|
-
with:
|
|
32
|
-
node-version: 22.x
|
|
33
|
-
registry-url: https://registry.npmjs.org/
|
|
34
|
-
- run: npm ci
|
|
35
|
-
- run: npm publish --provenance --access public
|
|
36
|
-
env:
|
|
37
|
-
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
|
Binary file
|
package/rollup.config.js
DELETED
package/tests/terminal.test.js
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
const terminal = require("../index.cjs");
|
|
2
|
-
|
|
3
|
-
const levels = terminal.levels;
|
|
4
|
-
|
|
5
|
-
describe("Terminal Module", () => {
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
jest.resetAllMocks();
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
describe("start", () => {
|
|
11
|
-
it("should write project information and port to stdout", () => {
|
|
12
|
-
const mockWrite = jest
|
|
13
|
-
.spyOn(process.stdout, "write")
|
|
14
|
-
.mockImplementation(() => true);
|
|
15
|
-
terminal.projectInfo = { name: "test-project", version: "1.0.0" };
|
|
16
|
-
|
|
17
|
-
terminal.start("localhost", 3000);
|
|
18
|
-
|
|
19
|
-
expect(mockWrite).toHaveBeenCalled();
|
|
20
|
-
mockWrite.mockRestore();
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe("pass", () => {
|
|
25
|
-
it("should write success message to stdout", () => {
|
|
26
|
-
const mockWrite = jest
|
|
27
|
-
.spyOn(process.stdout, "write")
|
|
28
|
-
.mockImplementation(() => true);
|
|
29
|
-
terminal.pass("Operation successful");
|
|
30
|
-
|
|
31
|
-
expect(mockWrite).toHaveBeenCalledWith(expect.stringContaining("PASS"));
|
|
32
|
-
mockWrite.mockRestore();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("should use console.log instead of stdout.write when verbose is 2 and msg is an object", () => {
|
|
36
|
-
terminal.setVerbose(2);
|
|
37
|
-
const mockLog = jest.spyOn(console, "log").mockImplementation(() => true);
|
|
38
|
-
const mockWrite = jest
|
|
39
|
-
.spyOn(process.stdout, "write")
|
|
40
|
-
.mockImplementation(() => true);
|
|
41
|
-
|
|
42
|
-
const message = { key: "value" };
|
|
43
|
-
terminal.pass(message);
|
|
44
|
-
|
|
45
|
-
expect(mockLog).toHaveBeenCalledWith(expect.stringContaining(levels.pass), message);
|
|
46
|
-
expect(mockWrite).not.toHaveBeenCalled();
|
|
47
|
-
|
|
48
|
-
mockLog.mockRestore();
|
|
49
|
-
mockWrite.mockRestore();
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
describe("log", () => {
|
|
54
|
-
it("should do nothing if verbose is 0", () => {
|
|
55
|
-
terminal.setVerbose(0);
|
|
56
|
-
const mockWrite = jest
|
|
57
|
-
.spyOn(process.stdout, "write")
|
|
58
|
-
.mockImplementation(() => true);
|
|
59
|
-
|
|
60
|
-
terminal.log("This is a log message");
|
|
61
|
-
terminal.pass("This is a pass message");
|
|
62
|
-
expect(mockWrite).not.toHaveBeenCalled();
|
|
63
|
-
|
|
64
|
-
mockWrite.mockRestore();
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it("should write info message to stdout when verbose is 2 and msg is a string", () => {
|
|
68
|
-
terminal.setVerbose(2);
|
|
69
|
-
const mockWrite = jest
|
|
70
|
-
.spyOn(process.stdout, "write")
|
|
71
|
-
.mockImplementation(() => true);
|
|
72
|
-
|
|
73
|
-
terminal.log("Info message");
|
|
74
|
-
expect(mockWrite).toHaveBeenCalledWith(expect.stringContaining("INFO"));
|
|
75
|
-
mockWrite.mockRestore();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it("should use console.log instead of stdout.write when verbose is 2 and msg is an error string", () => {
|
|
79
|
-
terminal.setVerbose(2);
|
|
80
|
-
const mockLog = jest.spyOn(console, "log").mockImplementation(() => true);
|
|
81
|
-
const mockWrite = jest
|
|
82
|
-
.spyOn(process.stdout, "write")
|
|
83
|
-
.mockImplementation(() => true);
|
|
84
|
-
|
|
85
|
-
const errorMessage = "Error: Something went wrong";
|
|
86
|
-
|
|
87
|
-
terminal.log(errorMessage);
|
|
88
|
-
|
|
89
|
-
expect(mockLog).toHaveBeenCalledWith(expect.stringContaining(levels.fail), errorMessage);
|
|
90
|
-
expect(mockWrite).not.toHaveBeenCalled();
|
|
91
|
-
|
|
92
|
-
mockLog.mockRestore();
|
|
93
|
-
mockWrite.mockRestore();
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it("should use console.log instead of stdout.write when verbose is 2 and msg is an object", () => {
|
|
97
|
-
terminal.setVerbose(2);
|
|
98
|
-
const mockLog = jest.spyOn(console, "log").mockImplementation(() => true);
|
|
99
|
-
const mockWrite = jest
|
|
100
|
-
.spyOn(process.stdout, "write")
|
|
101
|
-
.mockImplementation(() => true);
|
|
102
|
-
|
|
103
|
-
const message = { key: "value" };
|
|
104
|
-
terminal.log(message);
|
|
105
|
-
|
|
106
|
-
expect(mockLog).toHaveBeenCalledWith(expect.stringContaining(levels.info), message);
|
|
107
|
-
expect(mockWrite).not.toHaveBeenCalled();
|
|
108
|
-
|
|
109
|
-
mockLog.mockRestore();
|
|
110
|
-
mockWrite.mockRestore();
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
describe("isError", () => {
|
|
115
|
-
it("should return true if the data is an instance of Error", () => {
|
|
116
|
-
const error = new Error("Test error");
|
|
117
|
-
expect(terminal.isError(error)).toBe(true);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it("should return true if the string contains an error keyword", () => {
|
|
121
|
-
expect(terminal.isError("Error: Test error")).toBe(true);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it("should return false for data that is not an error", () => {
|
|
125
|
-
expect(terminal.isError("This is a message")).toBe(false);
|
|
126
|
-
expect(terminal.isError({})).toBe(false);
|
|
127
|
-
expect(terminal.isError(123)).toBe(false);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe("setup", () => {
|
|
132
|
-
it("should replace console.error with terminal.log", () => {
|
|
133
|
-
const originalError = console.error;
|
|
134
|
-
terminal.setup();
|
|
135
|
-
|
|
136
|
-
expect(console.error).toBe(terminal.log);
|
|
137
|
-
|
|
138
|
-
console.error = originalError;
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it("should backup the original console.error", () => {
|
|
142
|
-
const originalError = console.error;
|
|
143
|
-
|
|
144
|
-
terminal.setup();
|
|
145
|
-
|
|
146
|
-
expect(console.backup).toBe(originalError);
|
|
147
|
-
|
|
148
|
-
console.error = originalError;
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it("should not replace console.error if console.backup exists", () => {
|
|
152
|
-
console.backup = jest.fn();
|
|
153
|
-
const originalError = console.error;
|
|
154
|
-
const result = terminal.setup();
|
|
155
|
-
|
|
156
|
-
expect(result).toBe(false);
|
|
157
|
-
expect(console.error).toBe(originalError);
|
|
158
|
-
|
|
159
|
-
delete console.backup;
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it("should throw an error if console.error is not found", () => {
|
|
163
|
-
const originalConsole = global.console;
|
|
164
|
-
global.console = { log: jest.fn() };
|
|
165
|
-
|
|
166
|
-
expect(() => terminal.setup()).toThrow("console.error is not found");
|
|
167
|
-
|
|
168
|
-
global.console = originalConsole;
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
describe("clear", () => {
|
|
173
|
-
it("should call stdout.clearLine if stdout is TTY", () => {
|
|
174
|
-
const originalIsTTY = process.stdout.isTTY;
|
|
175
|
-
process.stdout.isTTY = true;
|
|
176
|
-
|
|
177
|
-
if (!process.stdout.clearLine) {
|
|
178
|
-
process.stdout.clearLine = jest.fn();
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const mockClearLine = jest
|
|
182
|
-
.spyOn(process.stdout, "clearLine")
|
|
183
|
-
.mockImplementation(() => true);
|
|
184
|
-
terminal.clear();
|
|
185
|
-
expect(mockClearLine).toHaveBeenCalled();
|
|
186
|
-
|
|
187
|
-
mockClearLine.mockRestore();
|
|
188
|
-
process.stdout.isTTY = originalIsTTY;
|
|
189
|
-
delete process.stdout.clearLine;
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
it("should not call stdout.clearLine if stdout is not TTY", () => {
|
|
193
|
-
const originalIsTTY = process.stdout.isTTY;
|
|
194
|
-
process.stdout.isTTY = false;
|
|
195
|
-
|
|
196
|
-
process.stdout.clearLine = jest.fn();
|
|
197
|
-
|
|
198
|
-
const mockClearLine = jest.spyOn(process.stdout, "clearLine");
|
|
199
|
-
|
|
200
|
-
terminal.clear();
|
|
201
|
-
expect(mockClearLine).not.toHaveBeenCalled();
|
|
202
|
-
|
|
203
|
-
mockClearLine.mockRestore();
|
|
204
|
-
process.stdout.isTTY = originalIsTTY;
|
|
205
|
-
delete process.stdout.clearLine;
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
describe("setVerbose", () => {
|
|
210
|
-
it("should update the verbose level", () => {
|
|
211
|
-
terminal.setVerbose(1);
|
|
212
|
-
expect(terminal.verbose).toBe(1);
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
});
|