devkits-text-counter 1.0.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 (4) hide show
  1. package/README.md +138 -0
  2. package/index.js +158 -0
  3. package/package.json +48 -0
  4. package/test.js +65 -0
package/README.md ADDED
@@ -0,0 +1,138 @@
1
+ # devkits-text-counter
2
+
3
+ > Count words, characters, lines, paragraphs, and reading time
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g devkits-text-counter
9
+ ```
10
+
11
+ Or use without installation:
12
+
13
+ ```bash
14
+ npx devkits-text-counter [args]
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```bash
20
+ # Count text argument
21
+ dk-count "Hello World"
22
+
23
+ # Count file content
24
+ dk-count < file.txt
25
+ dk-count < README.md
26
+
27
+ # Count from stdin
28
+ echo "Hello World" | dk-count
29
+ cat article.md | dk-count
30
+
31
+ # Specific counts
32
+ dk-count -w < file.txt # Words only
33
+ dk-count -c < file.txt # Characters only
34
+ dk-count -l < file.txt # Lines only
35
+ dk-count --json < file.txt # JSON output
36
+ ```
37
+
38
+ ## Output
39
+
40
+ ```
41
+ Characters: 1234 (1100 without spaces)
42
+ Words: 200
43
+ Lines: 15
44
+ Paragraphs: 5
45
+ Reading time: 1 min
46
+ Speaking time: 1 min 32 sec
47
+ ```
48
+
49
+ ## Why @devkits/text-counter?
50
+
51
+ - ✅ Fast - Instant counting
52
+ - ✅ Zero dependencies - Pure Node.js
53
+ - ✅ Offline - Works without internet
54
+ - ✅ Free - Open source (MIT)
55
+ - ✅ CLI - Use in your terminal
56
+ - ✅ Multiple metrics - words, chars, lines, paragraphs, reading time
57
+
58
+ ## Metrics
59
+
60
+ - **Characters** - Total characters (with and without spaces)
61
+ - **Words** - Word count
62
+ - **Lines** - Line count
63
+ - **Paragraphs** - Paragraph count
64
+ - **Reading time** - Estimated at 200 words per minute
65
+ - **Speaking time** - Estimated at 130 words per minute
66
+
67
+ ## Web Version
68
+
69
+ Prefer a GUI? Check out the web version: **https://devkits-tools.surge.sh/tools/text-counter**
70
+
71
+ - 84 developer tools in one PWA
72
+ - Works offline
73
+ - No signup required
74
+
75
+ ## Pro Features
76
+
77
+ Upgrade to Pro for advanced features:
78
+
79
+ - 📦 Batch Processing
80
+ - 🔗 API Access (1000 req/day free)
81
+ - ☁️ Cloud Sync
82
+ - 🎨 Custom Themes
83
+ - 📊 Advanced Analytics
84
+ - 💬 Priority Support
85
+
86
+ **Price:** $9 one-time payment
87
+ **Upgrade:** https://devkits-tools.surge.sh/pro
88
+ **Discount:** Use code `EARLYBIRD-2026` for 20% off
89
+
90
+ ## See Also
91
+
92
+ Part of the **[DevKits Tools](https://devkits-tools.surge.sh)** collection — 80+ free developer tools:
93
+
94
+ ### Popular Tools
95
+
96
+ | Tool | npm Package | Description |
97
+ |------|-------------|-------------|
98
+ | **[Base64](https://devkits-tools.surge.sh/tools/base64)** | `@devkits/base64` | Encode/decode Base64 |
99
+ | **[JSON Formatter](https://devkits-tools.surge.sh/tools/json-formatter)** | `@devkits/json-formatter` | Format and validate JSON |
100
+ | **[Color Converter](https://devkits-tools.surge.sh/tools/color-converter)** | `@devkits/color-converter` | HEX/RGB/HSL conversion |
101
+ | **[UUID Generator](https://devkits-tools.surge.sh/tools/uuid-generator)** | `@devkits/uuid-generator` | Generate unique UUIDs |
102
+ | **[Hash Generator](https://devkits-tools.surge.sh/tools/hash-generator)** | `@devkits/hash-generator` | MD5, SHA1, SHA256, SHA512 |
103
+ | **[Regex Tester](https://devkits-tools.surge.sh/tools/regex-tester)** | `@devkits/regex-tester` | Test regex patterns |
104
+
105
+ ### Other DevKits Tools
106
+
107
+ - **[HTML Tools](https://devkits-tools.surge.sh/tools/html-entities)** — HTML entity encode/decode
108
+ - **[CSS Tools](https://devkits-tools.surge.sh/tools/css-minifier)** — CSS minify/format
109
+ - **[Cron Parser](https://devkits-tools.surge.sh/tools/cron-parser)** — Parse cron expressions
110
+ - **[Case Convert](https://devkits-tools.surge.sh/tools/text-case)** — camelCase, snake_case, etc.
111
+ - **[Slugify](https://devkits-tools.surge.sh/tools/slug-generator)** — Create URL-friendly slugs
112
+ - **[Lorem Ipsum](https://devkits-tools.surge.sh/tools/lorem-ipsum)** — Generate placeholder text
113
+ - **[Password Generator](https://devkits-tools.surge.sh/tools/password-generator)** — Secure passwords
114
+ - **[Timestamp](https://devkits-tools.surge.sh/tools/timestamp)** — Unix timestamp converter
115
+
116
+ ---
117
+
118
+ ### More from DevKits
119
+
120
+ - **[Invoicely](https://invoicely-app.surge.sh)** — Free invoice generator for freelancers
121
+ - **[SnapOG](https://snapog.surge.sh)** — Free OG image generator with 20+ templates
122
+ - **[API Monitor](https://api-monitor-saas.surge.sh)** — Real-time API monitoring
123
+
124
+ ---
125
+
126
+ 👉 **Explore all 80+ developer tools at [DevKits Tools](https://devkits-tools.surge.sh)**
127
+
128
+ ## License
129
+
130
+ MIT © [DevKits Team](https://devkits-tools.surge.sh)
131
+
132
+ ---
133
+
134
+ ## 🚀 API Monitoring for Developers
135
+
136
+ Build better APIs with **API Monitor SaaS** — real-time monitoring, alerting, and analytics.
137
+
138
+ 👉 **Early Access: $1 pre-order (50% off for life)** → https://api-monitor-saas.surge.sh?utm_source=npm&utm_medium=readme&utm_campaign=phase0
package/index.js ADDED
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @devkits/text-counter - Count words, characters, lines, and reading time
5
+ *
6
+ * Usage:
7
+ * dk-count "Hello World" # Count text
8
+ * dk-count < file.txt # Count file
9
+ * echo "text" | dk-count # Count from stdin
10
+ *
11
+ * Web version: https://devkits-tools.surge.sh/tools/text-counter
12
+ * Pro features: https://devkits-tools.surge.sh/pro
13
+ */
14
+
15
+ function countText(text) {
16
+ const chars = text.length;
17
+ const charsNoSpaces = text.replace(/\s/g, '').length;
18
+ const words = text.trim() ? text.trim().split(/\s+/).length : 0;
19
+ const lines = text.split('\n').length;
20
+ const paragraphs = text.split(/\n\s*\n/).filter(p => p.trim()).length;
21
+
22
+ // Reading time: average 200 words per minute
23
+ const readingTimeMinutes = words / 200;
24
+ const readingTimeSeconds = Math.round(readingTimeMinutes * 60);
25
+
26
+ // Speaking time: average 130 words per minute
27
+ const speakingTimeMinutes = words / 130;
28
+ const speakingTimeSeconds = Math.round(speakingTimeMinutes * 60);
29
+
30
+ return {
31
+ characters: chars,
32
+ charactersNoSpaces: charsNoSpaces,
33
+ words: words,
34
+ lines: lines,
35
+ paragraphs: paragraphs || (words > 0 ? 1 : 0),
36
+ readingTime: formatTime(readingTimeSeconds),
37
+ speakingTime: formatTime(speakingTimeSeconds),
38
+ };
39
+ }
40
+
41
+ function formatTime(seconds) {
42
+ if (seconds < 60) {
43
+ return `${seconds} sec`;
44
+ }
45
+ const mins = Math.floor(seconds / 60);
46
+ const secs = seconds % 60;
47
+ return secs > 0 ? `${mins} min ${secs} sec` : `${mins} min`;
48
+ }
49
+
50
+ function showHelp() {
51
+ console.log(`
52
+ @devkits/text-counter - Count words, characters, lines, and reading time
53
+
54
+ Usage:
55
+ dk-count "Hello World" # Count text argument
56
+ dk-count < file.txt # Count file
57
+ echo "text" | dk-count # Count from stdin
58
+
59
+ Options:
60
+ -w, --words Show only word count
61
+ -c, --chars Show only character count
62
+ -l, --lines Show only line count
63
+ -j, --json Output as JSON
64
+ -h, --help Show this help message
65
+
66
+ Output includes:
67
+ - Characters (with and without spaces)
68
+ - Words
69
+ - Lines
70
+ - Paragraphs
71
+ - Reading time (at 200 wpm)
72
+ - Speaking time (at 130 wpm)
73
+
74
+ Examples:
75
+ dk-count "Hello World"
76
+ dk-count < README.md
77
+ dk-count -w < file.txt
78
+ dk-count --json < article.md
79
+
80
+ Web version: https://devkits-tools.surge.sh/tools/text-counter
81
+ Pro features: https://devkits-tools.surge.sh/pro
82
+ `);
83
+ }
84
+
85
+ // Main entry point
86
+ const args = process.argv.slice(2);
87
+
88
+ if (!args.length || args.includes('-h') || args.includes('--help')) {
89
+ showHelp();
90
+ process.exit(0);
91
+ }
92
+
93
+ // Parse options
94
+ let wordsOnly = false;
95
+ let charsOnly = false;
96
+ let linesOnly = false;
97
+ let jsonOutput = false;
98
+ let text = '';
99
+ const remainingArgs = [];
100
+
101
+ for (let i = 0; i < args.length; i++) {
102
+ if (args[i] === '-w' || args[i] === '--words') {
103
+ wordsOnly = true;
104
+ } else if (args[i] === '-c' || args[i] === '--chars') {
105
+ charsOnly = true;
106
+ } else if (args[i] === '-l' || args[i] === '--lines') {
107
+ linesOnly = true;
108
+ } else if (args[i] === '-j' || args[i] === '--json') {
109
+ jsonOutput = true;
110
+ } else {
111
+ remainingArgs.push(args[i]);
112
+ }
113
+ }
114
+
115
+ // Read from stdin if no text provided
116
+ const processText = (text) => {
117
+ const result = countText(text);
118
+
119
+ if (wordsOnly) {
120
+ console.log(result.words);
121
+ } else if (charsOnly) {
122
+ console.log(result.characters);
123
+ } else if (linesOnly) {
124
+ console.log(result.lines);
125
+ } else if (jsonOutput) {
126
+ console.log(JSON.stringify(result, null, 2));
127
+ } else {
128
+ console.log(`Characters: ${result.characters} (${result.charactersNoSpaces} without spaces)`);
129
+ console.log(`Words: ${result.words}`);
130
+ console.log(`Lines: ${result.lines}`);
131
+ console.log(`Paragraphs: ${result.paragraphs}`);
132
+ console.log(`Reading time: ${result.readingTime}`);
133
+ console.log(`Speaking time: ${result.speakingTime}`);
134
+ }
135
+ };
136
+
137
+ if (remainingArgs.length === 0 && !process.stdin.isTTY) {
138
+ let stdin = '';
139
+ process.stdin.setEncoding('utf8');
140
+ process.stdin.on('readable', () => {
141
+ let chunk;
142
+ while ((chunk = process.stdin.read()) !== null) {
143
+ stdin += chunk;
144
+ }
145
+ });
146
+ process.stdin.on('end', () => {
147
+ if (stdin) {
148
+ processText(stdin);
149
+ } else {
150
+ showHelp();
151
+ }
152
+ });
153
+ } else if (remainingArgs.length > 0) {
154
+ text = remainingArgs.join(' ');
155
+ processText(text);
156
+ } else {
157
+ showHelp();
158
+ }
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "devkits-text-counter",
3
+ "version": "1.0.0",
4
+ "description": "Count words, characters, lines, and reading time in text",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "dk-count": "./index.js",
8
+ "text-count": "./index.js"
9
+ },
10
+ "scripts": {
11
+ "test": "node test.js"
12
+ },
13
+ "keywords": [
14
+ "text",
15
+ "count",
16
+ "words",
17
+ "characters",
18
+ "lines",
19
+ "devkits",
20
+ "developer-tools",
21
+ "cli",
22
+ "command-line",
23
+ "nodejs",
24
+ "utility",
25
+ "productivity",
26
+ "dev-tools",
27
+ "free-tools"
28
+ ],
29
+ "author": "DevKits Team <devkits-auto@protonmail.com>",
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/devkits/tools"
34
+ },
35
+ "homepage": "https://devkits-tools.surge.sh/tools/text-counter",
36
+ "bugs": {
37
+ "url": "https://github.com/devkits/tools/issues"
38
+ },
39
+ "engines": {
40
+ "node": ">=14.0.0"
41
+ },
42
+ "files": [
43
+ "index.js",
44
+ "README.md",
45
+ "test.js"
46
+ ],
47
+ "dependencies": {}
48
+ }
package/test.js ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Tests for @devkits/text-counter
5
+ */
6
+
7
+ const { execSync } = require('child_process');
8
+
9
+ const tests = [
10
+ {
11
+ name: 'Count words in text',
12
+ cmd: 'echo "Hello World Test" | node index.js -w',
13
+ check: (result) => parseInt(result.trim()) === 3
14
+ },
15
+ {
16
+ name: 'Count characters in text',
17
+ cmd: 'echo "Hello" | node index.js -c',
18
+ check: (result) => parseInt(result.trim()) === 6 // includes newline from echo
19
+ },
20
+ {
21
+ name: 'Count lines in text',
22
+ cmd: 'echo -e "line1\\nline2\\nline3" | node index.js -l',
23
+ check: (result) => parseInt(result.trim()) === 3
24
+ },
25
+ {
26
+ name: 'JSON output has all fields',
27
+ cmd: 'echo "Hello World" | node index.js --json',
28
+ check: (result) => {
29
+ const data = JSON.parse(result);
30
+ return data.words !== undefined &&
31
+ data.characters !== undefined &&
32
+ data.lines !== undefined;
33
+ }
34
+ },
35
+ {
36
+ name: 'Reading time calculated',
37
+ cmd: 'node index.js "word ".repeat(200)',
38
+ check: (result) => result.includes('Reading time:')
39
+ },
40
+ ];
41
+
42
+ let passed = 0;
43
+ let failed = 0;
44
+
45
+ console.log('Running @devkits/text-counter tests...\n');
46
+
47
+ for (const test of tests) {
48
+ try {
49
+ const result = execSync(test.cmd, { encoding: 'utf8' }).trim();
50
+ if (test.check(result)) {
51
+ console.log(`✅ ${test.name}`);
52
+ passed++;
53
+ } else {
54
+ console.log(`❌ ${test.name}`);
55
+ console.log(` Got: ${result}`);
56
+ failed++;
57
+ }
58
+ } catch (err) {
59
+ console.log(`❌ ${test.name} - Error: ${err.message}`);
60
+ failed++;
61
+ }
62
+ }
63
+
64
+ console.log(`\n${passed}/${tests.length} tests passed`);
65
+ process.exit(failed > 0 ? 1 : 0);