locio 0.1.1 → 0.1.3
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/README.md +22 -16
- package/dist/index.cjs +2 -0
- package/dist/index.js +2 -0
- package/package.json +25 -13
- package/target/release/locio +0 -0
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# LocIO
|
|
2
2
|
|
|
3
3
|
**A powerful CLI tool to count lines and files in directories with extensive filtering options.**
|
|
4
4
|
|
|
@@ -10,14 +10,22 @@
|
|
|
10
10
|
- **Multiple extensions** - comma-separated extension lists (e.g., `rs,ts,js`)
|
|
11
11
|
- **Size filtering** - exclude files by minimum/maximum size
|
|
12
12
|
- **Binary detection** - automatically exclude binary files
|
|
13
|
-
- **
|
|
14
|
-
- **Fast and efficient** - built with
|
|
13
|
+
- **Export reports** - save results as `LocIO-report.{txt,json,csv,tsv}` files
|
|
14
|
+
- **Fast and efficient** - built with TypeScript
|
|
15
15
|
- **Rich statistics** - detailed breakdown by file extension and directory
|
|
16
16
|
|
|
17
17
|
## Quick Start
|
|
18
18
|
|
|
19
19
|
### Installation
|
|
20
20
|
|
|
21
|
+
### Run with npx (no global install)
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx locio@latest
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Install globally with npm
|
|
28
|
+
|
|
21
29
|
```bash
|
|
22
30
|
npm install -g locio
|
|
23
31
|
```
|
|
@@ -31,20 +39,20 @@ locio
|
|
|
31
39
|
# Count in specific directory
|
|
32
40
|
locio /path/to/directory
|
|
33
41
|
|
|
34
|
-
# Count only
|
|
35
|
-
locio --include-ext
|
|
42
|
+
# Count only TypeScript files (dot is optional: .ts or ts both work)
|
|
43
|
+
locio --include-ext ts,tsx --stats
|
|
36
44
|
```
|
|
37
45
|
|
|
38
46
|
## Documentation
|
|
39
47
|
|
|
40
|
-
**[Full Documentation Available Here](https://
|
|
48
|
+
**[Full Documentation Available Here](https://locio.js.org)**
|
|
41
49
|
|
|
42
50
|
The documentation includes:
|
|
43
51
|
|
|
44
52
|
- Complete CLI reference
|
|
45
53
|
- All filtering options and patterns
|
|
46
54
|
- Advanced examples and use cases
|
|
47
|
-
-
|
|
55
|
+
- Export format specifications (JSON, CSV, TSV)
|
|
48
56
|
- Best practices and tips
|
|
49
57
|
|
|
50
58
|
## Basic CLI Usage
|
|
@@ -65,15 +73,15 @@ locio --exclude ".*\.log$" --exclude-dir node_modules
|
|
|
65
73
|
# Include only specific extensions (comma-separated, dots optional)
|
|
66
74
|
locio --include-ext rs,ts,js --stats
|
|
67
75
|
|
|
68
|
-
#
|
|
69
|
-
locio --
|
|
76
|
+
# Export report in JSON format
|
|
77
|
+
locio --stats --export json
|
|
70
78
|
```
|
|
71
79
|
|
|
72
80
|
## Quick Example
|
|
73
81
|
|
|
74
82
|
```bash
|
|
75
|
-
# Count
|
|
76
|
-
locio --include-ext
|
|
83
|
+
# Count TypeScript source files with statistics
|
|
84
|
+
locio --include-ext ts,tsx --stats
|
|
77
85
|
|
|
78
86
|
# Count TypeScript files excluding node_modules (multiple extensions supported)
|
|
79
87
|
locio --include-ext ts,tsx --exclude-dir node_modules
|
|
@@ -81,12 +89,10 @@ locio --include-ext ts,tsx --exclude-dir node_modules
|
|
|
81
89
|
# Count with size limits and binary exclusion
|
|
82
90
|
locio --max-size 5MB --no-binary --stats
|
|
83
91
|
|
|
84
|
-
#
|
|
85
|
-
locio --stats --
|
|
92
|
+
# Export JSON report (writes to LocIO-report.json)
|
|
93
|
+
locio --stats --export json
|
|
86
94
|
```
|
|
87
95
|
|
|
88
96
|
---
|
|
89
97
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
_"Locio: Count your code, not your worries."_
|
|
98
|
+
_"LocIO: Count your code, not your worries."_
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";var e=require("process"),n=require("readline"),t=require("commander"),o=require("fs"),i=require("path"),s=require("chalk"),r=require("fast-glob"),l=require("ignore");function c(e){return e&&e.__esModule?e:{default:e}}function a(e){if(e&&e.__esModule)return e;var n=Object.create(null);return e&&Object.keys(e).forEach(function(t){if("default"!==t){var o=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(n,t,o.get?o:{enumerable:!0,get:function(){return e[t]}})}}),n.default=e,Object.freeze(n)}var d=a(e),f=a(n),u=a(o),y=a(i),_=c(s),p=c(r),x=c(l),g="0.1.2";function m(){const e=new t.Command;return e.name("LocIO").description("A powerful CLI tool to count lines and files in directories").version(g,"-v, --version","Show version number").argument("[directory]","Directory to scan",".").option("-f, --files-only","Count only files").option("-l, --lines-only","Count only lines").option("-e, --exclude <pattern>","Exclude files matching pattern",(e,n)=>n&&Array.isArray(n)?[...n,e]:[e]).option("--exclude-ext <extensions>","Exclude file extensions (comma-separated)").option("--include-ext <extensions>","Include only file extensions (comma-separated)").option("--exclude-dir <pattern>","Exclude directories matching pattern",(e,n)=>n&&Array.isArray(n)?[...n,e]:[e]).option("--include-dir <pattern>","Include only directories matching pattern",(e,n)=>n&&Array.isArray(n)?[...n,e]:[e]).option("--exclude-name <pattern>","Exclude files by name pattern",(e,n)=>n&&Array.isArray(n)?[...n,e]:[e]).option("--include-name <pattern>","Include only files by name pattern",(e,n)=>n&&Array.isArray(n)?[...n,e]:[e]).option("--max-size <size>","Maximum file size (e.g., 5MB)").option("--min-size <size>","Minimum file size (e.g., 1KB)").option("--no-hidden","Exclude hidden files").option("--no-empty","Exclude empty files").option("--follow-links","Follow symbolic links").option("--max-depth <depth>","Maximum directory depth",parseInt).option("--stats","Show detailed statistics").option("-p, --progress","Show progress").option("--include-blank","Include blank lines in count").option("--no-binary","Exclude binary files").option("-i, --ignore-case","Case-insensitive pattern matching").option("-q, --quiet","Quiet mode (minimal output)").option("--export [format]","Write report to LocIO-report.{ext} in the given format (human, json, csv, tsv)"),e}var b=class e extends Error{constructor(e,n){super(e),this.cause=n,this.name="LineCounterError"}static io(n,t){return new e(`IO error: ${n}`,t)}static invalidSizeFormat(n){return new e(`Invalid size format: ${n}`)}static invalidRegex(n,t){return new e(`Invalid regex pattern: ${n}${t?`: ${t.message}`:""}`,t)}static directoryNotFound(n){return new e(`Directory not found: ${n}`)}static notADirectory(n){return new e(`Not a directory: ${n}`)}};function h(e){return e instanceof b}function w(e){const n=["B","KB","MB","GB","TB"];let t=e,o=0;for(;t>=1024&&o<n.length-1;)t/=1024,o+=1;return 0===o?`${Math.floor(t)} ${n[o]}`:`${t.toFixed(2)} ${n[o]}`}function $(e){const n=e.directory;return"."===n?"current":n}function v(e,n){let t,o;switch(n.export||"human"){case"human":t="txt",o=function(e,n){let t="";if(n.quiet)return t+=`${e.total_files} ${e.total_lines}\n`,t;t+="=".repeat(60)+"\n",t+="LocIO RESULTS\n",t+="=".repeat(60)+"\n\n",t+=`Directory: ${$(n)}\n`,n.lines_only||(t+=`\nTotal Files: ${e.total_files}\n`,t+=`\nTotal Files Size: ${w(e.total_size)}\n`),n.files_only||(t+=`\nTotal Lines: ${e.total_lines}\n`),Object.keys(e.files_by_extension).length>0&&(t+=`\nExtensions: ${Object.keys(e.files_by_extension).sort().join(", ")}\n`);if(n.show_stats&&Object.keys(e.files_by_extension).length>0){const o=Object.keys(e.files_by_extension).sort();t+="\nStatistics by Extension:\n",t+="-".repeat(60)+"\n";for(const i of o){const o=e.files_by_extension[i],s=e.size_by_extension[i]||0,r=e.lines_by_extension[i]||0;t+=` ${i}: ${o} files`,n.lines_only||(t+=`, ${w(s)}`),n.files_only||(t+=`, ${r} lines`),t+="\n"}}if(n.show_stats&&e.details.length>0){t+="\nFiles by Directory:\n",t+="-".repeat(60)+"\n";const o={};for(const n of e.details)o[n.directory]||(o[n.directory]=[]),o[n.directory].push(n);const i=Object.keys(o).sort();for(const e of i){const i=o[e];t+=`Directory: ${e}\n`;for(const e of i){const o=w(e.size),i=null===e.lines||n.files_only?"":` | ${e.lines} lines`;t+=` - ${e.name} (${e.extension}, ${o}${i})\n`}t+="\n"}}return t+="\n",t}(e,n);break;case"json":t="json",o=function(e,n){const t={directory:$(n),files:e.total_files,size:e.total_size,size_formatted:w(e.total_size)};if(n.files_only||(t.lines=e.total_lines),n.show_stats){const n={};for(const t of Object.keys(e.files_by_extension))n[t]={files:e.files_by_extension[t],lines:e.lines_by_extension[t]||0,size:e.size_by_extension[t]||0};t.by_extension=n}return JSON.stringify(t,null,2)}(e,n);break;case"csv":t="csv",o=function(e,n){let t=`# Directory,${$(n)}\n`;t+="Extension,Files,Lines,Size\n";for(const n of Object.keys(e.files_by_extension))t+=`${n},${e.files_by_extension[n]},${e.lines_by_extension[n]||0},${e.size_by_extension[n]||0}\n`;return t}(e,n);break;case"tsv":t="tsv",o=function(e,n){let t=`# Directory\t${$(n)}\n`;t+="Extension\tFiles\tLines\tSize\n";for(const n of Object.keys(e.files_by_extension))t+=`${n}\t${e.files_by_extension[n]}\t${e.lines_by_extension[n]||0}\t${e.size_by_extension[n]||0}\n`;return t}(e,n)}const i=`LocIO-report.${t}`;try{u.writeFileSync(i,o,"utf-8"),n.quiet||console.log(`Report written to ${i}`)}catch(e){console.error(`Failed to create report file ${i}: ${e}`)}}function z(e,n){void 0===n.export?function(e,n){if(n.quiet)console.log(`${e.total_files} ${e.total_lines}`);else{if(console.log("\n"+_.default.cyan("=".repeat(60))),console.log(_.default.cyan.bold("LocIO RESULTS")),console.log(_.default.cyan("=".repeat(60))),console.log(`\n${_.default.green.bold("Directory:")} ${$(n)}`),n.lines_only||(console.log(`\n${_.default.green.bold("Total Files:")} ${_.default.yellow(e.total_files)}`),console.log(`\n${_.default.green.bold("Total Files Size:")} ${_.default.white(w(e.total_size))}`)),n.files_only||console.log(`\n${_.default.green.bold("Total Lines:")} ${_.default.yellow(e.total_lines)}`),Object.keys(e.files_by_extension).length>0){const n=Object.keys(e.files_by_extension).sort();console.log(`\n${_.default.green.bold("Extensions:")} ${_.default.white(n.join(", "))}`)}if(n.show_stats&&Object.keys(e.files_by_extension).length>0){console.log(`\n${_.default.cyan.bold("Statistics by Extension:")}`),console.log(_.default.gray("-".repeat(60)));const t=Object.keys(e.files_by_extension).sort();for(const o of t){const t=e.files_by_extension[o],i=e.size_by_extension[o]||0,s=e.lines_by_extension[o]||0;process.stdout.write(` ${_.default.white(o)}: ${_.default.yellow(t)} files`),n.lines_only||process.stdout.write(`, ${_.default.white(w(i))}`),n.files_only||process.stdout.write(`, ${_.default.yellow(s)} lines`),console.log()}}if(n.show_stats&&e.details.length>0){console.log(`\n${_.default.cyan.bold("Files by Directory:")}`),console.log(_.default.gray("-".repeat(60)));const t={};for(const n of e.details)t[n.directory]||(t[n.directory]=[]),t[n.directory].push(n);const o=Object.keys(t).sort();for(const e of o){const o=t[e];console.log(_.default.green.bold(`Directory: ${e}`));for(const e of o){const t=w(e.size),o=null===e.lines||n.files_only?"":` | ${e.lines} lines`;console.log(` - ${_.default.white(e.name)} (${_.default.blue(e.extension)}, ${_.default.white(t)}${o})`)}console.log()}}console.log()}}(e,n):v(e,n)}function S(e){const n=e.trim().toUpperCase();let t,o;n.endsWith("KB")?(t=n.slice(0,-2),o=1024):n.endsWith("MB")?(t=n.slice(0,-2),o=1048576):n.endsWith("GB")?(t=n.slice(0,-2),o=1073741824):n.endsWith("B")&&n.length>1?(t=n.slice(0,-1),o=1):(t=n,o=1);const i=parseFloat(t);return isNaN(i)?b.invalidSizeFormat(e):Math.floor(i*o)}function k(e,n){try{const t=u.readFileSync(e,"utf-8").split(/\r?\n/);return n?t.length:t.filter(e=>e.trim().length>0).length}catch(n){return b.io(`Failed to read file: ${e}`,n instanceof Error?n:void 0)}}var O=["jpg","jpeg","png","gif","bmp","svg","ico","webp","tiff","tif","psd","raw","heic","heif","avif","mp3","wav","flac","aac","ogg","wma","m4a","opus","aiff","au","mp4","avi","mkv","mov","wmv","flv","webm","m4v","mpg","mpeg","3gp","ogv","zip","rar","7z","tar","gz","bz2","xz","z","cab","iso","dmg","pkg","deb","rpm","pdf","doc","docx","xls","xlsx","ppt","pptx","odt","ods","odp","exe","dll","so","dylib","app","msi","bin","run","ttf","otf","woff","woff2","eot","db","sqlite","sqlite3","mdb","accdb","ps","eps","ai","sketch","fig","xd"];function E(e,n,t){const o=e,i=y.basename(e);for(const e of t.exclude_patterns)if(e.test(o))return!0;const s=y.extname(e).replace(/^\./,"").toLowerCase();if(s){for(const e of t.exclude_extensions)if(s===e.toLowerCase())return!0;if(t.include_extensions.length>0){let e=!1;for(const n of t.include_extensions)if(s===n.toLowerCase()){e=!0;break}if(!e)return!0}}else if(t.include_extensions.length>0)return!0;const r=y.dirname(e);for(const e of t.exclude_dirs)if(e.test(r))return!0;if(t.include_dirs.length>0){let e=!1;for(const n of t.include_dirs)if(n.test(r)){e=!0;break}if(!e)return!0}for(const e of t.exclude_names)if(e.test(i))return!0;if(t.include_names.length>0){let e=!1;for(const n of t.include_names)if(n.test(i)){e=!0;break}if(!e)return!0}if(n.no_hidden&&i.startsWith("."))return!0;try{const t=u.statSync(e).size;if(n.max_size){const e=S(n.max_size);if(!(e instanceof b)&&t>e)return!0}if(n.min_size){const e=S(n.min_size);if(!(e instanceof b)&&t<e)return!0}if(n.no_empty&&0===t)return!0}catch{}return!(!n.no_binary||!function(e){try{const n=Buffer.alloc(8192),t=u.openSync(e,"r"),o=u.readSync(t,n,0,8192,0);if(u.closeSync(t),0===o)return!1;for(let e=0;e<o;e++)if(0===n[e])return!0;return!1}catch{return!1}}(e))}function L(e){const n=Date.now(),t={total_files:0,total_lines:0,total_size:0,files_by_extension:{},lines_by_extension:{},size_by_extension:{},details:[]},o=function(e){try{const n=e.exclude_patterns.map(n=>{try{return new RegExp(n,e.ignore_case?"i":void 0)}catch(e){throw b.invalidRegex(n,e instanceof Error?e:void 0)}}),t=[...e.exclude_extensions.map(e=>e.replace(/^\./,"").toLowerCase()),...O.map(e=>e.toLowerCase())],o=Array.from(new Set(t)).sort(),i=e.include_extensions.map(e=>e.replace(/^\./,"").toLowerCase()),s=e.exclude_dirs.map(n=>new RegExp(n,e.ignore_case?"i":void 0)),r=e.include_dirs.map(n=>new RegExp(n,e.ignore_case?"i":void 0));return{exclude_patterns:n,exclude_extensions:o,include_extensions:i,exclude_dirs:s,include_dirs:r,exclude_names:e.exclude_names.map(n=>new RegExp(n,e.ignore_case?"i":void 0)),include_names:e.include_names.map(n=>new RegExp(n,e.ignore_case?"i":void 0))}}catch(e){return e instanceof b?e:b.io(`Failed to create filter patterns: ${e instanceof Error?e.message:String(e)}`)}}(e);if(h(o))return o;const i=function(e){const n=x.default();return n.add(".git"),n.add(".gitignore"),n.add(".lcignore"),function e(t,o){const i=y.join(t,".gitignore");try{if(u.existsSync(i)&&u.statSync(i).isFile()){const e=u.readFileSync(i,"utf-8"),s=y.relative(o,t)||".",r=e.split("\n").map(e=>e.trim()).filter(e=>e&&!e.startsWith("#"));for(const e of r)"."===s?n.add(e):n.add(y.join(s,e))}}catch{}try{const n=u.readdirSync(t);for(const i of n){const n=y.join(t,i);try{u.statSync(n).isDirectory()&&".git"!==i&&e(n,o)}catch{}}}catch{}}(e,e),n}(e.directory),s=y.join(e.directory,"**/*"),r={cwd:e.directory,absolute:!0,onlyFiles:!0,ignore:[],dot:!e.no_hidden,followSymbolicLinks:e.follow_links};let l=0,c=0;try{const n=p.default.sync(s,r).map(e=>"string"==typeof e?e:e.path||String(e));for(const s of n){if(void 0!==e.max_depth){const n=y.relative(e.directory,s);if(n.split(y.sep).length-1>e.max_depth)continue}const n=y.relative(e.directory,s);if(i.ignores(n))continue;try{if(!u.statSync(s).isFile())continue}catch{continue}if(E(s,e,o))continue;let r;l+=1,e.show_progress&&l%100==0&&!e.quiet&&process.stderr.write(`\rProcessed: ${l} files...`);try{r=u.statSync(s)}catch(n){e.quiet||console.error(`Warning: Could not read metadata for ${s}: ${n}`),c+=1;continue}const a=r.size,d=y.extname(s).replace(/^\./,"").toLowerCase()||"no-ext";t.total_files+=1,t.total_size+=a,t.files_by_extension[d]=(t.files_by_extension[d]||0)+1,t.size_by_extension[d]=(t.size_by_extension[d]||0)+a;let f=null;if(!e.files_only){const n=k(s,e.include_blank);h(n)?(e.quiet||console.error(`Warning: Could not count lines in ${s}: ${n.message}`),c+=1):(f=n,t.total_lines+=n,t.lines_by_extension[d]=(t.lines_by_extension[d]||0)+n)}const _=y.dirname(s),p=y.basename(s);t.details.push({directory:_,name:p,extension:d,size:a,lines:f})}}catch(e){return b.io(`Failed to scan directory: ${e instanceof Error?e.message:String(e)}`,e instanceof Error?e:void 0)}if(e.show_progress&&!e.quiet){const e=`${Date.now()-n}ms`;process.stderr.write(`\rProcessed: ${l} files (${c} errors) in ${e}\n`)}return t}function j(e){const n=function(e){if(e.version)return void console.log(`LocIO ${g}`);const n=y.resolve(e.directory);if(!u.existsSync(n))return b.directoryNotFound(e.directory);if(!u.statSync(n).isDirectory())return b.notADirectory(e.directory);const t=L({...e,directory:n});if(h(t))return t;z(t,{...e,directory:n})}(e);h(n)&&(console.error(`Error: ${n.message}`),process.exit(1)),process.exit(0)}(async function(){if(2===d.argv.length&&d.stdin.isTTY){if(!await new Promise((e,n)=>{const t=g;console.log("===================================="),console.log(` LocIO CLI v${t}`),console.log("===================================="),console.log("A fast, flexible line and file counter for your projects.\n"),console.log("Select an option:"),console.log(" 1) Quick scan of current directory (default settings)"),console.log(" 2) Show common command examples"),console.log(" 3) View full help (same as --help)"),console.log(" q) Quit\n"),d.nextTick(()=>{const t=f.createInterface({input:d.stdin,output:d.stdout}),o=()=>{t.question("Enter choice (1/2/3/q): ",n=>{switch(n.trim()){case"1":console.log('\nRunning quick scan on current directory (".") with default settings...\n'),t.close(),e(!0);break;case"2":console.log("\nCommon commands:"),console.log(" LocIO . --files-only"),console.log(" Scan current directory with default settings."),console.log(" LocIO . --files-only"),console.log(" Show only file counts."),console.log(" LocIO . --lines-only"),console.log(" Show only line counts."),console.log(' LocIO . --exclude "target" --exclude-dir ".git"'),console.log(" Ignore build and VCS directories."),console.log(" LocIO . --include-ext rs,ts,tsx"),console.log(" Only include specific extensions."),console.log(" LocIO . --export json"),console.log(" Print results in JSON format.\n"),t.close(),e(!1);break;case"3":console.log(),m().outputHelp(),console.log("\n"),t.close(),e(!1);break;case"q":case"Q":console.log("\nThank you for using LocIO."),t.close(),e(!1);break;default:console.log("Invalid choice. Please enter 1, 2, 3, or q.\n"),o()}})};t.on("error",e=>{console.error("\nFailed to read input. Exiting."),t.close(),n(e)}),o()})}))return}j(function(){const e=m();e.parse();const n=e.opts(),t=e.args,o=n.excludeExt?n.excludeExt.split(",").map(e=>e.trim()):[],i=n.includeExt?n.includeExt.split(",").map(e=>e.trim()):[];return{directory:t[0]||".",files_only:n.filesOnly||!1,lines_only:n.linesOnly||!1,exclude_patterns:n.exclude||[],exclude_extensions:o,include_extensions:i,exclude_dirs:n.excludeDir||[],include_dirs:n.includeDir||[],exclude_names:n.excludeName||[],include_names:n.includeName||[],max_size:n.maxSize,min_size:n.minSize,no_hidden:n.noHidden||!1,no_empty:n.noEmpty||!1,follow_links:n.followLinks||!1,max_depth:n.maxDepth,show_stats:n.stats||!1,show_progress:n.progress||!1,include_blank:n.includeBlank||!1,no_binary:n.noBinary||!1,ignore_case:n.ignoreCase||!1,quiet:n.quiet||!1,export:void 0!==n.export?!0===n.export?"human":"json"===n.export.toLowerCase()?"json":"csv"===n.export.toLowerCase()?"csv":"tsv"===n.export.toLowerCase()?"tsv":"human":void 0,version:!1}}())})().catch(e=>{console.error("Unexpected error:",e),d.exit(1)});
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import*as e from"process";import*as o from"readline";import{Command as n}from"commander";import*as t from"fs";import*as i from"path";import s from"chalk";import r from"fast-glob";import l from"ignore";var c="0.1.2";function a(){const e=new n;return e.name("LocIO").description("A powerful CLI tool to count lines and files in directories").version(c,"-v, --version","Show version number").argument("[directory]","Directory to scan",".").option("-f, --files-only","Count only files").option("-l, --lines-only","Count only lines").option("-e, --exclude <pattern>","Exclude files matching pattern",(e,o)=>o&&Array.isArray(o)?[...o,e]:[e]).option("--exclude-ext <extensions>","Exclude file extensions (comma-separated)").option("--include-ext <extensions>","Include only file extensions (comma-separated)").option("--exclude-dir <pattern>","Exclude directories matching pattern",(e,o)=>o&&Array.isArray(o)?[...o,e]:[e]).option("--include-dir <pattern>","Include only directories matching pattern",(e,o)=>o&&Array.isArray(o)?[...o,e]:[e]).option("--exclude-name <pattern>","Exclude files by name pattern",(e,o)=>o&&Array.isArray(o)?[...o,e]:[e]).option("--include-name <pattern>","Include only files by name pattern",(e,o)=>o&&Array.isArray(o)?[...o,e]:[e]).option("--max-size <size>","Maximum file size (e.g., 5MB)").option("--min-size <size>","Minimum file size (e.g., 1KB)").option("--no-hidden","Exclude hidden files").option("--no-empty","Exclude empty files").option("--follow-links","Follow symbolic links").option("--max-depth <depth>","Maximum directory depth",parseInt).option("--stats","Show detailed statistics").option("-p, --progress","Show progress").option("--include-blank","Include blank lines in count").option("--no-binary","Exclude binary files").option("-i, --ignore-case","Case-insensitive pattern matching").option("-q, --quiet","Quiet mode (minimal output)").option("--export [format]","Write report to LocIO-report.{ext} in the given format (human, json, csv, tsv)"),e}var f=class e extends Error{constructor(e,o){super(e),this.cause=o,this.name="LineCounterError"}static io(o,n){return new e(`IO error: ${o}`,n)}static invalidSizeFormat(o){return new e(`Invalid size format: ${o}`)}static invalidRegex(o,n){return new e(`Invalid regex pattern: ${o}${n?`: ${n.message}`:""}`,n)}static directoryNotFound(o){return new e(`Directory not found: ${o}`)}static notADirectory(o){return new e(`Not a directory: ${o}`)}};function d(e){return e instanceof f}function u(e){const o=["B","KB","MB","GB","TB"];let n=e,t=0;for(;n>=1024&&t<o.length-1;)n/=1024,t+=1;return 0===t?`${Math.floor(n)} ${o[t]}`:`${n.toFixed(2)} ${o[t]}`}function y(e){const o=e.directory;return"."===o?"current":o}function p(e,o){let n,i;switch(o.export||"human"){case"human":n="txt",i=function(e,o){let n="";if(o.quiet)return n+=`${e.total_files} ${e.total_lines}\n`,n;n+="=".repeat(60)+"\n",n+="LocIO RESULTS\n",n+="=".repeat(60)+"\n\n",n+=`Directory: ${y(o)}\n`,o.lines_only||(n+=`\nTotal Files: ${e.total_files}\n`,n+=`\nTotal Files Size: ${u(e.total_size)}\n`),o.files_only||(n+=`\nTotal Lines: ${e.total_lines}\n`),Object.keys(e.files_by_extension).length>0&&(n+=`\nExtensions: ${Object.keys(e.files_by_extension).sort().join(", ")}\n`);if(o.show_stats&&Object.keys(e.files_by_extension).length>0){const t=Object.keys(e.files_by_extension).sort();n+="\nStatistics by Extension:\n",n+="-".repeat(60)+"\n";for(const i of t){const t=e.files_by_extension[i],s=e.size_by_extension[i]||0,r=e.lines_by_extension[i]||0;n+=` ${i}: ${t} files`,o.lines_only||(n+=`, ${u(s)}`),o.files_only||(n+=`, ${r} lines`),n+="\n"}}if(o.show_stats&&e.details.length>0){n+="\nFiles by Directory:\n",n+="-".repeat(60)+"\n";const t={};for(const o of e.details)t[o.directory]||(t[o.directory]=[]),t[o.directory].push(o);const i=Object.keys(t).sort();for(const e of i){const i=t[e];n+=`Directory: ${e}\n`;for(const e of i){const t=u(e.size),i=null===e.lines||o.files_only?"":` | ${e.lines} lines`;n+=` - ${e.name} (${e.extension}, ${t}${i})\n`}n+="\n"}}return n+="\n",n}(e,o);break;case"json":n="json",i=function(e,o){const n={directory:y(o),files:e.total_files,size:e.total_size,size_formatted:u(e.total_size)};if(o.files_only||(n.lines=e.total_lines),o.show_stats){const o={};for(const n of Object.keys(e.files_by_extension))o[n]={files:e.files_by_extension[n],lines:e.lines_by_extension[n]||0,size:e.size_by_extension[n]||0};n.by_extension=o}return JSON.stringify(n,null,2)}(e,o);break;case"csv":n="csv",i=function(e,o){let n=`# Directory,${y(o)}\n`;n+="Extension,Files,Lines,Size\n";for(const o of Object.keys(e.files_by_extension))n+=`${o},${e.files_by_extension[o]},${e.lines_by_extension[o]||0},${e.size_by_extension[o]||0}\n`;return n}(e,o);break;case"tsv":n="tsv",i=function(e,o){let n=`# Directory\t${y(o)}\n`;n+="Extension\tFiles\tLines\tSize\n";for(const o of Object.keys(e.files_by_extension))n+=`${o}\t${e.files_by_extension[o]}\t${e.lines_by_extension[o]||0}\t${e.size_by_extension[o]||0}\n`;return n}(e,o)}const s=`LocIO-report.${n}`;try{t.writeFileSync(s,i,"utf-8"),o.quiet||console.log(`Report written to ${s}`)}catch(e){console.error(`Failed to create report file ${s}: ${e}`)}}function _(e,o){void 0===o.export?function(e,o){if(o.quiet)console.log(`${e.total_files} ${e.total_lines}`);else{if(console.log("\n"+s.cyan("=".repeat(60))),console.log(s.cyan.bold("LocIO RESULTS")),console.log(s.cyan("=".repeat(60))),console.log(`\n${s.green.bold("Directory:")} ${y(o)}`),o.lines_only||(console.log(`\n${s.green.bold("Total Files:")} ${s.yellow(e.total_files)}`),console.log(`\n${s.green.bold("Total Files Size:")} ${s.white(u(e.total_size))}`)),o.files_only||console.log(`\n${s.green.bold("Total Lines:")} ${s.yellow(e.total_lines)}`),Object.keys(e.files_by_extension).length>0){const o=Object.keys(e.files_by_extension).sort();console.log(`\n${s.green.bold("Extensions:")} ${s.white(o.join(", "))}`)}if(o.show_stats&&Object.keys(e.files_by_extension).length>0){console.log(`\n${s.cyan.bold("Statistics by Extension:")}`),console.log(s.gray("-".repeat(60)));const n=Object.keys(e.files_by_extension).sort();for(const t of n){const n=e.files_by_extension[t],i=e.size_by_extension[t]||0,r=e.lines_by_extension[t]||0;process.stdout.write(` ${s.white(t)}: ${s.yellow(n)} files`),o.lines_only||process.stdout.write(`, ${s.white(u(i))}`),o.files_only||process.stdout.write(`, ${s.yellow(r)} lines`),console.log()}}if(o.show_stats&&e.details.length>0){console.log(`\n${s.cyan.bold("Files by Directory:")}`),console.log(s.gray("-".repeat(60)));const n={};for(const o of e.details)n[o.directory]||(n[o.directory]=[]),n[o.directory].push(o);const t=Object.keys(n).sort();for(const e of t){const t=n[e];console.log(s.green.bold(`Directory: ${e}`));for(const e of t){const n=u(e.size),t=null===e.lines||o.files_only?"":` | ${e.lines} lines`;console.log(` - ${s.white(e.name)} (${s.blue(e.extension)}, ${s.white(n)}${t})`)}console.log()}}console.log()}}(e,o):p(e,o)}function x(e){const o=e.trim().toUpperCase();let n,t;o.endsWith("KB")?(n=o.slice(0,-2),t=1024):o.endsWith("MB")?(n=o.slice(0,-2),t=1048576):o.endsWith("GB")?(n=o.slice(0,-2),t=1073741824):o.endsWith("B")&&o.length>1?(n=o.slice(0,-1),t=1):(n=o,t=1);const i=parseFloat(n);return isNaN(i)?f.invalidSizeFormat(e):Math.floor(i*t)}function g(e,o){try{const n=t.readFileSync(e,"utf-8").split(/\r?\n/);return o?n.length:n.filter(e=>e.trim().length>0).length}catch(o){return f.io(`Failed to read file: ${e}`,o instanceof Error?o:void 0)}}var m=["jpg","jpeg","png","gif","bmp","svg","ico","webp","tiff","tif","psd","raw","heic","heif","avif","mp3","wav","flac","aac","ogg","wma","m4a","opus","aiff","au","mp4","avi","mkv","mov","wmv","flv","webm","m4v","mpg","mpeg","3gp","ogv","zip","rar","7z","tar","gz","bz2","xz","z","cab","iso","dmg","pkg","deb","rpm","pdf","doc","docx","xls","xlsx","ppt","pptx","odt","ods","odp","exe","dll","so","dylib","app","msi","bin","run","ttf","otf","woff","woff2","eot","db","sqlite","sqlite3","mdb","accdb","ps","eps","ai","sketch","fig","xd"];function b(e,o,n){const s=e,r=i.basename(e);for(const e of n.exclude_patterns)if(e.test(s))return!0;const l=i.extname(e).replace(/^\./,"").toLowerCase();if(l){for(const e of n.exclude_extensions)if(l===e.toLowerCase())return!0;if(n.include_extensions.length>0){let e=!1;for(const o of n.include_extensions)if(l===o.toLowerCase()){e=!0;break}if(!e)return!0}}else if(n.include_extensions.length>0)return!0;const c=i.dirname(e);for(const e of n.exclude_dirs)if(e.test(c))return!0;if(n.include_dirs.length>0){let e=!1;for(const o of n.include_dirs)if(o.test(c)){e=!0;break}if(!e)return!0}for(const e of n.exclude_names)if(e.test(r))return!0;if(n.include_names.length>0){let e=!1;for(const o of n.include_names)if(o.test(r)){e=!0;break}if(!e)return!0}if(o.no_hidden&&r.startsWith("."))return!0;try{const n=t.statSync(e).size;if(o.max_size){const e=x(o.max_size);if(!(e instanceof f)&&n>e)return!0}if(o.min_size){const e=x(o.min_size);if(!(e instanceof f)&&n<e)return!0}if(o.no_empty&&0===n)return!0}catch{}return!(!o.no_binary||!function(e){try{const o=Buffer.alloc(8192),n=t.openSync(e,"r"),i=t.readSync(n,o,0,8192,0);if(t.closeSync(n),0===i)return!1;for(let e=0;e<i;e++)if(0===o[e])return!0;return!1}catch{return!1}}(e))}function h(e){const o=Date.now(),n={total_files:0,total_lines:0,total_size:0,files_by_extension:{},lines_by_extension:{},size_by_extension:{},details:[]},s=function(e){try{const o=e.exclude_patterns.map(o=>{try{return new RegExp(o,e.ignore_case?"i":void 0)}catch(e){throw f.invalidRegex(o,e instanceof Error?e:void 0)}}),n=[...e.exclude_extensions.map(e=>e.replace(/^\./,"").toLowerCase()),...m.map(e=>e.toLowerCase())],t=Array.from(new Set(n)).sort(),i=e.include_extensions.map(e=>e.replace(/^\./,"").toLowerCase()),s=e.exclude_dirs.map(o=>new RegExp(o,e.ignore_case?"i":void 0)),r=e.include_dirs.map(o=>new RegExp(o,e.ignore_case?"i":void 0));return{exclude_patterns:o,exclude_extensions:t,include_extensions:i,exclude_dirs:s,include_dirs:r,exclude_names:e.exclude_names.map(o=>new RegExp(o,e.ignore_case?"i":void 0)),include_names:e.include_names.map(o=>new RegExp(o,e.ignore_case?"i":void 0))}}catch(e){return e instanceof f?e:f.io(`Failed to create filter patterns: ${e instanceof Error?e.message:String(e)}`)}}(e);if(d(s))return s;const c=function(e){const o=l();return o.add(".git"),o.add(".gitignore"),o.add(".lcignore"),function e(n,s){const r=i.join(n,".gitignore");try{if(t.existsSync(r)&&t.statSync(r).isFile()){const e=t.readFileSync(r,"utf-8"),l=i.relative(s,n)||".",c=e.split("\n").map(e=>e.trim()).filter(e=>e&&!e.startsWith("#"));for(const e of c)"."===l?o.add(e):o.add(i.join(l,e))}}catch{}try{const o=t.readdirSync(n);for(const r of o){const o=i.join(n,r);try{t.statSync(o).isDirectory()&&".git"!==r&&e(o,s)}catch{}}}catch{}}(e,e),o}(e.directory),a=i.join(e.directory,"**/*"),u={cwd:e.directory,absolute:!0,onlyFiles:!0,ignore:[],dot:!e.no_hidden,followSymbolicLinks:e.follow_links};let y=0,p=0;try{const o=r.sync(a,u).map(e=>"string"==typeof e?e:e.path||String(e));for(const r of o){if(void 0!==e.max_depth){const o=i.relative(e.directory,r);if(o.split(i.sep).length-1>e.max_depth)continue}const o=i.relative(e.directory,r);if(c.ignores(o))continue;try{if(!t.statSync(r).isFile())continue}catch{continue}if(b(r,e,s))continue;let l;y+=1,e.show_progress&&y%100==0&&!e.quiet&&process.stderr.write(`\rProcessed: ${y} files...`);try{l=t.statSync(r)}catch(o){e.quiet||console.error(`Warning: Could not read metadata for ${r}: ${o}`),p+=1;continue}const a=l.size,f=i.extname(r).replace(/^\./,"").toLowerCase()||"no-ext";n.total_files+=1,n.total_size+=a,n.files_by_extension[f]=(n.files_by_extension[f]||0)+1,n.size_by_extension[f]=(n.size_by_extension[f]||0)+a;let u=null;if(!e.files_only){const o=g(r,e.include_blank);d(o)?(e.quiet||console.error(`Warning: Could not count lines in ${r}: ${o.message}`),p+=1):(u=o,n.total_lines+=o,n.lines_by_extension[f]=(n.lines_by_extension[f]||0)+o)}const _=i.dirname(r),x=i.basename(r);n.details.push({directory:_,name:x,extension:f,size:a,lines:u})}}catch(e){return f.io(`Failed to scan directory: ${e instanceof Error?e.message:String(e)}`,e instanceof Error?e:void 0)}if(e.show_progress&&!e.quiet){const e=`${Date.now()-o}ms`;process.stderr.write(`\rProcessed: ${y} files (${p} errors) in ${e}\n`)}return n}function $(e){const o=function(e){if(e.version)return void console.log(`LocIO ${c}`);const o=i.resolve(e.directory);if(!t.existsSync(o))return f.directoryNotFound(e.directory);if(!t.statSync(o).isDirectory())return f.notADirectory(e.directory);const n=h({...e,directory:o});if(d(n))return n;_(n,{...e,directory:o})}(e);d(o)&&(console.error(`Error: ${o.message}`),process.exit(1)),process.exit(0)}(async function(){if(2===e.argv.length&&e.stdin.isTTY){if(!await new Promise((n,t)=>{const i=c;console.log("===================================="),console.log(` LocIO CLI v${i}`),console.log("===================================="),console.log("A fast, flexible line and file counter for your projects.\n"),console.log("Select an option:"),console.log(" 1) Quick scan of current directory (default settings)"),console.log(" 2) Show common command examples"),console.log(" 3) View full help (same as --help)"),console.log(" q) Quit\n"),e.nextTick(()=>{const i=o.createInterface({input:e.stdin,output:e.stdout}),s=()=>{i.question("Enter choice (1/2/3/q): ",e=>{switch(e.trim()){case"1":console.log('\nRunning quick scan on current directory (".") with default settings...\n'),i.close(),n(!0);break;case"2":console.log("\nCommon commands:"),console.log(" LocIO . --files-only"),console.log(" Scan current directory with default settings."),console.log(" LocIO . --files-only"),console.log(" Show only file counts."),console.log(" LocIO . --lines-only"),console.log(" Show only line counts."),console.log(' LocIO . --exclude "target" --exclude-dir ".git"'),console.log(" Ignore build and VCS directories."),console.log(" LocIO . --include-ext rs,ts,tsx"),console.log(" Only include specific extensions."),console.log(" LocIO . --export json"),console.log(" Print results in JSON format.\n"),i.close(),n(!1);break;case"3":console.log(),a().outputHelp(),console.log("\n"),i.close(),n(!1);break;case"q":case"Q":console.log("\nThank you for using LocIO."),i.close(),n(!1);break;default:console.log("Invalid choice. Please enter 1, 2, 3, or q.\n"),s()}})};i.on("error",e=>{console.error("\nFailed to read input. Exiting."),i.close(),t(e)}),s()})}))return}$(function(){const e=a();e.parse();const o=e.opts(),n=e.args,t=o.excludeExt?o.excludeExt.split(",").map(e=>e.trim()):[],i=o.includeExt?o.includeExt.split(",").map(e=>e.trim()):[];return{directory:n[0]||".",files_only:o.filesOnly||!1,lines_only:o.linesOnly||!1,exclude_patterns:o.exclude||[],exclude_extensions:t,include_extensions:i,exclude_dirs:o.excludeDir||[],include_dirs:o.includeDir||[],exclude_names:o.excludeName||[],include_names:o.includeName||[],max_size:o.maxSize,min_size:o.minSize,no_hidden:o.noHidden||!1,no_empty:o.noEmpty||!1,follow_links:o.followLinks||!1,max_depth:o.maxDepth,show_stats:o.stats||!1,show_progress:o.progress||!1,include_blank:o.includeBlank||!1,no_binary:o.noBinary||!1,ignore_case:o.ignoreCase||!1,quiet:o.quiet||!1,export:void 0!==o.export?!0===o.export?"human":"json"===o.export.toLowerCase()?"json":"csv"===o.export.toLowerCase()?"csv":"tsv"===o.export.toLowerCase()?"tsv":"human":void 0,version:!1}}())})().catch(o=>{console.error("Unexpected error:",o),e.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "locio",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "A powerful CLI tool to count lines and files in directories with extensive filtering options",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
5
7
|
"bin": {
|
|
6
|
-
"
|
|
7
|
-
"locio": "target/release/locio"
|
|
8
|
+
"locio": "./dist/index.js"
|
|
8
9
|
},
|
|
9
10
|
"scripts": {
|
|
10
|
-
"
|
|
11
|
-
"build": "
|
|
12
|
-
"
|
|
13
|
-
"version:check": "./scripts/version.sh",
|
|
14
|
-
"version:update": "./scripts/npm-version.sh",
|
|
15
|
-
"format": "npx prettier --write \"**/*.{js,json,ts,md}\""
|
|
11
|
+
"build": "rm -rf dist && tsup",
|
|
12
|
+
"build:watch": "tsup --watch",
|
|
13
|
+
"format": "prettier --write \"**/*.{js,json,ts,md}\""
|
|
16
14
|
},
|
|
17
15
|
"keywords": [
|
|
18
16
|
"cli",
|
|
19
|
-
"
|
|
17
|
+
"LocIO",
|
|
20
18
|
"file-counter",
|
|
21
19
|
"statistics",
|
|
22
20
|
"code-analysis",
|
|
@@ -26,12 +24,26 @@
|
|
|
26
24
|
"author": "Toufiq Hasan Kiron <hello@kiron.dev>",
|
|
27
25
|
"license": "MIT",
|
|
28
26
|
"files": [
|
|
29
|
-
"
|
|
30
|
-
"
|
|
27
|
+
"dist",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
31
30
|
],
|
|
32
31
|
"repository": {
|
|
33
32
|
"type": "git",
|
|
34
33
|
"url": "https://github.com/kiron0/locio.git"
|
|
35
34
|
},
|
|
36
|
-
"homepage": "https://
|
|
35
|
+
"homepage": "https://locio.js.org",
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"commander": "^14.0.2",
|
|
38
|
+
"chalk": "^5.6.2",
|
|
39
|
+
"ignore": "^7.0.5",
|
|
40
|
+
"fast-glob": "^3.3.3"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^25.0.3",
|
|
44
|
+
"prettier": "^3.7.4",
|
|
45
|
+
"terser": "^5.44.1",
|
|
46
|
+
"tsup": "^8.5.1",
|
|
47
|
+
"typescript": "^5.9.3"
|
|
48
|
+
}
|
|
37
49
|
}
|
package/target/release/locio
DELETED
|
Binary file
|