@lowdep/codestat 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.
- package/LICENSE +21 -0
- package/README.md +131 -0
- package/bin/codestat.js +256 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rushabh Shah
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# codestat
|
|
2
|
+
|
|
3
|
+
   
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
Lines of code by language — zero-dependency Node.js alternative to `cloc`, `tokei`, and `scc`.
|
|
7
|
+
|
|
8
|
+
Counts code lines, comment lines, and blank lines per language. Works on Windows, Mac, and Linux with a single `npx codestat`.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Why?
|
|
13
|
+
|
|
14
|
+
- `cloc` requires Perl
|
|
15
|
+
- `tokei` requires Rust/cargo
|
|
16
|
+
- `scc` requires Go
|
|
17
|
+
|
|
18
|
+
`codestat` is a single Node.js file. If you have Node.js, you have `codestat`.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g codestat
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or without installing:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx codestat
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
codestat # Current directory
|
|
40
|
+
codestat ./src # Specific directory
|
|
41
|
+
codestat --json # JSON output
|
|
42
|
+
codestat --sort files # Sort by file count instead of code lines
|
|
43
|
+
codestat --sort name # Sort alphabetically
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Example Output
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
codestat my-app
|
|
52
|
+
|
|
53
|
+
Language Files Code Comment Blank Total
|
|
54
|
+
──────────────────────────────────────────────────────────────────────────
|
|
55
|
+
TypeScript 84 8,234 412 892 9,538 ████████████████
|
|
56
|
+
CSS 12 2,105 67 341 2,513 █████░░░░░░░░░░░
|
|
57
|
+
JavaScript 8 1,204 189 223 1,616 ███░░░░░░░░░░░░░
|
|
58
|
+
HTML 6 456 0 89 545 █░░░░░░░░░░░░░░░
|
|
59
|
+
YAML 4 112 34 28 174 ░░░░░░░░░░░░░░░░
|
|
60
|
+
Markdown 3 0 0 210 210 ░░░░░░░░░░░░░░░░
|
|
61
|
+
JSON 2 198 0 0 198 ░░░░░░░░░░░░░░░░
|
|
62
|
+
──────────────────────────────────────────────────────────────────────────
|
|
63
|
+
TOTAL 119 12,309 702 1,783 14,794
|
|
64
|
+
|
|
65
|
+
7 language(s) · skipped: node_modules, dist, build, .git
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Supported Languages (36+)
|
|
71
|
+
|
|
72
|
+
TypeScript, JavaScript, Python, Rust, Go, Java, C/C++, C#, PHP, Ruby, Swift, Kotlin, Shell, CSS, SCSS/Sass, Less, HTML, Vue, Svelte, JSON, YAML, TOML, Markdown, SQL, GraphQL, Dockerfile, Makefile, Terraform, Lua, Dart, R, Elixir, Erlang, Haskell, Scala, Text
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Skipped Automatically
|
|
77
|
+
|
|
78
|
+
`node_modules`, `.git`, `dist`, `build`, `out`, `.next`, `coverage`, `__pycache__`, `vendor`, `venv`, `target`
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## JSON Output
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
codestat --json
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"directory": "/path/to/project",
|
|
91
|
+
"summary": {
|
|
92
|
+
"files": 119,
|
|
93
|
+
"code": 12309,
|
|
94
|
+
"comments": 702,
|
|
95
|
+
"blank": 1783,
|
|
96
|
+
"total": 14794
|
|
97
|
+
},
|
|
98
|
+
"languages": [
|
|
99
|
+
{
|
|
100
|
+
"name": "TypeScript",
|
|
101
|
+
"files": 84,
|
|
102
|
+
"code": 8234,
|
|
103
|
+
"comments": 412,
|
|
104
|
+
"blank": 892,
|
|
105
|
+
"total": 9538
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
MIT
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Keywords
|
|
120
|
+
|
|
121
|
+
`lines of code` · `loc counter` · `cloc alternative` · `tokei alternative` · `scc alternative` · `code statistics` · `count lines` · `sloc` · `zero dependencies` · `cross-platform`
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
<div align="center">
|
|
126
|
+
|
|
127
|
+
**Built to solve, shared to help — Rushabh Shah 🛠️✨**
|
|
128
|
+
|
|
129
|
+
<sub>One of 40+ zero-dependency developer CLI tools — no <code>node_modules</code>, ever.</sub>
|
|
130
|
+
|
|
131
|
+
</div>
|
package/bin/codestat.js
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const VERSION = '1.0.0';
|
|
8
|
+
|
|
9
|
+
// ─── Language definitions ─────────────────────────────────────────────────────
|
|
10
|
+
// Each entry: extensions[], name, lineComment, blockCommentStart, blockCommentEnd
|
|
11
|
+
const LANGUAGES = [
|
|
12
|
+
{ name: 'TypeScript', exts: ['.ts', '.tsx'], lc: '//', bs: '/*', be: '*/' },
|
|
13
|
+
{ name: 'JavaScript', exts: ['.js', '.jsx', '.mjs', '.cjs'], lc: '//', bs: '/*', be: '*/' },
|
|
14
|
+
{ name: 'Python', exts: ['.py', '.pyw'], lc: '#', bs: '"""', be: '"""' },
|
|
15
|
+
{ name: 'Rust', exts: ['.rs'], lc: '//', bs: '/*', be: '*/' },
|
|
16
|
+
{ name: 'Go', exts: ['.go'], lc: '//', bs: '/*', be: '*/' },
|
|
17
|
+
{ name: 'Java', exts: ['.java'], lc: '//', bs: '/*', be: '*/' },
|
|
18
|
+
{ name: 'C/C++', exts: ['.c', '.cpp', '.cc', '.cxx', '.h', '.hpp'], lc: '//', bs: '/*', be: '*/' },
|
|
19
|
+
{ name: 'C#', exts: ['.cs'], lc: '//', bs: '/*', be: '*/' },
|
|
20
|
+
{ name: 'PHP', exts: ['.php'], lc: '//', bs: '/*', be: '*/' },
|
|
21
|
+
{ name: 'Ruby', exts: ['.rb'], lc: '#', bs: '=begin', be: '=end' },
|
|
22
|
+
{ name: 'Swift', exts: ['.swift'], lc: '//', bs: '/*', be: '*/' },
|
|
23
|
+
{ name: 'Kotlin', exts: ['.kt', '.kts'], lc: '//', bs: '/*', be: '*/' },
|
|
24
|
+
{ name: 'Shell', exts: ['.sh', '.bash', '.zsh', '.fish'], lc: '#', bs: null, be: null },
|
|
25
|
+
{ name: 'CSS', exts: ['.css'], lc: null, bs: '/*', be: '*/' },
|
|
26
|
+
{ name: 'SCSS/Sass', exts: ['.scss', '.sass'], lc: '//', bs: '/*', be: '*/' },
|
|
27
|
+
{ name: 'Less', exts: ['.less'], lc: '//', bs: '/*', be: '*/' },
|
|
28
|
+
{ name: 'HTML', exts: ['.html', '.htm'], lc: null, bs: '<!--', be: '-->' },
|
|
29
|
+
{ name: 'Vue', exts: ['.vue'], lc: '//', bs: '<!--', be: '-->' },
|
|
30
|
+
{ name: 'Svelte', exts: ['.svelte'], lc: '//', bs: '<!--', be: '-->' },
|
|
31
|
+
{ name: 'JSON', exts: ['.json'], lc: null, bs: null, be: null },
|
|
32
|
+
{ name: 'YAML', exts: ['.yml', '.yaml'], lc: '#', bs: null, be: null },
|
|
33
|
+
{ name: 'TOML', exts: ['.toml'], lc: '#', bs: null, be: null },
|
|
34
|
+
{ name: 'Markdown', exts: ['.md', '.mdx'], lc: null, bs: null, be: null },
|
|
35
|
+
{ name: 'SQL', exts: ['.sql'], lc: '--', bs: '/*', be: '*/' },
|
|
36
|
+
{ name: 'GraphQL', exts: ['.graphql', '.gql'], lc: '#', bs: null, be: null },
|
|
37
|
+
{ name: 'Dockerfile', exts: [], names: ['dockerfile'], lc: '#', bs: null, be: null },
|
|
38
|
+
{ name: 'Makefile', exts: [], names: ['makefile', 'gnumakefile'], lc: '#', bs: null, be: null },
|
|
39
|
+
{ name: 'Terraform', exts: ['.tf', '.tfvars'], lc: '#', bs: '/*', be: '*/' },
|
|
40
|
+
{ name: 'Lua', exts: ['.lua'], lc: '--', bs: '--[[', be: ']]' },
|
|
41
|
+
{ name: 'Dart', exts: ['.dart'], lc: '//', bs: '/*', be: '*/' },
|
|
42
|
+
{ name: 'R', exts: ['.r', '.R'], lc: '#', bs: null, be: null },
|
|
43
|
+
{ name: 'Elixir', exts: ['.ex', '.exs'], lc: '#', bs: null, be: null },
|
|
44
|
+
{ name: 'Erlang', exts: ['.erl', '.hrl'], lc: '%', bs: null, be: null },
|
|
45
|
+
{ name: 'Haskell', exts: ['.hs', '.lhs'], lc: '--', bs: '{-', be: '-}' },
|
|
46
|
+
{ name: 'Scala', exts: ['.scala'], lc: '//', bs: '/*', be: '*/' },
|
|
47
|
+
{ name: 'Text', exts: ['.txt'], lc: null, bs: null, be: null },
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
const EXT_MAP = new Map();
|
|
51
|
+
const NAME_MAP = new Map();
|
|
52
|
+
for (const lang of LANGUAGES) {
|
|
53
|
+
for (const e of (lang.exts || [])) EXT_MAP.set(e, lang);
|
|
54
|
+
for (const n of (lang.names || [])) NAME_MAP.set(n, lang);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function detectLang(filePath) {
|
|
58
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
59
|
+
if (ext && EXT_MAP.has(ext)) return EXT_MAP.get(ext);
|
|
60
|
+
const base = path.basename(filePath).toLowerCase();
|
|
61
|
+
if (NAME_MAP.has(base)) return NAME_MAP.get(base);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ─── Line counter ─────────────────────────────────────────────────────────────
|
|
66
|
+
function countLines(filePath, lang) {
|
|
67
|
+
let content;
|
|
68
|
+
try { content = fs.readFileSync(filePath, 'utf8'); } catch { return null; }
|
|
69
|
+
|
|
70
|
+
const lines = content.split('\n');
|
|
71
|
+
let code = 0, comments = 0, blank = 0;
|
|
72
|
+
let inBlock = false;
|
|
73
|
+
|
|
74
|
+
for (const rawLine of lines) {
|
|
75
|
+
const line = rawLine.trim();
|
|
76
|
+
|
|
77
|
+
if (!line) { blank++; continue; }
|
|
78
|
+
|
|
79
|
+
// Block comment tracking
|
|
80
|
+
if (!inBlock && lang.bs && line.includes(lang.bs)) {
|
|
81
|
+
inBlock = true;
|
|
82
|
+
}
|
|
83
|
+
if (inBlock) {
|
|
84
|
+
comments++;
|
|
85
|
+
if (lang.be && line.includes(lang.be)) inBlock = false;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Line comment
|
|
90
|
+
if (lang.lc && line.startsWith(lang.lc)) {
|
|
91
|
+
comments++;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
code++;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return { code, comments, blank, total: lines.length };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ─── Directory walker ─────────────────────────────────────────────────────────
|
|
102
|
+
const SKIP_DIRS = new Set([
|
|
103
|
+
'node_modules', '.git', 'dist', 'build', 'out', '.next', '.nuxt',
|
|
104
|
+
'__pycache__', 'vendor', 'venv', '.venv', 'env', 'target',
|
|
105
|
+
'.turbo', 'coverage', '.cache', '.svelte-kit', 'public',
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
function walk(dir, results = new Map()) {
|
|
109
|
+
let entries;
|
|
110
|
+
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return results; }
|
|
111
|
+
|
|
112
|
+
for (const e of entries) {
|
|
113
|
+
if (SKIP_DIRS.has(e.name)) continue;
|
|
114
|
+
if (e.name.startsWith('.')) continue;
|
|
115
|
+
|
|
116
|
+
const full = path.join(dir, e.name);
|
|
117
|
+
if (e.isDirectory()) {
|
|
118
|
+
walk(full, results);
|
|
119
|
+
} else if (e.isFile()) {
|
|
120
|
+
const lang = detectLang(full);
|
|
121
|
+
if (!lang) continue;
|
|
122
|
+
const counts = countLines(full, lang);
|
|
123
|
+
if (!counts) continue;
|
|
124
|
+
|
|
125
|
+
const key = lang.name;
|
|
126
|
+
if (!results.has(key)) {
|
|
127
|
+
results.set(key, { name: key, files: 0, code: 0, comments: 0, blank: 0, total: 0 });
|
|
128
|
+
}
|
|
129
|
+
const r = results.get(key);
|
|
130
|
+
r.files++;
|
|
131
|
+
r.code += counts.code;
|
|
132
|
+
r.comments += counts.comments;
|
|
133
|
+
r.blank += counts.blank;
|
|
134
|
+
r.total += counts.total;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return results;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ─── ANSI ─────────────────────────────────────────────────────────────────────
|
|
141
|
+
const isTTY = process.stdout.isTTY;
|
|
142
|
+
const c = (code, t) => isTTY ? `\x1b[${code}m${t}\x1b[0m` : t;
|
|
143
|
+
const bold = t => c('1', t);
|
|
144
|
+
const dim = t => c('2', t);
|
|
145
|
+
const cyan = t => c('36', t);
|
|
146
|
+
const green = t => c('32', t);
|
|
147
|
+
const yellow = t => c('33', t);
|
|
148
|
+
|
|
149
|
+
function bar(pct, width = 16) {
|
|
150
|
+
const filled = Math.round(pct * width);
|
|
151
|
+
const b = '█'.repeat(filled) + '░'.repeat(width - filled);
|
|
152
|
+
if (pct > 0.3) return green(b);
|
|
153
|
+
if (pct > 0.1) return yellow(b);
|
|
154
|
+
return dim(b);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ─── CLI ──────────────────────────────────────────────────────────────────────
|
|
158
|
+
const args = process.argv.slice(2);
|
|
159
|
+
const flags = new Set(args.filter(a => a.startsWith('-')));
|
|
160
|
+
const positional = args.filter(a => !a.startsWith('-'));
|
|
161
|
+
|
|
162
|
+
if (flags.has('--version') || flags.has('-v')) {
|
|
163
|
+
console.log(`codestat v${VERSION}`); process.exit(0);
|
|
164
|
+
}
|
|
165
|
+
if (flags.has('--help') || flags.has('-h')) {
|
|
166
|
+
console.log(`
|
|
167
|
+
${bold('codestat')} — Lines of code by language
|
|
168
|
+
|
|
169
|
+
${bold('USAGE')}
|
|
170
|
+
codestat [directory]
|
|
171
|
+
|
|
172
|
+
${bold('OPTIONS')}
|
|
173
|
+
--json Output as JSON
|
|
174
|
+
--sort code Sort by code lines (default)
|
|
175
|
+
--sort files Sort by file count
|
|
176
|
+
--sort name Sort alphabetically
|
|
177
|
+
--version Show version
|
|
178
|
+
--help Show this help
|
|
179
|
+
|
|
180
|
+
${bold('EXAMPLES')}
|
|
181
|
+
codestat Current directory
|
|
182
|
+
codestat ./src Specific directory
|
|
183
|
+
codestat --json JSON output
|
|
184
|
+
codestat --sort files Sort by file count
|
|
185
|
+
|
|
186
|
+
${bold('NOTE')}
|
|
187
|
+
Skips: node_modules, .git, dist, build, coverage, venv, target
|
|
188
|
+
`);
|
|
189
|
+
process.exit(0);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const targetDir = path.resolve(positional[0] || '.');
|
|
193
|
+
const asJson = flags.has('--json');
|
|
194
|
+
const sortKey = (() => {
|
|
195
|
+
const i = args.indexOf('--sort');
|
|
196
|
+
return i !== -1 ? (args[i + 1] || 'code') : 'code';
|
|
197
|
+
})();
|
|
198
|
+
|
|
199
|
+
if (!fs.existsSync(targetDir)) {
|
|
200
|
+
console.error(`codestat: directory not found: ${targetDir}`);
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!asJson) process.stderr.write(dim('Counting lines…\r'));
|
|
205
|
+
|
|
206
|
+
const results = walk(targetDir);
|
|
207
|
+
const rows = [...results.values()];
|
|
208
|
+
|
|
209
|
+
// Sort
|
|
210
|
+
rows.sort((a, b) => {
|
|
211
|
+
if (sortKey === 'files') return b.files - a.files;
|
|
212
|
+
if (sortKey === 'name') return a.name.localeCompare(b.name);
|
|
213
|
+
return b.code - a.code;
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const totCode = rows.reduce((s, r) => s + r.code, 0);
|
|
217
|
+
const totComments = rows.reduce((s, r) => s + r.comments, 0);
|
|
218
|
+
const totBlank = rows.reduce((s, r) => s + r.blank, 0);
|
|
219
|
+
const totTotal = rows.reduce((s, r) => s + r.total, 0);
|
|
220
|
+
const totFiles = rows.reduce((s, r) => s + r.files, 0);
|
|
221
|
+
|
|
222
|
+
if (asJson) {
|
|
223
|
+
console.log(JSON.stringify({
|
|
224
|
+
directory: targetDir,
|
|
225
|
+
summary: { files: totFiles, code: totCode, comments: totComments, blank: totBlank, total: totTotal },
|
|
226
|
+
languages: rows,
|
|
227
|
+
}, null, 2));
|
|
228
|
+
process.exit(0);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
process.stderr.write(' \r');
|
|
232
|
+
|
|
233
|
+
const projectName = path.basename(targetDir);
|
|
234
|
+
console.log(`\n${bold('codestat')} ${cyan(projectName)} ${dim(targetDir)}\n`);
|
|
235
|
+
|
|
236
|
+
// Dynamic column widths
|
|
237
|
+
const nameW = Math.max(...rows.map(r => r.name.length), 12);
|
|
238
|
+
|
|
239
|
+
const hdr = (s, w) => bold(s.padStart(w));
|
|
240
|
+
console.log(
|
|
241
|
+
` ${'Language'.padEnd(nameW)} ${hdr('Files', 6)} ${hdr('Code', 9)} ${hdr('Comment', 9)} ${hdr('Blank', 7)} ${hdr('Total', 9)} ${''}`,
|
|
242
|
+
);
|
|
243
|
+
console.log(dim(' ' + '─'.repeat(nameW + 60)));
|
|
244
|
+
|
|
245
|
+
for (const r of rows) {
|
|
246
|
+
const pct = totCode > 0 ? r.code / totCode : 0;
|
|
247
|
+
console.log(
|
|
248
|
+
` ${r.name.padEnd(nameW)} ${dim(String(r.files).padStart(6))} ${String(r.code).padStart(9)} ${dim(String(r.comments).padStart(9))} ${dim(String(r.blank).padStart(7))} ${dim(String(r.total).padStart(9))} ${bar(pct)}`,
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
console.log(dim(' ' + '─'.repeat(nameW + 60)));
|
|
253
|
+
console.log(
|
|
254
|
+
` ${bold('TOTAL'.padEnd(nameW))} ${dim(String(totFiles).padStart(6))} ${bold(String(totCode).padStart(9))} ${dim(String(totComments).padStart(9))} ${dim(String(totBlank).padStart(7))} ${dim(String(totTotal).padStart(9))}`,
|
|
255
|
+
);
|
|
256
|
+
console.log(dim(`\n ${rows.length} language(s) · skipped: node_modules, dist, build, .git\n`));
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lowdep/codestat",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Lines of code by language — zero-dep Node.js alternative to cloc/tokei, works on Windows",
|
|
5
|
+
"bin": {
|
|
6
|
+
"codestat": "bin/codestat.js"
|
|
7
|
+
},
|
|
8
|
+
"keywords": [
|
|
9
|
+
"lines-of-code",
|
|
10
|
+
"loc",
|
|
11
|
+
"cloc",
|
|
12
|
+
"statistics",
|
|
13
|
+
"cli",
|
|
14
|
+
"developer-tools",
|
|
15
|
+
"code-analysis",
|
|
16
|
+
"lines of code",
|
|
17
|
+
"loc counter",
|
|
18
|
+
"cloc alternative",
|
|
19
|
+
"tokei alternative",
|
|
20
|
+
"scc alternative",
|
|
21
|
+
"code statistics",
|
|
22
|
+
"count lines",
|
|
23
|
+
"sloc",
|
|
24
|
+
"zero dependencies",
|
|
25
|
+
"cross-platform"
|
|
26
|
+
],
|
|
27
|
+
"author": "Rushabh Shah",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=14"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"bin/"
|
|
34
|
+
],
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/Rushabh5000/codestat.git"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/Rushabh5000/codestat/issues"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/Rushabh5000/codestat#readme",
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
}
|
|
46
|
+
}
|