Skip to content

Commit 4f8b0c5

Browse files
authored
feat: CI, tests and fixes
2 parents a107c83 + fec4724 commit 4f8b0c5

File tree

5 files changed

+201
-29
lines changed

5 files changed

+201
-29
lines changed

.github/workflows/deno.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Deno
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
fail-fast: true
14+
matrix:
15+
# Test for latest stable and canary deno versions
16+
deno-version: [vx.x.x, canary]
17+
18+
steps:
19+
- name: Setup repo
20+
uses: actions/checkout@v2
21+
22+
- name: Setup Deno ${{ matrix.deno-version }}
23+
uses: denoland/setup-deno@v1.1.4
24+
with:
25+
deno-version: ${{ matrix.deno-version }}
26+
27+
- name: Check typings
28+
run: deno check main.ts
29+
30+
- name: Check formatting
31+
run: deno fmt --check
32+
33+
- name: Check linting
34+
run: deno lint
35+
36+
- name: Run tests
37+
run: deno task test
38+
39+
- name: Run dry publish
40+
run: deno publish --dry-run
41+
42+
- name: Check license headers
43+
run: |
44+
deno run -A --no-check https://deno.land/x/anzu@1.0.2/src/cli.ts \
45+
-i ./ "/.+\.ts/" \
46+
-e "deps.ts" \
47+
-l "// Copyright 2024 Im-Beast. All rights reserved. MIT license."

deno.jsonc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22
"name": "@crayon/color-support",
33
"version": "2.0.0",
44

5-
"imports": { "@beast/compat": "jsr:@beast/compat@^0.1.2" },
5+
"tasks": {
6+
"test": "deno test --allow-env"
7+
},
8+
9+
"imports": {
10+
"@beast/compat": "jsr:@beast/compat@^0.1.2",
11+
"@std/assert": "jsr:@std/assert@^0.226.0"
12+
},
613
"exports": "./main.ts",
714

815
"compilerOptions": {

deno.lock

Lines changed: 21 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

main.test.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright 2024 Im-Beast. All rights reserved. MIT license.
2+
/// <reference lib="deno.ns" />
3+
4+
import { assertEquals } from "@std/assert";
5+
import { ColorSupport, getColorSupport } from "./main.ts";
6+
7+
function resetEnv(): void {
8+
Deno.env.delete("COLORTERM");
9+
Deno.env.delete("TERM");
10+
Deno.env.delete("CI");
11+
Deno.env.delete("NO_COLOR");
12+
Deno.env.delete("FORCE_COLOR");
13+
}
14+
15+
async function subTest(
16+
t: Deno.TestContext,
17+
variables: [keys: string[], values: string[]][],
18+
expected: ColorSupport,
19+
) {
20+
for (const [keys, values] of variables) {
21+
for (const value of values) {
22+
const keyTitle = keys.length > 1 ? `[${keys}]` : keys[0];
23+
24+
await t.step(
25+
`\x1b[33m${keyTitle}\x1b[0m=\x1b[36m${value}\x1b[0m`,
26+
async () => {
27+
resetEnv();
28+
for (const key of keys) {
29+
Deno.env.set(key, value);
30+
}
31+
32+
assertEquals(await getColorSupport(), expected);
33+
34+
for (const key of keys) {
35+
Deno.env.delete(key);
36+
}
37+
},
38+
);
39+
}
40+
}
41+
}
42+
43+
Deno.test("TrueColor", async (t) => {
44+
await subTest(t, [
45+
[["COLORTERM"], ["truecolor", "24bit"]],
46+
// deno-fmt-ignore
47+
[["TERM"], ["iterm", "linux-truecolor", "screen-truecolor", "tmux-truecolor", "xterm-truecolor", "vte-truecolor"]],
48+
[["CI", "GITHUB_ACTIONS"], ["TRUE", "1"]],
49+
[["CI", "GITEA_ACTIONS"], ["TRUE", "1"]],
50+
[["FORCE_COLOR"], ["1", "TRUE"]],
51+
], ColorSupport.TrueColor);
52+
});
53+
54+
Deno.test("HighColor", async (t) => {
55+
await subTest(t, [
56+
// deno-fmt-ignore
57+
[["TERM"], ["linux-256", "screen-256", "tmux-256", "xterm-256", "xterm", "rxvt", "tmux", "putty", "teken" ]],
58+
], ColorSupport.HighColor);
59+
});
60+
61+
Deno.test("FourBit", async (t) => {
62+
await subTest(t, [
63+
[["COLORTERM"], ["4bit"]],
64+
[["CI", "TRAVIS"], ["1", "TRUE"]],
65+
[["CI", "CIRCLECI"], ["1", "TRUE"]],
66+
[["CI", "GITLAB_CI"], ["1", "TRUE"]],
67+
[["CI", "BUILDKITE"], ["1", "TRUE"]],
68+
[["CI", "DRONE"], ["1", "TRUE"]],
69+
[["CI", "APPVEYOR"], ["1", "TRUE"]],
70+
], ColorSupport.FourBit);
71+
});
72+
73+
Deno.test("None", async (t) => {
74+
await subTest(t, [
75+
[["TERM"], ["DUMB"]],
76+
], ColorSupport.None);
77+
});
78+
79+
Deno.test("NoColor", async (t) => {
80+
await subTest(t, [
81+
[["NO_COLOR"], ["1"]],
82+
], ColorSupport.NoColor);
83+
});

main.ts

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,6 @@ function parseEnv(env: string | undefined): boolean {
88
return !!env && env !== "0";
99
}
1010

11-
let NO_COLOR = false;
12-
let FORCE_COLOR = false;
13-
if (await hasPermission(Permission.Env)) {
14-
NO_COLOR = parseEnv(env("NO_COLOR"));
15-
FORCE_COLOR = parseEnv(env("FORCE_COLOR"));
16-
} else if ("Deno" in globalThis) {
17-
// @ts-expect-error Deno is not defined as a type
18-
NO_COLOR = globalThis.Deno.noColor;
19-
}
20-
21-
async function checkCI(ci: string): Promise<boolean> {
22-
return await hasPermission(Permission.Env, ci) && parseEnv(env(ci));
23-
}
24-
2511
const CITrueColor = [
2612
"GITHUB_ACTIONS",
2713
"GITEA_ACTIONS",
@@ -77,8 +63,24 @@ export enum ColorSupport {
7763
export async function getColorSupport(
7864
defaultColorSupport = ColorSupport.FourBit,
7965
): Promise<ColorSupport> {
80-
if (FORCE_COLOR) return ColorSupport.TrueColor;
81-
else if (NO_COLOR) return ColorSupport.NoColor;
66+
if ("Deno" in globalThis) {
67+
// @ts-ignore Deno types
68+
if (globalThis.Deno?.noColor) return ColorSupport.NoColor;
69+
}
70+
71+
if (
72+
await hasPermission(Permission.Env, "NO_COLOR") &&
73+
parseEnv(env("NO_COLOR"))
74+
) {
75+
return ColorSupport.NoColor;
76+
}
77+
78+
if (
79+
await hasPermission(Permission.Env, "FORCE_COLOR") &&
80+
parseEnv(env("FORCE_COLOR"))
81+
) {
82+
return ColorSupport.TrueColor;
83+
}
8284

8385
if (await hasPermission(Permission.Sys, "osRelease")) {
8486
const details = await osDetails();
@@ -108,16 +110,24 @@ export async function getColorSupport(
108110
}
109111

110112
if (await hasPermission(Permission.Env, "TERM")) {
111-
const term = env("TERM");
113+
const term = env("TERM")?.toLowerCase();
112114
switch (term) {
113115
case "iterm":
114-
case "linux-truecolor":
115-
case "screen-truecolor":
116-
case "tmux-truecolor":
117-
case "xterm-truecolor":
118116
return ColorSupport.TrueColor;
117+
case "xterm":
118+
case "rxvt":
119+
case "tmux":
120+
case "putty":
121+
case "teken":
122+
return ColorSupport.HighColor;
123+
case "dumb":
124+
return ColorSupport.None;
119125
default:
120-
if (term?.startsWith("vte")) {
126+
if (
127+
term?.startsWith("vte") ||
128+
term?.endsWith("24bit") ||
129+
term?.endsWith("truecolor")
130+
) {
121131
return ColorSupport.TrueColor;
122132
} else if (term?.includes("256")) {
123133
return ColorSupport.HighColor;
@@ -127,10 +137,16 @@ export async function getColorSupport(
127137
}
128138

129139
if (await hasPermission(Permission.Env, "CI") && env("CI")) {
130-
if (CITrueColor.find(checkCI)) {
131-
return ColorSupport.TrueColor;
132-
} else if (CIFourBit.find(checkCI)) {
133-
return ColorSupport.FourBit;
140+
for (const ci of CITrueColor) {
141+
if (await hasPermission(Permission.Env, ci) && parseEnv(env(ci))) {
142+
return ColorSupport.TrueColor;
143+
}
144+
}
145+
146+
for (const ci of CIFourBit) {
147+
if (await hasPermission(Permission.Env, ci) && parseEnv(env(ci))) {
148+
return ColorSupport.FourBit;
149+
}
134150
}
135151
}
136152

0 commit comments

Comments
 (0)