Skip to content

Commit 3cfa720

Browse files
feat: Use unicode symbols with ASCII fallback for log labels (#399)
* feat: use unicode symbols with ASCII fallback for log labels * fix: add types * fix: add types * chore: move isUnicodeSupported to separate file
1 parent 27837ac commit 3cfa720

File tree

4 files changed

+126
-6
lines changed

4 files changed

+126
-6
lines changed

lib/__tests__/logger.test.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,83 @@ import {
88
LOG_LEVEL,
99
logger,
1010
shouldLog,
11+
getLabels,
1112
} from '../logger.js';
13+
import { isUnicodeSupported } from '../isUnicodeSupported.js';
1214

1315
describe('lib/logger', () => {
1416
afterEach(() => {
1517
setLogLevel(LOG_LEVEL.LOG);
1618
});
1719

20+
describe('isUnicodeSupported()', () => {
21+
const originalEnv = process.env;
22+
const originalPlatform = process.platform;
23+
24+
afterEach(() => {
25+
process.env = originalEnv;
26+
Object.defineProperty(process, 'platform', {
27+
value: originalPlatform,
28+
});
29+
});
30+
31+
it('returns true on non-win32 when TERM is not linux', () => {
32+
Object.defineProperty(process, 'platform', { value: 'darwin' });
33+
process.env = { ...originalEnv, TERM: 'xterm-256color' };
34+
expect(isUnicodeSupported()).toBe(true);
35+
});
36+
37+
it('returns false on non-win32 when TERM is linux', () => {
38+
Object.defineProperty(process, 'platform', { value: 'linux' });
39+
process.env = { ...originalEnv, TERM: 'linux' };
40+
expect(isUnicodeSupported()).toBe(false);
41+
});
42+
43+
it('returns true on win32 when WT_SESSION is set', () => {
44+
Object.defineProperty(process, 'platform', { value: 'win32' });
45+
process.env = { ...originalEnv, WT_SESSION: '1' };
46+
expect(isUnicodeSupported()).toBe(true);
47+
});
48+
49+
it('returns false on win32 with no unicode-capable env vars', () => {
50+
Object.defineProperty(process, 'platform', { value: 'win32' });
51+
process.env = {};
52+
expect(isUnicodeSupported()).toBe(false);
53+
});
54+
});
55+
56+
describe('getLabels()', () => {
57+
const originalEnv = process.env;
58+
const originalPlatform = process.platform;
59+
60+
afterEach(() => {
61+
process.env = originalEnv;
62+
Object.defineProperty(process, 'platform', {
63+
value: originalPlatform,
64+
});
65+
});
66+
67+
it('returns unicode labels when unicode is supported', () => {
68+
Object.defineProperty(process, 'platform', { value: 'darwin' });
69+
process.env = { ...originalEnv, TERM: 'xterm-256color' };
70+
const labels = getLabels();
71+
expect(labels.success).toBe('✔ SUCCESS');
72+
expect(labels.warning).toBe('⚠ WARNING');
73+
expect(labels.error).toBe('✖ ERROR');
74+
expect(labels.info).toBe('ℹ INFO');
75+
});
76+
77+
it('returns ASCII labels when unicode is not supported', () => {
78+
Object.defineProperty(process, 'platform', { value: 'linux' });
79+
process.env = { ...originalEnv, TERM: 'linux' };
80+
const labels = getLabels();
81+
expect(labels.success).toBe('[SUCCESS]');
82+
expect(labels.warning).toBe('[WARNING]');
83+
expect(labels.error).toBe('[ERROR]');
84+
expect(labels.info).toBe('[INFO]');
85+
});
86+
});
87+
1888
describe('stylize()', () => {
1989
it('stylizes input', () => {
2090
const res = stylize('[ERROR]', Styles.error, ['test']);

lib/__tests__/oauth.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ describe('lib/oauth', () => {
5656
describe('addOauthToAccountConfig', () => {
5757
it('should update the config', () => {
5858
const oauthManager = new OAuth2Manager(account, () => null);
59-
console.log('oauthManager', oauthManager.account);
6059
addOauthToAccountConfig(oauthManager);
6160
expect(updateConfigAccount).toHaveBeenCalledTimes(1);
6261
expect(updateConfigAccount).toHaveBeenCalledWith(account);

lib/isUnicodeSupported.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Adapted from https://github.com/sindresorhus/is-unicode-supported (MIT)
2+
export function isUnicodeSupported(): boolean {
3+
if (process.platform !== 'win32') {
4+
return process.env.TERM !== 'linux';
5+
}
6+
7+
return (
8+
Boolean(process.env.WT_SESSION) ||
9+
Boolean(process.env.TERMINUS_SUBLIME) ||
10+
process.env.ConEmuTask === '{cmd::Cmder}' ||
11+
process.env.TERM_PROGRAM === 'Terminus-Sublime' ||
12+
process.env.TERM_PROGRAM === 'vscode' ||
13+
process.env.TERM === 'xterm-256color' ||
14+
process.env.TERM === 'alacritty' ||
15+
process.env.TERMINAL_EMULATOR === 'JetBrains-JediTerm'
16+
);
17+
}

lib/logger.ts

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
22

33
import chalk, { type ChalkInstance } from 'chalk';
4+
import { isUnicodeSupported } from './isUnicodeSupported.js';
45

56
export const LOG_LEVEL = {
67
NONE: 0,
@@ -10,6 +11,34 @@ export const LOG_LEVEL = {
1011
ERROR: 8,
1112
};
1213

14+
interface LogLabels {
15+
success: string;
16+
warning: string;
17+
error: string;
18+
info: string;
19+
debug: string;
20+
}
21+
22+
const UNICODE_LABELS: LogLabels = {
23+
success: '✔ SUCCESS',
24+
warning: '⚠ WARNING',
25+
error: '✖ ERROR',
26+
info: 'ℹ INFO',
27+
debug: 'DEBUG',
28+
};
29+
30+
const ASCII_LABELS: LogLabels = {
31+
success: '[SUCCESS]',
32+
warning: '[WARNING]',
33+
error: '[ERROR]',
34+
info: '[INFO]',
35+
debug: '[DEBUG]',
36+
};
37+
38+
export function getLabels(): LogLabels {
39+
return isUnicodeSupported() ? UNICODE_LABELS : ASCII_LABELS;
40+
}
41+
1342
/**
1443
* Chalk styles for logger strings.
1544
*/
@@ -33,22 +62,27 @@ export function stylize(label: string, style: ChalkInstance, args: any[]) {
3362

3463
export class Logger {
3564
error(...args: any[]) {
36-
console.error(...stylize('[ERROR]', Styles.error, args));
65+
const labels = getLabels();
66+
console.error(...stylize(labels.error, Styles.error, args));
3767
}
3868
warn(...args: any[]) {
39-
console.warn(...stylize('[WARNING]', Styles.warn, args));
69+
const labels = getLabels();
70+
console.warn(...stylize(labels.warning, Styles.warn, args));
4071
}
4172
log(...args: any[]) {
4273
console.log(...args);
4374
}
4475
success(...args: any[]) {
45-
console.log(...stylize('[SUCCESS]', Styles.success, args));
76+
const labels = getLabels();
77+
console.log(...stylize(labels.success, Styles.success, args));
4678
}
4779
info(...args: any[]) {
48-
console.info(...stylize('[INFO]', Styles.info, args));
80+
const labels = getLabels();
81+
console.info(...stylize(labels.info, Styles.info, args));
4982
}
5083
debug(...args: any[]) {
51-
console.debug(...stylize('[DEBUG]', Styles.log, args));
84+
const labels = getLabels();
85+
console.debug(...stylize(labels.debug, Styles.log, args));
5286
}
5387
group(...args: any[]) {
5488
console.group(...args);

0 commit comments

Comments
 (0)