awecolor 0.1.0

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.
Files changed (3) hide show
  1. package/README.md +67 -0
  2. package/awecolor.mjs +157 -0
  3. package/package.json +29 -0
package/README.md ADDED
@@ -0,0 +1,67 @@
1
+ <div align="center">
2
+ <h1>awecolor: Hex Color Visualizer</h1>
3
+ <p><strong>Colorize hex color codes in your terminal.</strong></p>
4
+ <p>Pipe text or pass files to see hex colors rendered with their actual background.</p>
5
+ <p>
6
+ <strong>English</strong> ·
7
+ <a href="./README_cn.md">简体中文</a>
8
+ </p>
9
+ <p>
10
+ <img src="https://img.shields.io/badge/version-0.1.0-7C3AED?style=flat-square" alt="Version">
11
+ <img src="https://img.shields.io/badge/node-%E2%89%A518-0EA5E9?style=flat-square" alt="Node">
12
+ </p>
13
+ <p>
14
+ <img src="https://img.shields.io/badge/status-alpha-c96a3d?style=flat-square" alt="Status">
15
+ <img src="https://img.shields.io/badge/install-npm-22C55E?style=flat-square" alt="npm install">
16
+ <img src="https://img.shields.io/badge/platform-terminal-334155?style=flat-square" alt="Platform">
17
+ <img src="https://img.shields.io/npm/dm/awecolor?style=flat-square" alt="npm downloads">
18
+ <img src="https://img.shields.io/github/stars/mugpeng/awecolor?style=flat-square" alt="GitHub stars">
19
+ </p>
20
+ </div>
21
+
22
+ > Colorize hex color codes in your terminal.
23
+
24
+ A small CLI that finds hex color codes (`#RGB`, `#RGBA`, `#RRGGBB`, `#RRGGBBAA`) in text and renders them with colored backgrounds. Useful for previewing colors in CSS, config files, or any text that contains hex values.
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ npm install -g awecolor
30
+ ```
31
+
32
+ Or run directly with `npx`:
33
+
34
+ ```bash
35
+ npx awecolor styles.css
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ```bash
41
+ # Pipe from any command
42
+ cat styles.css | awecolor
43
+
44
+ # Read a file directly
45
+ awecolor theme.json
46
+
47
+ # List all colors with locations
48
+ awecolor --extract styles.css
49
+ ```
50
+
51
+ ## Commands
52
+
53
+ ```bash
54
+ awecolor [OPTIONS] [FILE...]
55
+
56
+ awecolor styles.css # Colorize hex codes in a file
57
+ cat styles.css | awecolor # Colorize from stdin
58
+ awecolor --extract styles.css # List colors with location and context
59
+ awecolor --no-color styles.css # Plain text output (no ANSI)
60
+ awecolor --force-color styles.css # Force color even when piped
61
+ ```
62
+
63
+ ## Development
64
+
65
+ ```bash
66
+ npm test
67
+ ```
package/awecolor.mjs ADDED
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+ import { readFile } from "node:fs/promises";
3
+ import { argv, stdin, stdout, stderr, exit } from "node:process";
4
+ import { createRequire } from "node:module";
5
+
6
+ const require = createRequire(import.meta.url);
7
+ const { version: VERSION } = require("./package.json");
8
+
9
+ const HELP = `Usage: awecolor [OPTIONS] [FILE...]
10
+
11
+ Colorize hex color codes in text.
12
+
13
+ Options:
14
+ --extract List colors with location and context instead of colorizing.
15
+ --no-color Output plain text (no ANSI codes).
16
+ --force-color Force color output even when stdout is not a TTY.
17
+ -h, --help Show this message and exit.
18
+ -v, --version Show the version and exit.`;
19
+
20
+ const HEX_RE = /#(?:[0-9a-fA-F]{8}|[0-9a-fA-F]{6}|[0-9a-fA-F]{4}|[0-9a-fA-F]{3})\b(?![0-9a-fA-F])/g;
21
+
22
+ // --- Pure logic ---
23
+
24
+ function expandHex(hex) {
25
+ const h = hex.slice(1);
26
+ if (h.length === 8 || h.length === 6) return "#" + h.slice(0, 6);
27
+ if (h.length === 4) return "#" + h[0] + h[0] + h[1] + h[1] + h[2] + h[2];
28
+ return "#" + h[0] + h[0] + h[1] + h[1] + h[2] + h[2];
29
+ }
30
+
31
+ function hexToRgb(hex) {
32
+ const h = hex.slice(1);
33
+ return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
34
+ }
35
+
36
+ function luminance(r, g, b) {
37
+ return 0.299 * r + 0.587 * g + 0.114 * b;
38
+ }
39
+
40
+ function foregroundColor(hex) {
41
+ const [r, g, b] = hexToRgb(hex);
42
+ return luminance(r, g, b) > 160 ? "#111111" : "#ffffff";
43
+ }
44
+
45
+ function colorize(text, chalk) {
46
+ return text.replace(HEX_RE, (match) => {
47
+ const bg = expandHex(match);
48
+ const fg = foregroundColor(bg);
49
+ return chalk.bgHex(bg).hex(fg)(` ${match} `);
50
+ });
51
+ }
52
+
53
+ function extractColors(text) {
54
+ const results = [];
55
+ const lines = text.split("\n");
56
+ const termWidth = stdout.columns || 80;
57
+
58
+ for (let i = 0; i < lines.length; i++) {
59
+ const line = lines[i];
60
+ let match;
61
+ HEX_RE.lastIndex = 0;
62
+ while ((match = HEX_RE.exec(line)) !== null) {
63
+ const col = match.index + 1;
64
+ const meta = `${match[0]} ${i + 1}:${col}`;
65
+ const maxContext = termWidth - meta.length - 2;
66
+ let context = line;
67
+ if (context.length > maxContext && maxContext > 10) {
68
+ const start = Math.max(0, match.index - Math.floor(maxContext / 3));
69
+ const end = Math.min(line.length, start + maxContext);
70
+ context = (start > 0 ? "..." : "") + line.slice(start, end) + (end < line.length ? "..." : "");
71
+ }
72
+ results.push(`${meta} ${context}`);
73
+ }
74
+ }
75
+ return results;
76
+ }
77
+
78
+ // --- CLI wiring ---
79
+
80
+ function parseArgs(args) {
81
+ const opts = { files: [], extract: false, noColor: false, forceColor: false };
82
+ let i = 0;
83
+ while (i < args.length) {
84
+ const a = args[i];
85
+ if (a === "--extract") { opts.extract = true; i++; }
86
+ else if (a === "--no-color") { opts.noColor = true; i++; }
87
+ else if (a === "--force-color") { opts.forceColor = true; i++; }
88
+ else if (a === "-h" || a === "--help") { stdout.write(HELP + "\n"); exit(0); }
89
+ else if (a === "-v" || a === "--version") { stdout.write(`awecolor ${VERSION}\n`); exit(0); }
90
+ else if (a === "--") { opts.files = args.slice(i + 1); break; }
91
+ else if (a.startsWith("-")) { stderr.write(`Unknown option: ${a}\nRun "awecolor --help" for usage.\n`); exit(1); }
92
+ else { opts.files.push(a); i++; }
93
+ }
94
+ return opts;
95
+ }
96
+
97
+ function isInteractive() {
98
+ return stdin.isTTY && stdout.isTTY;
99
+ }
100
+
101
+ function hasAnsiSupport() {
102
+ return stdout.isTTY || !!process.env.FORCE_COLOR || !!process.env.COLORTERM;
103
+ }
104
+
105
+ async function readStdin() {
106
+ let data = "";
107
+ for await (const chunk of stdin) data += chunk;
108
+ return data;
109
+ }
110
+
111
+ async function main() {
112
+ const args = argv.slice(2);
113
+ const opts = parseArgs(args);
114
+
115
+ const useColor = !opts.noColor && (opts.forceColor || hasAnsiSupport());
116
+
117
+ let Chalk;
118
+ if (useColor) {
119
+ const { Chalk: C } = await import("chalk");
120
+ Chalk = new C({ level: 3 });
121
+ }
122
+
123
+ if (opts.files.length === 0) {
124
+ if (isInteractive()) { stdout.write(HELP + "\n"); exit(0); }
125
+ const text = await readStdin();
126
+ if (!text) { exit(0); }
127
+ if (opts.extract) {
128
+ const results = extractColors(text);
129
+ stdout.write(results.join("\n") + "\n");
130
+ } else if (useColor) {
131
+ stdout.write(colorize(text, Chalk));
132
+ } else {
133
+ stdout.write(text);
134
+ }
135
+ return;
136
+ }
137
+
138
+ for (const file of opts.files) {
139
+ let text;
140
+ try {
141
+ text = await readFile(file, "utf-8");
142
+ } catch (err) {
143
+ stderr.write(`Cannot read "${file}": ${err.code === "ENOENT" ? "file not found" : err.message}\n`);
144
+ exit(1);
145
+ }
146
+ if (opts.extract) {
147
+ const results = extractColors(text);
148
+ stdout.write(results.join("\n") + "\n");
149
+ } else if (useColor) {
150
+ stdout.write(colorize(text, Chalk));
151
+ } else {
152
+ stdout.write(text);
153
+ }
154
+ }
155
+ }
156
+
157
+ main();
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "awecolor",
3
+ "version": "0.1.0",
4
+ "description": "Colorize hex color codes in text",
5
+ "type": "module",
6
+ "bin": {
7
+ "awecolor": "./awecolor.mjs"
8
+ },
9
+ "files": [
10
+ "awecolor.mjs"
11
+ ],
12
+ "keywords": [
13
+ "hex",
14
+ "color",
15
+ "cli",
16
+ "colorize",
17
+ "terminal"
18
+ ],
19
+ "engines": {
20
+ "node": ">=18"
21
+ },
22
+ "dependencies": {
23
+ "chalk": "^5.4.1"
24
+ },
25
+ "scripts": {
26
+ "test": "echo '#FF0000 #00FF00 #0000FF' | node awecolor.mjs --extract | grep -q '#FF0000'"
27
+ },
28
+ "license": "MIT"
29
+ }