locio 0.1.3 β 1.0.1
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 +28 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -10,7 +10,13 @@
|
|
|
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
|
-
- **
|
|
13
|
+
- **Comment analysis** - count comment lines separately (full-line and inline)
|
|
14
|
+
- **Remove comments** - automatically remove comments from code files
|
|
15
|
+
- **Project type detection** - automatically detects project type (Node.js, Rust, Python, etc.)
|
|
16
|
+
- **Auto-excludes** - automatically applies common excludes based on detected project type
|
|
17
|
+
- **Export reports** - save results in multiple formats: `txt`, `json`, `csv`, `tsv`, `markdown`, `html`
|
|
18
|
+
- **Watch mode** - automatically rescan on file changes
|
|
19
|
+
- **Top files/dirs** - show largest files and directories with most files
|
|
14
20
|
- **Fast and efficient** - built with TypeScript
|
|
15
21
|
- **Rich statistics** - detailed breakdown by file extension and directory
|
|
16
22
|
|
|
@@ -75,6 +81,15 @@ locio --include-ext rs,ts,js --stats
|
|
|
75
81
|
|
|
76
82
|
# Export report in JSON format
|
|
77
83
|
locio --stats --export json
|
|
84
|
+
|
|
85
|
+
# Count comments separately
|
|
86
|
+
locio --comments --stats
|
|
87
|
+
|
|
88
|
+
# Remove comments from TypeScript files
|
|
89
|
+
locio --rm-comments ts
|
|
90
|
+
|
|
91
|
+
# Watch directory for changes
|
|
92
|
+
locio --watch
|
|
78
93
|
```
|
|
79
94
|
|
|
80
95
|
## Quick Example
|
|
@@ -91,6 +106,18 @@ locio --max-size 5MB --no-binary --stats
|
|
|
91
106
|
|
|
92
107
|
# Export JSON report (writes to LocIO-report.json)
|
|
93
108
|
locio --stats --export json
|
|
109
|
+
|
|
110
|
+
# Count comments and show code vs comments ratio
|
|
111
|
+
locio --code-vs-comments --stats
|
|
112
|
+
|
|
113
|
+
# Remove comments from JavaScript and TypeScript files
|
|
114
|
+
locio --rm-comments js,ts
|
|
115
|
+
|
|
116
|
+
# Show top 10 largest files
|
|
117
|
+
locio --stats --top-files 10
|
|
118
|
+
|
|
119
|
+
# Watch mode with statistics
|
|
120
|
+
locio --watch
|
|
94
121
|
```
|
|
95
122
|
|
|
96
123
|
---
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
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)});
|
|
2
|
+
"use strict";var e=require("process"),n=require("readline"),t=require("commander"),o=require("fs"),s=require("path"),i=require("url"),l=require("chalk"),r=require("fast-glob"),c=require("ignore"),a="undefined"!=typeof document?document.currentScript:null;function d(e){return e&&e.__esModule?e:{default:e}}function u(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 m=u(e),f=u(n),p=u(o),_=u(s),y=d(l),h=d(r),g=d(c),x=Object.defineProperty,b=(e,n,t)=>((e,n,t)=>n in e?x(e,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[n]=t)(e,"symbol"!=typeof n?n+"":n,t),$=i.fileURLToPath("undefined"==typeof document?require("url").pathToFileURL(__filename).href:a&&"SCRIPT"===a.tagName.toUpperCase()&&a.src||new URL("index.cjs",document.baseURI).href),v=s.dirname($);function k(){try{const e=[s.join(v,"../package.json"),s.join(v,"../../package.json"),s.join(process.cwd(),"package.json")];for(const n of e)try{const e=JSON.parse(o.readFileSync(n,"utf-8"));if(e.version)return e.version}catch{continue}return"0.0.0"}catch(e){return"0.0.0"}}var L=class e extends Error{constructor(e,n,t){super(e),this.cause=n,b(this,"suggestion"),this.name="LineCounterError",this.suggestion=t}static io(n,t){return new e(`IO error: ${n}`,t,"Check if the file/directory exists, you have read permissions, and there's sufficient disk space.")}static invalidSizeFormat(n){return new e(`Invalid size format: ${n}`,void 0,"Size format should be a number followed by a unit (e.g., '5MB', '1KB', '500B').\nValid units: B, KB, MB, GB, TB (case-insensitive).")}static invalidRegex(n,t){return new e(`Invalid regex pattern: ${n}${t?`: ${t.message}`:""}`,t,"Check your regex pattern syntax. Common issues:\n - Escape special characters with backslash (\\* for literal *)\n - Use proper grouping syntax (parentheses, brackets)\n - Verify quantifiers are properly placed\n - Test your pattern at https://regex101.com")}static directoryNotFound(n){let t;try{t=_.resolve(n)}catch{t=n}return new e(`Directory not found: ${n}`,void 0,`The path "${n}" does not exist.\n - Check if the path is correct (resolved: ${t})\n - Use relative paths like '.' for current directory\n - Verify you have read permissions\n - Check if it's a file instead of a directory (use the file path directly)`)}static notADirectory(n){return new e(`Not a directory: ${n}`,void 0,`"${n}" exists but is not a directory.\n - If it's a file, you can scan it directly: locio <file-path>\n - If you meant a directory, check the path spelling\n - Use 'locio .' to scan the current directory`)}static fileNotFound(n){return new e(`File not found: ${n}`,void 0,`The file "${n}" does not exist.\n - Check if the file path is correct\n - Verify the file extension\n - Ensure you have read permissions`)}static exportPathError(n,t){return new e(`Export path error: ${n}`,void 0,`Cannot write to export path "${n}": ${t}\n - Ensure the directory exists or can be created\n - Check write permissions\n - Verify there's sufficient disk space\n - Use an absolute path if relative paths aren't working`)}};function w(e){return e instanceof L}function C(e,n){return n&&Array.isArray(n)?[...n,e]:[e]}function j(e){return e.split(",").map(e=>e.trim()).filter(Boolean)}function S(e){if(void 0===e)return;if(!0===e)return"human";const n={json:"json",csv:"csv",tsv:"tsv",markdown:"markdown",md:"markdown",html:"html",human:"human",txt:"human"},t=j(e).map(e=>n[e.toLowerCase()]).filter(e=>void 0!==e);return t.length>0?1===t.length?t[0]:t:void 0}function z(e){const n=_.resolve(e);if(!p.existsSync(n))return{path:null,error:L.directoryNotFound(e)};const t=p.statSync(n);return t.isDirectory()||t.isFile()?{path:n,error:null}:{path:null,error:L.notADirectory(e)}}function E(e,n){const t=e.length>n.length?e:n;if(0===t.length)return 1;const o=function(e,n){const t=[];for(let e=0;e<=n.length;e++)t[e]=[e];for(let n=0;n<=e.length;n++)t[0][n]=n;for(let o=1;o<=n.length;o++)for(let s=1;s<=e.length;s++)n.charAt(o-1)===e.charAt(s-1)?t[o][s]=t[o-1][s-1]:t[o][s]=Math.min(t[o-1][s-1]+1,t[o][s-1]+1,t[o-1][s]+1);return t[n.length][e.length]}(e,n);return(t.length-o)/t.length}function F(){const e=new t.Command,n=["files-only","lines-only","exclude","exclude-ext","include-ext","exclude-dir","include-dir","exclude-name","include-name","max-size","min-size","no-hidden","no-empty","follow-links","max-depth","stats","no-progress","no-binary","ignore-case","quiet","export","export-path","watch","no-comments","code-vs-comments","rm-comments","top-files","top-dirs","version"];return e.configureOutput({writeErr:e=>{if(e.includes("unknown option")){const t=e.match(/unknown option ['"]--?([^'"]+)['"]/);if(t){const e=t[1],o=function(e,n,t=3){return n.map(n=>({option:n,score:E(e,n)})).sort((e,n)=>n.score-e.score).filter(e=>e.score>.3).slice(0,t).map(e=>e.option)}(e,n);if(o.length>0){const n=1===o.length?"Did you mean this?":"Did you mean one of these?";process.stderr.write(`\nβ Unknown option: '--${e}'\n\nπ‘ ${n}\n`+o.map(e=>` β’ --${e}`).join("\n")+"\n\nRun 'locio --help' to see all available options.\n\n"),process.exit(1)}process.stderr.write(`\nβ Unknown option: '--${e}'\n\nπ‘ This option doesn't exist. Run 'locio --help' to see all available options.\n\n`),process.exit(1)}}process.stderr.write(e)}}),e.name("LocIO").description("A powerful CLI tool to count lines and files in directories").version(k(),"-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",C).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",C).option("--include-dir <pattern>","Include only directories matching pattern",C).option("--exclude-name <pattern>","Exclude files by name pattern",C).option("--include-name <pattern>","Include only files by name pattern",C).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("--no-progress","Disable progress indicator (enabled by default)").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, markdown, html). Multiple formats can be specified comma-separated (e.g., json,html,markdown)").option("--export-path <dir>","Specify output directory for exported reports. Files will use default naming (LocIO-report.{ext}). Directories will be created automatically if they don't exist").option("-w, --watch","Watch directory for changes and auto-rescan").option("--no-comments","Disable comment counting (enabled by default)").option("--code-vs-comments","Show code vs comments ratio (automatically enables --comments)").option("--rm-comments [extensions]","Remove comments from files (modifies files in place). Optionally specify file extensions (comma-separated, e.g., js,ts,py). If no extensions specified, all files are processed.").option("--top-files <n>","Show top N largest files by size",parseInt).option("--top-dirs <n>","Show top N directories with most files",parseInt),e}var D=[{type:"nextjs",files:["next.config.js","next.config.ts","next.config.mjs","next.config.cjs"],packageJsonDeps:["next"],packageJsonDevDeps:["next"],priority:100},{type:"angular",files:["angular.json","angular-cli.json"],packageJsonDeps:["@angular/core"],packageJsonDevDeps:["@angular/cli","@angular/core"],priority:90},{type:"vue",files:["vue.config.js","vue.config.ts","vite.config.js","vite.config.ts"],packageJsonDeps:["vue"],packageJsonDevDeps:["vue","@vitejs/plugin-vue","vite"],dirs:[".nuxt"],priority:85},{type:"react",files:["react-scripts"],packageJsonDeps:["react"],packageJsonDevDeps:["react","react-scripts","@vitejs/plugin-react","vite"],dirs:["node_modules/react"],priority:80},{type:"typescript",files:["tsconfig.json","tsconfig.app.json","tsconfig.base.json"],priority:70},{type:"nodejs",files:["package.json"],priority:75},{type:"rust",files:["Cargo.toml","Cargo.lock"],priority:100},{type:"python",files:["requirements.txt","setup.py","pyproject.toml","Pipfile","poetry.lock","manage.py","setup.cfg","Pipfile.lock"],dirs:["__pycache__"],priority:100},{type:"go",files:["go.mod","go.sum","Gopkg.toml","Gopkg.lock"],priority:100},{type:"java",files:["pom.xml","build.gradle","build.gradle.kts","settings.gradle"],dirs:[".gradle"],priority:100},{type:"csharp",files:["*.csproj","*.sln","project.json","*.fsproj","*.vbproj"],dirs:[".vs"],priority:100},{type:"ruby",files:["Gemfile","Rakefile","Gemfile.lock"],dirs:[".bundle"],priority:100},{type:"php",files:["composer.json","composer.lock","artisan"],dirs:["vendor"],priority:100},{type:"swift",files:["Package.swift","*.xcodeproj","*.xcworkspace"],dirs:[".build"],priority:100},{type:"kotlin",files:["build.gradle.kts","settings.gradle.kts"],dirs:[".gradle"],priority:100},{type:"dart",files:["pubspec.yaml","pubspec.yml","pubspec.lock"],dirs:[".dart_tool"],priority:100}],T={nodejs:{exclude_dirs:["node_modules",".next",".nuxt",".cache","dist","build",".turbo",".vercel",".output"],exclude_extensions:[],exclude_names:["package-lock.json","yarn.lock","pnpm-lock.yaml"]},nextjs:{exclude_dirs:["node_modules",".next",".vercel","out","dist","build",".turbo"],exclude_extensions:[],exclude_names:["package-lock.json","yarn.lock","pnpm-lock.yaml"]},react:{exclude_dirs:["node_modules","build","dist",".cache","coverage",".nyc_output"],exclude_extensions:[],exclude_names:["package-lock.json","yarn.lock","pnpm-lock.yaml"]},vue:{exclude_dirs:["node_modules","dist",".nuxt",".cache","coverage",".output"],exclude_extensions:[],exclude_names:["package-lock.json","yarn.lock","pnpm-lock.yaml"]},angular:{exclude_dirs:["node_modules","dist",".angular","coverage",".nyc_output"],exclude_extensions:[],exclude_names:["package-lock.json","yarn.lock","pnpm-lock.yaml"]},typescript:{exclude_dirs:["node_modules","dist","build",".cache","coverage",".nyc_output"],exclude_extensions:[],exclude_names:["package-lock.json","yarn.lock","pnpm-lock.yaml"]},rust:{exclude_dirs:["target",".cargo"],exclude_extensions:[],exclude_names:["Cargo.lock"]},python:{exclude_dirs:["__pycache__",".pytest_cache",".mypy_cache",".ruff_cache",".venv","venv","env",".env","build","dist",".*\\.egg-info",".tox",".coverage","htmlcov",".hypothesis"],exclude_extensions:["pyc","pyo","pyd","so"],exclude_names:[".python-version","pip-log.txt","pip-delete-this-directory.txt"]},go:{exclude_dirs:["vendor",".cache"],exclude_extensions:[],exclude_names:["go.sum"]},java:{exclude_dirs:["target","build",".gradle","out",".idea",".classpath",".settings"],exclude_extensions:["class","jar","war","ear"],exclude_names:[".project",".*\\.iml"]},csharp:{exclude_dirs:["bin","obj",".vs","packages","TestResults","[Bb]in","[Oo]bj"],exclude_extensions:["dll","exe","pdb"],exclude_names:[]},ruby:{exclude_dirs:["vendor",".bundle","tmp","log"],exclude_extensions:[],exclude_names:["Gemfile.lock"]},php:{exclude_dirs:["vendor","node_modules"],exclude_extensions:[],exclude_names:["composer.lock"]},swift:{exclude_dirs:[".build",".swiftpm","DerivedData"],exclude_extensions:[],exclude_names:["Package.resolved"]},kotlin:{exclude_dirs:["build",".gradle","out",".idea",".classpath",".settings"],exclude_extensions:["class","jar"],exclude_names:[".project",".*\\.iml"]},dart:{exclude_dirs:[".dart_tool","build"],exclude_extensions:[],exclude_names:["pubspec.lock"]},unknown:{exclude_dirs:[],exclude_extensions:[],exclude_names:[]}};function O(e,n,t){if(!e||!n&&!t)return!1;const o={...e.dependencies||{},...e.devDependencies||{}};if(n)for(const e of n)if(o[e])return!0;if(t)for(const e of t)if(o[e])return!0;return!1}function M(e,n){if(!e||!n||!e.scripts)return!1;for(const t of n)if(e.scripts[t])return!0;return!1}function q(e,n){if(n.includes("*"))try{const t=p.readdirSync(e),o=n.replace(/\*/g,".*"),s=new RegExp(`^${o}$`);return t.some(n=>{const t=_.join(e,n);try{const e=p.statSync(t);return(e.isFile()||e.isDirectory())&&s.test(n)}catch{return!1}})}catch{return!1}else{const t=_.join(e,n);try{if(p.existsSync(t)){return p.statSync(t).isFile()}}catch{}}return!1}function R(e,n){const t=_.join(e,n);try{if(p.existsSync(t)){return p.statSync(t).isDirectory()}}catch{}return!1}function I(e,n=2){try{const t=p.readdirSync(e);for(const o of t){const t=_.join(e,o);try{const e=p.statSync(t);if(e.isFile()&&(o.endsWith(".ts")||o.endsWith(".tsx")))return!0;if(e.isDirectory()&&n>0&&!o.startsWith(".")&&"node_modules"!==o&&I(t,n-1))return!0}catch{}}}catch{}return!1}function B(e){const n=_.resolve(e);let t=n;try{p.statSync(n).isFile()&&(t=_.dirname(n))}catch{}const o=new Map,s=function(e){const n=_.join(e,"package.json");try{if(p.existsSync(n)){const e=p.readFileSync(n,"utf-8");return JSON.parse(e)}}catch{}return null}(t);for(const e of D){let n=0;const i=[];for(const o of e.files)q(t,o)&&(n+=30,i.push(`file:${o}`));if(e.dirs)for(const o of e.dirs)R(t,o)&&(n+=20,i.push(`dir:${o}`));if((e.packageJsonDeps||e.packageJsonDevDeps)&&O(s,e.packageJsonDeps,e.packageJsonDevDeps)){n+=50;const t=[...e.packageJsonDeps||[],...e.packageJsonDevDeps||[]];i.push(`dep:${t.join(",")}`)}if(e.packageJsonScripts&&M(s,e.packageJsonScripts)&&(n+=15,i.push(`script:${e.packageJsonScripts.join(",")}`)),"typescript"===e.type&&(q(t,"tsconfig.json")&&(n+=30,i.push("file:tsconfig.json")),I(t)&&(n+=20,i.push("typescript-files")),s&&q(t,"package.json"))){O(s,["express","koa","fastify","nest","@nestjs/core"],["ts-node","ts-node-dev"])&&(n=Math.floor(.5*n),i.push("nodejs-backend-penalty"))}if("nodejs"===e.type&&q(t,"package.json")&&(q(t,"tsconfig.json")||I(t))&&(n+=40,i.push("nodejs-with-typescript")),"react"===e.type)try{const e=p.readdirSync(t);e.some(e=>{const n=_.join(t,e);try{return p.statSync(n).isFile()&&(e.endsWith(".jsx")||e.endsWith(".tsx"))}catch{return!1}})&&(n+=15,i.push("jsx-files"))}catch{}n=Math.floor(n*(1+e.priority/100)),n>0&&o.set(e.type,{type:e.type,score:n,indicators:i})}if(s){if(!Array.from(o.keys()).some(e=>"react"===e||"vue"===e||"angular"===e||"nextjs"===e)){const e=q(t,"tsconfig.json")||I(t);if(e&&q(t,"package.json")){O(s,["express","koa","fastify","nest","@nestjs/core"],["ts-node","ts-node-dev"])&&(o.has("nodejs")||o.set("nodejs",{type:"nodejs",score:55,indicators:["package.json","nodejs-backend-with-typescript"]})),o.has("typescript")||o.set("typescript",{type:"typescript",score:40,indicators:["tsconfig-or-ts-files"]})}else e?o.has("typescript")||o.set("typescript",{type:"typescript",score:40,indicators:["tsconfig-or-ts-files"]}):o.has("nodejs")||o.set("nodejs",{type:"nodejs",score:30,indicators:["package.json"]})}}return Array.from(o.values()).sort((e,n)=>n.score-e.score)}function W(e){const n=B(e);return 0===n.length?"unknown":n[0].type}function A(e){const n=[];let t="",o="",s=!1;switch(e.toLowerCase().replace(/^\./,"")){case"js":case"jsx":case"ts":case"tsx":case"c":case"cpp":case"cc":case"cxx":case"h":case"hpp":case"java":case"cs":case"php":case"swift":case"go":case"rust":case"rs":case"dart":case"kt":case"scala":case"sc":n.push("//"),t="/*",o="*/",s=!0;break;case"sh":case"bash":case"zsh":case"fish":case"py":case"python":case"rb":case"ruby":case"r":case"pl":case"perl":case"yaml":case"yml":case"toml":case"conf":case"ini":case"cfg":case"dockerfile":case"makefile":case"make":case"cmake":case"ps1":case"psm1":case"ex":case"exs":n.push("#");break;case"html":case"htm":case"xml":case"xhtml":case"svg":n.push("\x3c!--"),t="\x3c!--",o="--\x3e",s=!0;break;case"css":case"scss":case"sass":case"less":case"styl":t="/*",o="*/",s=!0;break;case"sql":n.push("--"),t="/*",o="*/",s=!0;break;case"lua":n.push("--"),t="--[[",o="]]",s=!0;break;case"pas":case"p":case"pp":case"fs":case"fsi":case"fsx":n.push("//"),t="(*",o="*)",s=!0;break;case"hs":case"lhs":n.push("--"),t="{-",o="-}",s=!0;break;case"erl":case"hrl":case"m":case"matlab":n.push("%");break;case"vhd":case"vhdl":n.push("--");break;case"bat":case"cmd":n.push("::");break;case"vbs":n.push("'");break;case"clj":case"cljs":case"cljc":case"lisp":case"lsp":case"el":case"rkt":case"rktl":n.push(";");break;case"ml":case"mli":t="(*",o="*)",s=!0;break;default:n.push("//","#","--")}return{singleLine:n,multiLineStart:t,multiLineEnd:o,supportsMultiLine:s}}function P(e,n,t){let o=0,s=!1,i=0,l=-1;const r=[];let c=-1,a=-1;for(;i<e.length;){const d=e[i];if(s)s=!1,i++;else if("\\"!==d||0===o){if(3===o&&"$"===d&&i+1<e.length&&"{"===e[i+1]){let n=1;for(i+=2;i<e.length&&n>0;)"{"===e[i]?n++:"}"===e[i]&&n--,i++;continue}if(0===o){if('"'===d)o=2;else if("'"===d)o=1;else if("`"===d)o=3;else if("/"===d&&i+1<e.length){const t=e[i+1];if("/"===t||"*"===t){for(const t of n.singleLine)if(e.substring(i).startsWith(t)){r.push({pos:i,marker:t});break}n.supportsMultiLine&&-1===c&&e.substring(i).startsWith(n.multiLineStart)&&(c=i),i++;continue}{const n=i>0?e[i-1]:" ";/[\s,;=([{!&|?:]/.test(n)&&(o=4,l=i)}}}else if(2===o&&'"'===d)o=0;else if(1===o&&"'"===d)o=0;else if(3===o&&"`"===d)o=0;else if(4===o){if("\\"===d){i+1<e.length?i+=2:i++;continue}if("/"===d)if(i+1<e.length){const n=e[i+1];if(/[gimsuvy]/.test(n)){let n=i+1;for(;n<e.length&&/[gimsuvy]/.test(e[n]);)n++;(n>=e.length||!/[a-zA-Z0-9_]/.test(e[n]))&&(o=0,l=-1,i=n-1)}else/[a-zA-Z0-9_]/.test(n)||(o=0,l=-1)}else o=0,l=-1;else if(" "===d||"\t"===d){const n=i-l-1;let t=!0;for(let n=l+1;n<i;n++)if(" "!==e[n]&&"\t"!==e[n]){t=!1;break}if(t&&n<=2){let n=i+1;for(;n<e.length&&(" "===e[n]||"\t"===e[n]);)n++;n<e.length&&/[0-9;,)}\]\]]/.test(e[n])&&(o=0,l=-1)}}else/[;,)}\]\]]/.test(d)&&(o=0,l=-1)}if(0===o){for(const t of n.singleLine)if(e.substring(i).startsWith(t)){r.push({pos:i,marker:t});break}if(n.supportsMultiLine&&-1===c&&e.substring(i).startsWith(n.multiLineStart)&&(c=i),n.supportsMultiLine&&t&&e.substring(i).startsWith(n.multiLineEnd)){a=i;break}}i++}else s=!0,i++}if(t){if(-1!==a){const t=e.substring(0,a).trim(),o=e.substring(a+n.multiLineEnd.length).trim();return{commentStart:0,commentEnd:a+n.multiLineEnd.length,isMultiLine:!0,endsMultiLine:!0,commentMarker:n.multiLineEnd,hasCodeBefore:t.length>0,hasCodeAfter:o.length>0}}return{commentStart:0,commentEnd:e.length,isMultiLine:!0,endsMultiLine:!1,commentMarker:n.multiLineEnd,hasCodeBefore:!1,hasCodeAfter:!1}}if(n.supportsMultiLine&&-1!==c){const t=e.substring(0,c).trim(),o=e.indexOf(n.multiLineEnd,c),s=-1!==o,i=s?e.substring(o+n.multiLineEnd.length).trim():"";return{commentStart:c,commentEnd:s?o+n.multiLineEnd.length:e.length,isMultiLine:!0,endsMultiLine:s,commentMarker:n.multiLineStart,hasCodeBefore:t.length>0,hasCodeAfter:i.length>0}}if(r.length>0){const n=r[0],t=e.substring(0,n.pos).trim();return{commentStart:n.pos,commentEnd:e.length,isMultiLine:!1,endsMultiLine:!1,commentMarker:n.marker,hasCodeBefore:t.length>0,hasCodeAfter:!1}}return null}function N(e){try{const n=p.readFileSync(e,"utf-8"),t=n.split(/\r?\n/),o=A(_.extname(e));let s=!1;const i=[];let l=!1;for(const e of t){const n=e,t=U(e,o,s);t.line!==n&&(l=!0),!t.line.trim()&&t.isEmpty||i.push(t.line),s=t.inMultiLineComment}const r=i.join("\n");return l||r!==n?(p.writeFileSync(e,r,"utf-8"),{success:!0,commentsFound:!0}):{success:!0,commentsFound:!1}}catch{return{success:!1,commentsFound:!1}}}function J(e){const n=e.replace(/^\/\//,"").replace(/^\/\*/,"").replace(/\*\/$/,"").trim().toLowerCase();return n.startsWith("eslint")||n.startsWith("@eslint")||n.includes("eslint-disable")||n.includes("eslint-enable")}function U(e,n,t){if(t){const t=e.indexOf(n.multiLineEnd);if(-1!==t){const o=e.substring(0,t+n.multiLineEnd.length),s=e.substring(t+n.multiLineEnd.length);return J(o)?{line:e.trimEnd(),inMultiLineComment:!1,isEmpty:0===e.trim().length}:{line:s.trimEnd(),inMultiLineComment:!1,isEmpty:0===s.trim().length}}return J(e)?{line:e.trimEnd(),inMultiLineComment:!0,isEmpty:0===e.trim().length}:{line:"",inMultiLineComment:!0,isEmpty:!0}}let o=0,s=!1,i=0,l=-1;const r=[];let c=-1;for(;i<e.length;){const t=e[i];if(s)s=!1,i++;else if("\\"!==t||0===o){if(3===o&&"$"===t&&i+1<e.length&&"{"===e[i+1]){let n=1;for(i+=2;i<e.length&&n>0;)"{"===e[i]?n++:"}"===e[i]&&n--,i++;continue}if(0===o){if('"'===t)o=2;else if("'"===t)o=1;else if("`"===t)o=3;else if("/"===t&&i+1<e.length){const t=e[i+1];if("/"===t||"*"===t){for(const t of n.singleLine)if(e.substring(i).startsWith(t)){r.push(i);break}n.supportsMultiLine&&-1===c&&e.substring(i).startsWith(n.multiLineStart)&&(c=i),i++;continue}{const n=i>0?e[i-1]:" ";/[\s,;=([{!&|?:]/.test(n)&&(o=4,l=i)}}}else if(2===o&&'"'===t)o=0;else if(1===o&&"'"===t)o=0;else if(3===o&&"`"===t)o=0;else if(4===o){if("\\"===t){i+1<e.length?i+=2:i++;continue}if("/"===t)if(i+1<e.length){const n=e[i+1];if(/[gimsuvy]/.test(n)){let n=i+1;for(;n<e.length&&/[gimsuvy]/.test(e[n]);)n++;(n>=e.length||!/[a-zA-Z0-9_]/.test(e[n]))&&(o=0,l=-1,i=n-1)}else/[a-zA-Z0-9_]/.test(n)||(o=0,l=-1)}else o=0,l=-1;else if(" "===t||"\t"===t){const n=i-l-1;let t=!0;for(let n=l+1;n<i;n++)if(" "!==e[n]&&"\t"!==e[n]){t=!1;break}if(t&&n<=2){let n=i+1;for(;n<e.length&&(" "===e[n]||"\t"===e[n]);)n++;n<e.length&&/[0-9;,)}\]\]]/.test(e[n])&&(o=0,l=-1)}}else/[;,)}\]\]]/.test(t)&&(o=0,l=-1)}if(0===o){for(const t of n.singleLine)if(e.substring(i).startsWith(t)){r.push(i);break}n.supportsMultiLine&&-1===c&&e.substring(i).startsWith(n.multiLineStart)&&(c=i)}i++}else s=!0,i++}if(-1!==c){const t=e.substring(0,c),o=e.indexOf(n.multiLineEnd,c+n.multiLineStart.length);if(-1!==o){const s=e.substring(c,o+n.multiLineEnd.length),i=e.substring(o+n.multiLineEnd.length);if(J(s))return{line:e.trimEnd(),inMultiLineComment:!1,isEmpty:0===e.trim().length};const l=(t+i).trimEnd();return{line:l,inMultiLineComment:!1,isEmpty:0===l.length}}{if(J(e.substring(c)))return{line:e.trimEnd(),inMultiLineComment:!0,isEmpty:0===e.trim().length};const n=t.trimEnd();return{line:n,inMultiLineComment:!0,isEmpty:0===n.length}}}if(r.length>0){const t=r[0];for(const o of n.singleLine)if(e.substring(t).startsWith(o)){if(J(e.substring(t+o.length)))return{line:e.trimEnd(),inMultiLineComment:!1,isEmpty:0===e.trim().length};break}const o=e.substring(0,t).trimEnd();return{line:o,inMultiLineComment:!1,isEmpty:0===o.length}}return{line:e,inMultiLineComment:!1,isEmpty:!1}}function G(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 V(e){return{codeLines:e.code_lines||0,commentLines:e.comment_lines||0,fullLineComments:e.full_line_comments||0,inlineComments:e.inline_comments||0}}function K(e,n,t,o,s){let i=` (${e} code, ${n} comments`;return void 0!==s&&s>0&&(i+=`, ${s} blank`),(t>0||o>0)&&(i+=`: ${t} full-line, ${o} inline`),i+=")",i}function H(e,n,t,o,s){let i=` ${y.default.gray(`(${y.default.blue(e)} code, ${y.default.cyan(n)} comments`)}`;return void 0!==s&&s>0&&(i+=y.default.gray(`, ${y.default.gray(s)} blank`)),(t>0||o>0)&&(i+=y.default.gray(`: ${y.default.yellow(t)} full-line, ${y.default.magenta(o)} inline`)),i+=y.default.gray(")"),i}function Q(e,n){return(e.comments||e.show_stats)&&!e.files_only&&n}function Y(e,n,t){return{sizeStr:G(e),linesStr:null===n||t.files_only?"":` | ${n} lines`}}function Z(e){const n={};for(const t of e)n[t.directory]||(n[t.directory]=[]),n[t.directory].push(t);return n}function X(e){try{return p.statSync(e.directory).isFile()}catch{return!1}}function ee(e){const n=e.directory;try{if(p.statSync(n).isFile())return _.basename(n)}catch{}return"."===n?"current":n}function ne(e){return{nodejs:"Node.js",rust:"Rust",python:"Python",go:"Go",java:"Java",csharp:"C#",ruby:"Ruby",php:"PHP",swift:"Swift",kotlin:"Kotlin",dart:"Dart",typescript:"TypeScript",vue:"Vue.js",react:"React",angular:"Angular",nextjs:"Next.js",unknown:"Unknown"}[e]||e}function te(e,n){return[...e.details].sort((e,n)=>n.size-e.size).slice(0,n)}function oe(e,n){const t={};for(const n of e.details)t[n.directory]||(t[n.directory]={fileCount:0,totalSize:0,totalLines:0}),t[n.directory].fileCount+=1,t[n.directory].totalSize+=n.size,null!==n.lines&&(t[n.directory].totalLines+=n.lines);return Object.entries(t).map(([e,n])=>({directory:e,...n})).sort((e,n)=>n.fileCount-e.fileCount).slice(0,n)}function se(e,n,t){switch(e){case"human":return 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".padStart(37).padEnd(60)+"\n",t+="=".repeat(60)+"\n\n",t+=`Directory: ${ee(n)}\n`,n.lines_only||(X(n)?t+=`\nSize: ${G(e.total_size)}\n`:(t+=`\nTotal Files: ${e.total_files}\n`,t+=`\nTotal Files Size: ${G(e.total_size)}\n`)),!n.files_only&&(t+=`\nTotal Lines: ${e.total_lines}\n`,(n.comments||n.show_stats)&&void 0!==e.total_comment_lines&&(t+=`Total Comment Lines: ${e.total_comment_lines}\n`,void 0!==e.total_full_line_comments&&(t+=` - Full Line Comments: ${e.total_full_line_comments}\n`),void 0!==e.total_inline_comments&&(t+=` - Inline Comments: ${e.total_inline_comments}\n`),void 0!==e.total_code_lines&&(t+=`Total Code Lines: ${e.total_code_lines}\n`),void 0!==e.total_blank_lines&&e.total_blank_lines>0&&(t+=`Total Blank Lines: ${e.total_blank_lines}\n`),n.code_vs_comments&&void 0!==e.total_code_lines))&&(t+=`Code vs Comments Ratio: ${e.total_code_lines>0?(e.total_comment_lines/e.total_code_lines).toFixed(2):"0.00"}:1 (${e.total_comment_lines} comments per ${e.total_code_lines} code 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 s of o){const o=e.files_by_extension[s],i=e.size_by_extension[s]||0,l=e.lines_by_extension[s]||0;if(t+=` ${s}: ${o} files`,n.lines_only||(t+=`, ${G(i)}`),!n.files_only&&(t+=`, ${l} lines`,Q(n,void 0!==e.comment_lines_by_extension?.[s]))){const o=V({comment_lines:e.comment_lines_by_extension?.[s]||0,code_lines:e.code_lines_by_extension?.[s]||0,full_line_comments:e.full_line_comments_by_extension?.[s]||0,inline_comments:e.inline_comments_by_extension?.[s]||0}),i=e.blank_lines_by_extension?.[s]||0;t+=K(o.codeLines,o.commentLines,o.fullLineComments,o.inlineComments,i),n.code_vs_comments&&o.codeLines>0&&(t+=` [${(o.commentLines/o.codeLines).toFixed(2)}:1]`)}t+="\n"}}if(n.show_stats&&e.details.length>0){t+="\nFiles by Directory:\n",t+="-".repeat(60)+"\n";const o=Z(e.details),s=Object.keys(o).sort();for(const e of s){const s=o[e];t+=`Directory: ${e}\n`;for(const e of s){const o=G(e.size),s=null===e.lines||n.files_only?"":` | ${e.lines} lines`;let i="";if(Q(n,void 0!==e.comment_lines&&null!==e.comment_lines)){const n=V(e);i=K(n.codeLines,n.commentLines,n.fullLineComments,n.inlineComments,e.blank_lines||void 0)}t+=` - ${e.name} (${e.extension}, ${o}${s}${i})\n`}t+="\n"}}if(n.top_files&&n.top_files>0){const o=te(e,n.top_files);t+=`\nTop ${n.top_files} Largest Files:\n`,t+="-".repeat(60)+"\n";for(const e of o){const{sizeStr:o,linesStr:s}=Y(e.size,e.lines,n);t+=` ${o.padEnd(10)} ${e.name} (${e.extension})${s}\n`}}if(n.top_dirs&&n.top_dirs>0){const o=oe(e,n.top_dirs);t+=`\nTop ${n.top_dirs} Directories (by file count):\n`,t+="-".repeat(60)+"\n";for(const e of o){const o=G(e.totalSize),s=n.files_only?"":` | ${e.totalLines} lines`;t+=` ${e.fileCount.toString().padEnd(5)} files ${e.directory} (${o}${s})\n`}}return t+="\n",t}(n,t);case"json":return function(e,n){const t=W(n.directory),o={directory:ee(n)};if("unknown"!==t&&(o.project_type=t,o.project_type_display=ne(t)),X(n)||(o.files=e.total_files,o.size=e.total_size,o.size_formatted=G(e.total_size)),n.files_only||(o.lines=e.total_lines,n.comments&&(o.comment_lines=e.total_comment_lines||0,o.code_lines=e.total_code_lines||0,o.blank_lines=e.total_blank_lines||0,o.full_line_comments=e.total_full_line_comments||0,o.inline_comments=e.total_inline_comments||0,n.code_vs_comments&&void 0!==e.total_code_lines&&(o.code_vs_comments_ratio=e.total_code_lines>0?parseFloat((e.total_comment_lines/e.total_code_lines).toFixed(2)):0))),n.show_stats){const t={};for(const o of Object.keys(e.files_by_extension))t[o]={files:e.files_by_extension[o],lines:e.lines_by_extension[o]||0,size:e.size_by_extension[o]||0},n.comments&&(t[o].comment_lines=e.comment_lines_by_extension?.[o]||0,t[o].code_lines=e.code_lines_by_extension?.[o]||0,t[o].blank_lines=e.blank_lines_by_extension?.[o]||0,t[o].full_line_comments=e.full_line_comments_by_extension?.[o]||0,t[o].inline_comments=e.inline_comments_by_extension?.[o]||0,n.code_vs_comments&&e.code_lines_by_extension?.[o]&&e.code_lines_by_extension[o]>0&&(t[o].code_vs_comments_ratio=parseFloat(((e.comment_lines_by_extension[o]||0)/e.code_lines_by_extension[o]).toFixed(2))));o.by_extension=t}if(n.top_files&&n.top_files>0){const t=te(e,n.top_files);o.top_files=t.map(e=>({name:e.name,directory:e.directory,extension:e.extension,size:e.size,size_formatted:G(e.size),lines:e.lines}))}if(n.top_dirs&&n.top_dirs>0){const t=oe(e,n.top_dirs);o.top_directories=t.map(e=>({directory:e.directory,file_count:e.fileCount,total_size:e.totalSize,total_size_formatted:G(e.totalSize),total_lines:e.totalLines}))}return JSON.stringify(o,null,2)}(n,t);case"csv":return function(e,n){const t=W(n.directory);let o=`# Directory,${ee(n)}\n`;if("unknown"!==t&&(o+=`# Project Type,${ne(t)}\n`),n.comments){o+="Extension,Files,Lines,Code Lines,Comment Lines,Blank Lines,Size",n.code_vs_comments&&(o+=",Code vs Comments Ratio"),o+="\n";for(const t of Object.keys(e.files_by_extension)){const s=e.files_by_extension[t],i=e.lines_by_extension[t]||0,l=e.code_lines_by_extension?.[t]||0,r=e.comment_lines_by_extension?.[t]||0;o+=`${t},${s},${i},${l},${r},${e.blank_lines_by_extension?.[t]||0},${e.size_by_extension[t]||0}`,n.code_vs_comments&&l>0&&(o+=`,${((r||0)/l).toFixed(2)}`),o+="\n"}}else{o+="Extension,Files,Lines,Size\n";for(const n of Object.keys(e.files_by_extension))o+=`${n},${e.files_by_extension[n]},${e.lines_by_extension[n]||0},${e.size_by_extension[n]||0}\n`}return o}(n,t);case"tsv":return function(e,n){const t=W(n.directory);let o=`# Directory\t${ee(n)}\n`;if("unknown"!==t&&(o+=`# Project Type\t${ne(t)}\n`),n.comments){o+="Extension\tFiles\tLines\tCode Lines\tComment Lines\tBlank Lines\tSize",n.code_vs_comments&&(o+="\tCode vs Comments Ratio"),o+="\n";for(const t of Object.keys(e.files_by_extension)){const s=e.files_by_extension[t],i=e.lines_by_extension[t]||0,l=e.code_lines_by_extension?.[t]||0,r=e.comment_lines_by_extension?.[t]||0;o+=`${t}\t${s}\t${i}\t${l}\t${r}\t${e.blank_lines_by_extension?.[t]||0}\t${e.size_by_extension[t]||0}`,n.code_vs_comments&&l>0&&(o+=`\t${((r||0)/l).toFixed(2)}`),o+="\n"}}else{o+="Extension\tFiles\tLines\tSize\n";for(const n of Object.keys(e.files_by_extension))o+=`${n}\t${e.files_by_extension[n]}\t${e.lines_by_extension[n]||0}\t${e.size_by_extension[n]||0}\n`}return o}(n,t);case"markdown":return function(e,n){const t=W(n.directory);let o="# LocIO Report\n\n";o+=`**Directory:** ${ee(n)}\n`,"unknown"!==t&&(o+=`**Project Type:** ${ne(t)}\n`),o+="\n",o+="## Summary\n\n",o+="| Metric | Value |\n",o+="|--------|-------|\n",o+=`| Total Files | ${e.total_files} |\n`,o+=`| Total Size | ${G(e.total_size)} |\n`,!n.files_only&&(o+=`| Total Lines | ${e.total_lines} |\n`,n.comments&&void 0!==e.total_comment_lines&&(o+=`| Comment Lines | ${e.total_comment_lines} |\n`,void 0!==e.total_code_lines&&(o+=`| Code Lines | ${e.total_code_lines} |\n`),void 0!==e.total_blank_lines&&e.total_blank_lines>0&&(o+=`| Blank Lines | ${e.total_blank_lines} |\n`),n.code_vs_comments&&void 0!==e.total_code_lines&&e.total_code_lines>0))&&(o+=`| Code vs Comments Ratio | ${(e.total_comment_lines/e.total_code_lines).toFixed(2)}:1 |\n`);if(Object.keys(e.files_by_extension).length>0){o+="\n## Statistics by Extension\n\n",o+="| Extension | Files |",n.lines_only||(o+=" Size |"),n.files_only||(o+=" Lines |",n.comments&&(o+=" Code | Comments |",n.code_vs_comments&&(o+=" Ratio |"))),o+="\n",o+="|----------|-------|",n.lines_only||(o+="------|"),n.files_only||(o+="-------|",n.comments&&(o+="------|-----------|",n.code_vs_comments&&(o+="-------|"))),o+="\n";const t=Object.keys(e.files_by_extension).sort();for(const s of t){const t=e.files_by_extension[s],i=e.size_by_extension[s]||0,l=e.lines_by_extension[s]||0,r=e.code_lines_by_extension?.[s]||0,c=e.comment_lines_by_extension?.[s]||0;o+=`| \`${s}\` | ${t} |`,n.lines_only||(o+=` ${G(i)} |`),!n.files_only&&(o+=` ${l} |`,n.comments)&&(o+=` ${r} | ${c} |`,n.code_vs_comments&&r>0?o+=` ${((c||0)/r).toFixed(2)}:1 |`:n.code_vs_comments&&(o+=" - |")),o+="\n"}}if(n.show_stats&&e.details.length>0){o+="\n## Files by Directory\n\n";const t=Z(e.details),s=Object.keys(t).sort();for(const e of s){const s=t[e];o+=`### ${e}\n\n`,o+="| File | Extension | Size |",n.files_only||(o+=" Lines |",(n.comments||n.show_stats)&&(o+=" Code | Comments | Blank | Full-Line | Inline |")),o+="\n",o+="|------|-----------|------|",n.files_only||(o+="-------|",(n.comments||n.show_stats)&&(o+="------|----------|-------|----------|--------|")),o+="\n";for(const e of s)o+=`| ${e.name} | \`${e.extension}\` | ${G(e.size)} |`,!n.files_only&&null!==e.lines&&(o+=` ${e.lines} |`,n.comments||n.show_stats)&&(o+=` ${e.code_lines||0} | ${e.comment_lines||0} | ${e.blank_lines||0} | ${e.full_line_comments||0} | ${e.inline_comments||0} |`),o+="\n";o+="\n"}}if(n.top_files&&n.top_files>0){const t=te(e,n.top_files);o+=`\n## Top ${n.top_files} Largest Files\n\n`,o+="| Size | File | Extension |",n.files_only||(o+=" Lines |"),o+="\n",o+="|------|------|-----------|",n.files_only||(o+="-------|"),o+="\n";for(const e of t)o+=`| ${G(e.size)} | ${e.name} | \`${e.extension}\` |`,n.files_only||null===e.lines||(o+=` ${e.lines} |`),o+="\n";o+="\n"}if(n.top_dirs&&n.top_dirs>0){const t=oe(e,n.top_dirs);o+=`\n## Top ${n.top_dirs} Directories (by file count)\n\n`,o+="| Files | Directory | Size |",n.files_only||(o+=" Lines |"),o+="\n",o+="|-------|-----------|------|",n.files_only||(o+="-------|"),o+="\n";for(const e of t)o+=`| ${e.fileCount} | ${e.directory} | ${G(e.totalSize)} |`,n.files_only||(o+=` ${e.totalLines} |`),o+="\n";o+="\n"}return o+="\n---\n\n",o+="*Generated by [LocIO](https://locio.js.org)*\n",o}(n,t);case"html":return function(e,n){const t=W(n.directory),o=Object.keys(e.files_by_extension).sort(),s=o.map(n=>({ext:n,files:e.files_by_extension[n],lines:e.lines_by_extension[n]||0,size:e.size_by_extension[n]||0,codeLines:e.code_lines_by_extension?.[n]||0,commentLines:e.comment_lines_by_extension?.[n]||0,blankLines:e.blank_lines_by_extension?.[n]||0}));return`<!DOCTYPE html>\n<html lang="en">\n<head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n <title>LocIO Report - ${ee(n)}</title>\n <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"><\/script>\n <style>\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n min-height: 100vh;\n padding: 20px;\n }\n .container {\n max-width: 1200px;\n margin: 0 auto;\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n overflow: hidden;\n }\n .header {\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n padding: 40px;\n text-align: center;\n }\n .header h1 {\n font-size: 2.5em;\n margin-bottom: 10px;\n }\n .header p {\n opacity: 0.9;\n font-size: 1.1em;\n }\n .content {\n padding: 40px;\n }\n .summary-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 20px;\n margin-bottom: 40px;\n }\n .card {\n background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);\n padding: 25px;\n border-radius: 10px;\n text-align: center;\n box-shadow: 0 4px 6px rgba(0,0,0,0.1);\n }\n .card h3 {\n color: #667eea;\n font-size: 0.9em;\n text-transform: uppercase;\n letter-spacing: 1px;\n margin-bottom: 10px;\n }\n .card .value {\n font-size: 2.5em;\n font-weight: bold;\n color: #2d3748;\n }\n .section {\n margin-bottom: 40px;\n }\n .section h2 {\n color: #2d3748;\n margin-bottom: 20px;\n padding-bottom: 10px;\n border-bottom: 3px solid #667eea;\n }\n .chart-container {\n position: relative;\n height: 400px;\n margin: 20px 0;\n }\n table {\n width: 100%;\n border-collapse: collapse;\n margin-top: 20px;\n background: white;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n }\n th {\n background: #667eea;\n color: white;\n padding: 15px;\n text-align: left;\n font-weight: 600;\n }\n td {\n padding: 12px 15px;\n border-bottom: 1px solid #e2e8f0;\n }\n tr:hover {\n background: #f7fafc;\n }\n .footer {\n text-align: center;\n padding: 20px;\n color: #718096;\n border-top: 1px solid #e2e8f0;\n }\n .footer a {\n color: #667eea;\n text-decoration: none;\n }\n </style>\n</head>\n<body>\n <div class="container">\n <div class="header">\n <h1>LocIO Report</h1>\n <p>Directory: ${ee(n)}</p>\n ${"unknown"!==t?`<p>Project Type: <strong>${ne(t)}</strong></p>`:""}\n </div>\n <div class="content">\n <div class="summary-cards">\n <div class="card">\n <h3>Total Files</h3>\n <div class="value">${e.total_files}</div>\n </div>\n <div class="card">\n <h3>Total Size</h3>\n <div class="value">${G(e.total_size)}</div>\n </div>\n ${n.files_only?"":`<div class="card">\n <h3>Total Lines</h3>\n <div class="value">${e.total_lines}</div>\n </div>`}\n ${n.comments&&void 0!==e.total_comment_lines?`<div class="card">\n <h3>Comment Lines</h3>\n <div class="value">${e.total_comment_lines}</div>\n </div>\n <div class="card">\n <h3>Code Lines</h3>\n <div class="value">${e.total_code_lines||0}</div>\n </div>\n ${void 0!==e.total_blank_lines&&e.total_blank_lines>0?`<div class="card">\n <h3>Blank Lines</h3>\n <div class="value">${e.total_blank_lines}</div>\n </div>`:""}`:""}\n </div>\n\n ${o.length>0?`<div class="section">\n <h2>π Statistics by Extension</h2>\n <div class="chart-container">\n <canvas id="extensionChart"></canvas>\n </div>\n <table>\n <thead>\n <tr>\n <th>Extension</th>\n <th>Files</th>\n ${n.lines_only?"":"<th>Size</th>"}\n ${n.files_only?"":"<th>Lines</th>"}\n ${n.comments?"<th>Code</th><th>Comments</th><th>Blank</th>":""}\n </tr>\n </thead>\n <tbody>\n ${s.map(e=>`<tr>\n <td><strong>${e.ext}</strong></td>\n <td>${e.files}</td>\n ${n.lines_only?"":`<td>${G(e.size)}</td>`}\n ${n.files_only?"":`<td>${e.lines}</td>`}\n ${n.comments?`<td>${e.codeLines}</td><td>${e.commentLines}</td><td>${e.blankLines}</td>`:""}\n </tr>`).join("")}\n </tbody>\n </table>\n </div>`:""}\n\n ${n.comments&&void 0!==e.total_code_lines&&e.total_code_lines>0?'<div class="section">\n <h2>π¬ Code vs Comments</h2>\n <div class="chart-container">\n <canvas id="commentChart"></canvas>\n </div>\n </div>':""}\n\n ${n.top_files&&n.top_files>0?(()=>{const t=te(e,n.top_files);return`<div class="section">\n <h2>π Top ${n.top_files} Largest Files</h2>\n <table>\n <thead>\n <tr>\n <th>Size</th>\n <th>File</th>\n <th>Extension</th>\n ${n.files_only?"":"<th>Lines</th>"}\n </tr>\n </thead>\n <tbody>\n ${t.map(e=>`<tr>\n <td><strong>${G(e.size)}</strong></td>\n <td>${e.name}</td>\n <td><code>${e.extension}</code></td>\n ${n.files_only||null===e.lines?"":`<td>${e.lines}</td>`}\n </tr>`).join("")}\n </tbody>\n </table>\n </div>`})():""}\n\n ${n.top_dirs&&n.top_dirs>0?(()=>{const t=oe(e,n.top_dirs);return`<div class="section">\n <h2>π Top ${n.top_dirs} Directories (by file count)</h2>\n <table>\n <thead>\n <tr>\n <th>Files</th>\n <th>Directory</th>\n <th>Size</th>\n ${n.files_only?"":"<th>Lines</th>"}\n </tr>\n </thead>\n <tbody>\n ${t.map(e=>`<tr>\n <td><strong>${e.fileCount}</strong></td>\n <td>${e.directory}</td>\n <td>${G(e.totalSize)}</td>\n ${n.files_only?"":`<td>${e.totalLines}</td>`}\n </tr>`).join("")}\n </tbody>\n </table>\n </div>`})():""}\n\n ${"html"===n.export?(()=>{const t={};for(const n of e.details)t[n.directory]||(t[n.directory]={fileCount:0,totalSize:0,totalLines:0}),t[n.directory].fileCount+=1,t[n.directory].totalSize+=n.size,null!==n.lines&&(t[n.directory].totalLines+=n.lines);const o=Object.entries(t),s=Math.max(...o.map(([,e])=>e.fileCount)),i=Math.max(...o.map(([,e])=>e.totalSize));return`<div class="section">\n <h2>πΊοΈ Directory Heatmap</h2>\n <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 15px; margin-top: 20px;">\n ${o.map(([e,t])=>{const o=(t.fileCount/s*100+t.totalSize/i*100)/2,l=240-1.2*o;return`<div style="\n background: linear-gradient(135deg, hsl(${l}, 70%, ${85-.3*o}%), hsl(${l}, 70%, ${75-.3*o}%));\n padding: 15px;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n color: ${o>50?"white":"#2d3748"};\n ">\n <div style="font-weight: bold; margin-bottom: 8px; font-size: 0.9em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="${e}">${e.split("/").pop()||e}</div>\n <div style="font-size: 0.8em; opacity: 0.9;">\n <div>π ${t.fileCount} files</div>\n <div>πΎ ${G(t.totalSize)}</div>\n ${n.files_only?"":`<div>π ${t.totalLines} lines</div>`}\n </div>\n </div>`}).join("")}\n </div>\n </div>`})():""}\n </div>\n <div class="footer">\n Generated by <a href="https://locio.js.org">LocIO</a>\n </div>\n </div>\n\n <script>\n ${o.length>0?`const extensionCtx = document.getElementById('extensionChart');\n new Chart(extensionCtx, {\n type: 'bar',\n data: {\n labels: ${JSON.stringify(o)},\n datasets: [\n ${n.files_only?"":`{\n label: 'Lines',\n data: ${JSON.stringify(o.map(n=>e.lines_by_extension[n]||0))},\n backgroundColor: 'rgba(102, 126, 234, 0.8)',\n borderColor: 'rgba(102, 126, 234, 1)',\n borderWidth: 2\n },`}\n {\n label: 'Files',\n data: ${JSON.stringify(o.map(n=>e.files_by_extension[n]))},\n backgroundColor: 'rgba(118, 75, 162, 0.8)',\n borderColor: 'rgba(118, 75, 162, 1)',\n borderWidth: 2\n }\n ]\n },\n options: {\n responsive: true,\n maintainAspectRatio: false,\n plugins: {\n legend: {\n position: 'top',\n },\n title: {\n display: true,\n text: 'Files and Lines by Extension'\n }\n }\n }\n });`:""}\n\n ${n.comments&&void 0!==e.total_code_lines&&e.total_code_lines>0?`const commentCtx = document.getElementById('commentChart');\n new Chart(commentCtx, {\n type: 'doughnut',\n data: {\n labels: ['Code Lines', 'Comment Lines'],\n datasets: [{\n data: [${e.total_code_lines}, ${e.total_comment_lines||0}],\n backgroundColor: [\n 'rgba(102, 126, 234, 0.8)',\n 'rgba(118, 75, 162, 0.8)'\n ],\n borderColor: [\n 'rgba(102, 126, 234, 1)',\n 'rgba(118, 75, 162, 1)'\n ],\n borderWidth: 2\n }]\n },\n options: {\n responsive: true,\n maintainAspectRatio: false,\n plugins: {\n legend: {\n position: 'bottom',\n },\n title: {\n display: true,\n text: 'Code vs Comments Distribution'\n }\n }\n }\n });`:""}\n <\/script>\n</body>\n</html>`}(n,t)}}function ie(e,n,t){const o=function(e){switch(e){case"human":return"txt";case"json":return"json";case"csv":return"csv";case"tsv":return"tsv";case"markdown":return"md";case"html":return"html"}}(e);let s;return s=Array.isArray(n.export)&&n.export.length>1&&void 0!==t?`LocIO-report-${t+1}.${o}`:`LocIO-report.${o}`,n.export_path?_.join(n.export_path,s):s}function le(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"+y.default.cyan("=".repeat(60))),console.log(y.default.cyan.bold("LocIO RESULTS".padStart(37).padEnd(60))),console.log(y.default.cyan("=".repeat(60))),console.log(`\n${y.default.green.bold("Directory:")} ${ee(n)}`),n.lines_only||(X(n)?console.log(`\n${y.default.green.bold("Size:")} ${y.default.white(G(e.total_size))}`):(console.log(`\n${y.default.green.bold("Total Files:")} ${y.default.yellow(e.total_files)}`),console.log(`\n${y.default.green.bold("Total Files Size:")} ${y.default.white(G(e.total_size))}`))),!n.files_only&&(console.log(`\n${y.default.green.bold("Total Lines:")} ${y.default.yellow(e.total_lines)}`),(n.comments||n.show_stats)&&void 0!==e.total_comment_lines&&(console.log(`\n${y.default.green.bold("Total Comment Lines:")} ${y.default.cyan(e.total_comment_lines)}`),void 0!==e.total_full_line_comments&&console.log(` ${y.default.gray("β")} ${y.default.green("Full Line Comments:")} ${y.default.cyan(e.total_full_line_comments)}`),void 0!==e.total_inline_comments&&console.log(` ${y.default.gray("β")} ${y.default.green("Inline Comments:")} ${y.default.cyan(e.total_inline_comments)}`),void 0!==e.total_code_lines&&console.log(`\n${y.default.green.bold("Total Code Lines:")} ${y.default.blue(e.total_code_lines)}`),void 0!==e.total_blank_lines&&e.total_blank_lines>0&&console.log(`\n${y.default.green.bold("Total Blank Lines:")} ${y.default.gray(e.total_blank_lines)}`),n.code_vs_comments&&void 0!==e.total_code_lines))){const n=e.total_code_lines>0?(e.total_comment_lines/e.total_code_lines).toFixed(2):"0.00";console.log(`\n${y.default.green.bold("Code vs Comments Ratio:")} ${y.default.magenta(n)}:1 ${y.default.gray(`(${e.total_comment_lines} comments per ${e.total_code_lines} code lines)`)}`)}if(Object.keys(e.files_by_extension).length>0){const n=Object.keys(e.files_by_extension).sort();console.log(`\n${y.default.green.bold("Extensions:")} ${y.default.white(n.join(", "))}`)}if(n.show_stats&&Object.keys(e.files_by_extension).length>0){console.log(`\n${y.default.cyan.bold("Statistics by Extension:")}`),console.log(y.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],s=e.size_by_extension[o]||0,i=e.lines_by_extension[o]||0;let l=` ${y.default.white(o)}: ${y.default.yellow(t)} files`;if(n.lines_only||(l+=`, ${y.default.white(G(s))}`),!n.files_only&&(l+=`, ${y.default.yellow(i)} lines`,Q(n,void 0!==e.comment_lines_by_extension?.[o]))){const t=V({comment_lines:e.comment_lines_by_extension?.[o]||0,code_lines:e.code_lines_by_extension?.[o]||0,full_line_comments:e.full_line_comments_by_extension?.[o]||0,inline_comments:e.inline_comments_by_extension?.[o]||0}),s=e.blank_lines_by_extension?.[o]||0;if(l+=H(t.codeLines,t.commentLines,t.fullLineComments,t.inlineComments,s),n.code_vs_comments&&t.codeLines>0){const e=(t.commentLines/t.codeLines).toFixed(2);l+=` ${y.default.magenta(`[${e}:1]`)}`}}console.log(l)}}if(n.show_stats&&e.details.length>0){console.log(`\n${y.default.cyan.bold("Files by Directory:")}`),console.log(y.default.gray("-".repeat(60)));const t=Z(e.details),o=Object.keys(t).sort();for(const e of o){const o=t[e];console.log(y.default.green.bold(`Directory: ${e}`));for(const e of o){const t=G(e.size),o=null===e.lines||n.files_only?"":` | ${e.lines} lines`;let s="";if(Q(n,void 0!==e.comment_lines&&null!==e.comment_lines)){const n=V(e);s=H(n.codeLines,n.commentLines,n.fullLineComments,n.inlineComments,e.blank_lines||void 0)}console.log(` - ${y.default.white(e.name)} (${y.default.blue(e.extension)}, ${y.default.white(t)}${o}${s})`)}console.log()}}if(n.top_files&&n.top_files>0){const t=te(e,n.top_files);console.log(`\n${y.default.cyan.bold(`Top ${n.top_files} Largest Files:`)}`),console.log(y.default.gray("-".repeat(60)));for(const e of t){const{sizeStr:t,linesStr:o}=Y(e.size,e.lines,n);console.log(` ${y.default.yellow(t.padEnd(10))} ${y.default.white(e.name)} ${y.default.blue(`(${e.extension})`)}${o}`)}}if(n.top_dirs&&n.top_dirs>0){const t=oe(e,n.top_dirs);console.log(`\n${y.default.cyan.bold(`Top ${n.top_dirs} Directories (by file count):`)}`),console.log(y.default.gray("-".repeat(60)));for(const e of t){const t=G(e.totalSize),o=n.files_only?"":` | ${e.totalLines} lines`;console.log(` ${y.default.yellow(e.fileCount.toString().padEnd(5))} files ${y.default.white(e.directory)} ${y.default.gray(`(${t}${o})`)}`)}}console.log()}}(e,n):function(e,n){const t=Array.isArray(n.export)?n.export:[n.export||"human"];for(let o=0;o<t.length;o++){const s=t[o],i=se(s,e,n),l=ie(s,n,o);try{let e;e=n.export_path?n.export_path:_.dirname(l),"."!==e&&e!==l&&p.mkdirSync(e,{recursive:!0}),p.writeFileSync(l,i,"utf-8"),n.quiet||console.log(`Report written to ${l}`)}catch(e){const n=(e instanceof Error?e:new Error(String(e))).message||String(e);let t="";t=n.includes("ENOENT")?`The directory for "${l}" does not exist.\n - Ensure the parent directory exists\n - Check if the path is correct`:n.includes("EACCES")||n.includes("permission")?`Permission denied when writing to "${l}".\n - Check write permissions for the directory\n - Try running with appropriate permissions\n - Use a different output directory`:n.includes("ENOSPC")?"Insufficient disk space.\n - Free up disk space\n - Choose a different location":"Check if the path is valid and you have write permissions.",console.error(`\nβ Failed to create report file ${l}`),console.error(`π Error: ${n}`),t&&console.error(`\nπ‘ Suggestion:\n${t}`)}}}(e,n)}function re(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 s=parseFloat(t);return isNaN(s)?L.invalidSizeFormat(e):Math.floor(s*o)}var ce=["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"],ae=["md","markdown","txt","rst","adoc","asciidoc","org","wiki","json","yaml","yml","toml","ini","cfg","conf","config","properties","env","dotenv","csv","tsv","xml","html","htm","xhtml","log","lock","lockfile"];function de(e){try{if(e.max_size){const n=re(e.max_size);if(n instanceof L)return n}if(e.min_size){const n=re(e.min_size);if(n instanceof L)return n}const n=W(e.directory),t=T[n]||T.unknown,o=e.exclude_patterns.map(n=>{try{return new RegExp(n,e.ignore_case?"i":void 0)}catch(e){throw L.invalidRegex(n,e instanceof Error?e:void 0)}}),s=[...e.exclude_extensions.map(e=>e.replace(/^\./,"").toLowerCase()),...t.exclude_extensions.map(e=>e.toLowerCase()),...ce.map(e=>e.toLowerCase())],i=Array.from(new Set(s)).sort(),l=e.include_extensions.map(e=>e.replace(/^\./,"").toLowerCase()),r=[...e.exclude_dirs,...t.exclude_dirs].map(n=>new RegExp(n,e.ignore_case?"i":void 0)),c=e.include_dirs.map(n=>new RegExp(n,e.ignore_case?"i":void 0)),a=[...e.exclude_names,...t.exclude_names].map(n=>new RegExp(n,e.ignore_case?"i":void 0));return{exclude_patterns:o,exclude_extensions:i,include_extensions:l,exclude_dirs:r,include_dirs:c,exclude_names:a,include_names:e.include_names.map(n=>new RegExp(n,e.ignore_case?"i":void 0)),detected_project_type:n}}catch(e){return e instanceof L?e:L.io(`Failed to create filter patterns: ${e instanceof Error?e.message:String(e)}`)}}function ue(e,n,t){const o=e,s=_.basename(e);for(const e of t.exclude_patterns)if(e.test(o))return!0;const i=_.extname(e).replace(/^\./,"").toLowerCase();if(i){for(const e of t.exclude_extensions)if(i===e.toLowerCase())return!0;if(t.include_extensions.length>0){let e=!1;for(const n of t.include_extensions)if(i===n.toLowerCase()){e=!0;break}if(!e)return!0}}else if(t.include_extensions.length>0)return!0;const l=_.dirname(e);for(const e of t.exclude_dirs)if(e.test(l))return!0;if(t.include_dirs.length>0){let e=!1;for(const n of t.include_dirs)if(n.test(l)){e=!0;break}if(!e)return!0}for(const e of t.exclude_names)if(e.test(s))return!0;if(t.include_names.length>0){let e=!1;for(const n of t.include_names)if(n.test(s)){e=!0;break}if(!e)return!0}if(n.no_hidden&&s.startsWith("."))return!0;try{const t=p.statSync(e).size;if(n.max_size){const e=re(n.max_size);if(!(e instanceof L)&&t>e)return!0}if(n.min_size){const e=re(n.min_size);if(!(e instanceof L)&&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=p.openSync(e,"r"),o=p.readSync(t,n,0,8192,0);if(p.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 me(e){return _.extname(e).replace(/^\./,"").toLowerCase()||"no-ext"}function fe(e){const n=null!==e.commentLines,t=null!==e.codeLines&&null!==e.blankLines;return n||t?{totalLines:e.lines||0,commentLines:e.commentLines||0,codeLines:e.codeLines||0,fullLineComments:e.fullLineComments||0,inlineComments:e.inlineComments||0,blankLines:e.blankLines||0}:null}function pe(e,n,t,o,s){if(e.total_files+=1,e.total_size+=t,e.files_by_extension[n]=(e.files_by_extension[n]||0)+1,e.size_by_extension[n]=(e.size_by_extension[n]||0)+t,null!==o&&(e.total_lines+=o,e.lines_by_extension[n]=(e.lines_by_extension[n]||0)+o),s){const t=s.codeLines+s.commentLines+s.blankLines;s.totalLines!==t&&(s.totalLines=t),e.total_comment_lines=(e.total_comment_lines||0)+s.commentLines,e.total_code_lines=(e.total_code_lines||0)+s.codeLines,e.total_blank_lines=(e.total_blank_lines||0)+s.blankLines,e.total_full_line_comments=(e.total_full_line_comments||0)+s.fullLineComments,e.total_inline_comments=(e.total_inline_comments||0)+s.inlineComments,e.comment_lines_by_extension[n]=(e.comment_lines_by_extension[n]||0)+s.commentLines,e.code_lines_by_extension[n]=(e.code_lines_by_extension[n]||0)+s.codeLines,e.blank_lines_by_extension||(e.blank_lines_by_extension={}),e.blank_lines_by_extension[n]=(e.blank_lines_by_extension[n]||0)+s.blankLines,e.full_line_comments_by_extension[n]=(e.full_line_comments_by_extension[n]||0)+s.fullLineComments,e.inline_comments_by_extension[n]=(e.inline_comments_by_extension[n]||0)+s.inlineComments}}function _e(e,n){const t=_.extname(e).replace(/^\./,"").toLowerCase(),o=ae.map(e=>e.toLowerCase()).includes(t);if(n.comments){if(!o){const n=function(e){try{const n=p.readFileSync(e,"utf-8").split(/\r?\n/),t=A(_.extname(e));let o=n.length,s=0,i=0,l=0,r=0,c=0,a=!1;for(const e of n){if(0===e.trim().length){a?(i++,l++):c++;continue}const n=P(e,t,a);n?(n.isMultiLine&&(a=!n.endsMultiLine),n.hasCodeBefore?(r++,s++,n.hasCodeAfter):(l++,n.hasCodeAfter&&s++),i++):a?(i++,l++):s++}return{totalLines:o,codeLines:s,commentLines:i,fullLineComments:l,inlineComments:r,blankLines:c}}catch{return null}}(e);if(n)return{lines:n.totalLines,commentLines:n.commentLines,codeLines:n.codeLines,fullLineComments:n.fullLineComments,inlineComments:n.inlineComments,blankLines:n.blankLines,error:null}}const n=function(e){try{const n=p.readFileSync(e,"utf-8").split(/\r?\n/);let t=0,o=0;for(const e of n)0===e.trim().length?t++:o++;return{total:n.length,blank:t,code:o}}catch(n){return L.io(`Failed to read file: ${e}`,n instanceof Error?n:void 0)}}(e);return w(n)?{lines:null,commentLines:null,codeLines:null,fullLineComments:null,inlineComments:null,blankLines:null,error:n}:{lines:n.total,commentLines:0,codeLines:n.code,fullLineComments:0,inlineComments:0,blankLines:n.blank,error:null}}const s=function(e){try{return p.readFileSync(e,"utf-8").split(/\r?\n/).length}catch(n){return L.io(`Failed to read file: ${e}`,n instanceof Error?n:void 0)}}(e);return w(s)?{lines:null,commentLines:null,codeLines:null,fullLineComments:null,inlineComments:null,blankLines:null,error:s}:{lines:s,commentLines:null,codeLines:null,fullLineComments:null,inlineComments:null,blankLines:null,error:null}}function ye(e,n,t,o,s,i,l,r,c){return{directory:_.dirname(e),name:_.basename(e),extension:t,size:n,lines:o,comment_lines:s,code_lines:i,blank_lines:c,full_line_comments:l,inline_comments:r}}function he(e){try{return{metadata:p.statSync(e),error:null}}catch(e){return{metadata:null,error:e instanceof Error?e:new Error(String(e))}}}function ge(e,n,t){return _.relative(n,e).split(_.sep).length-1>t}var xe=class{constructor(e){b(this,"total"),b(this,"current",0),b(this,"startTime"),b(this,"width",40),b(this,"errors",0),this.total=e,this.startTime=Date.now()}update(e,n=0){this.current=e,this.errors=n,this.render()}increment(e=0){this.current++,e>0&&(this.errors=e),this.render()}formatTime(e){if(e<1e3)return`${e}ms`;if(e<6e4)return`${(e/1e3).toFixed(1)}s`;return`${Math.floor(e/6e4)}m ${Math.floor(e%6e4/1e3)}s`}calculateETA(){if(0===this.current)return"calculating...";const e=Date.now()-this.startTime,n=this.current/e,t=(this.total-this.current)/n;return t<0||!isFinite(t)?"calculating...":this.formatTime(t)}render(){const e=this.total>0?this.current/this.total*100:0,n=e.toFixed(1).padStart(5),t=String(this.current).padStart(String(this.total).length),o=this.errors>0?y.default.red(` (${this.errors} errors)`):"",s=Date.now()-this.startTime,i=this.formatTime(s),l=this.calculateETA();if(!process.stderr.isTTY)return void(this.current%100!=0&&this.current!==this.total||process.stderr.write(`\rProcessed: ${t}/${this.total} (${n}%) | ${i} elapsed | ETA: ${l}${o}`));const r=Math.round(e/100*this.width),c=this.width-r,a=`\r${y.default.green("β".repeat(r))+y.default.gray("β".repeat(c))} ${n}% | ${t}/${this.total} files | ${i} elapsed | ETA: ${l}${o}`;process.stderr.write("[K"+a)}finish(){const e=Date.now()-this.startTime,n=this.formatTime(e),t=this.errors>0?y.default.red(` (${this.errors} errors)`):"";if(process.stderr.isTTY){const e=100,o=y.default.green("β".repeat(this.width)),s=String(this.current).padStart(String(this.total).length);process.stderr.write(`\r${o} ${e.toFixed(1).padStart(5)}% | ${s}/${this.total} files | ${n}${t}\n`)}else process.stderr.write(`\rProcessed: ${this.current}/${this.total} files in ${n}${t}\n`)}};function be(e){const n=Date.now(),t={total_files:0,total_lines:0,total_size:0,total_comment_lines:0,total_code_lines:0,total_blank_lines:0,total_full_line_comments:0,total_inline_comments:0,files_by_extension:{},lines_by_extension:{},comment_lines_by_extension:{},code_lines_by_extension:{},blank_lines_by_extension:{},full_line_comments_by_extension:{},inline_comments_by_extension:{},size_by_extension:{},details:[]},o=de(e);if(w(o))return o;const s=_.resolve(e.directory),i=_.dirname(s),{processed:l,errors:r}=function(e,n,t,o,s){let i=0,l=0;if(void 0!==n.max_depth&&ge(e,s,n.max_depth))return{processed:i,errors:l};try{if(!p.statSync(e).isFile())return{processed:i,errors:l}}catch{return{processed:i,errors:l}}if(ue(e,n,o))return{processed:i,errors:l};const r=he(e);if(r.error)return n.quiet||console.error(`Warning: Could not read metadata for ${e}: ${r.error}`),l+=1,{processed:i,errors:l};const c=r.metadata.size,a=me(e);if(n.rm_comments){const t=a.toLowerCase().replace(/^\./,"");if(ae.map(e=>e.toLowerCase()).includes(t))return{processed:i,errors:l};if((()=>{if(!0===n.rm_comments)return!0;if("string"==typeof n.rm_comments){const e=j(n.rm_comments).map(e=>e.toLowerCase().replace(/^\./,""));return e.includes(t)||e.includes(`.${t}`)}return!1})()){const t=N(e);if(t.success){if(t.commentsFound){if(!n.quiet){const n=_.relative(s,e);console.log(`β Removed comments from ${n}`)}i+=1}}else{if(!n.quiet){const n=_.relative(s,e);console.error(`β Failed to remove comments from ${n}`)}l+=1}}return{processed:i,errors:l}}i+=1;let d=null,u=null,m=null,f=null,y=null,h=null,g=null;if(!n.files_only){const t=_e(e,n);t.error?(n.quiet||console.error(`Warning: Could not count lines in ${e}: ${t.error.message}`),l+=1):(d=t.lines,u=t.commentLines,m=t.codeLines,f=t.fullLineComments,y=t.inlineComments,h=t.blankLines,g=fe(t))}return pe(t,a,c,d,g),t.details.push(ye(e,c,a,d,u,m,f,y,h)),{processed:i,errors:l}}(s,e,t,o,i);return $e(e,n,l,r),e.rm_comments?{...t,_commentsRemoved:l}:t}function $e(e,n,t,o){if(e.show_progress&&!e.quiet){const e=`${Date.now()-n}ms`;process.stderr.write(`\rProcessed: ${t} files (${o} errors) in ${e}\n`)}}function ve(e){const n=Date.now(),t={total_files:0,total_lines:0,total_size:0,total_comment_lines:0,total_code_lines:0,total_blank_lines:0,total_full_line_comments:0,total_inline_comments:0,files_by_extension:{},lines_by_extension:{},comment_lines_by_extension:{},code_lines_by_extension:{},blank_lines_by_extension:{},full_line_comments_by_extension:{},inline_comments_by_extension:{},size_by_extension:{},details:[]},o=de(e);if(w(o))return o;const s=function(e){const n=g.default();return n.add(".git"),n.add(".gitignore"),n.add(".lcignore"),function e(t,o){const s=_.join(t,".gitignore");try{if(p.existsSync(s)&&p.statSync(s).isFile()){const e=p.readFileSync(s,"utf-8"),i=_.relative(o,t)||".",l=e.split("\n").map(e=>e.trim()).filter(e=>e&&!e.startsWith("#"));for(const e of l)"."===i?n.add(e):n.add(_.join(i,e))}}catch{}try{const n=p.readdirSync(t);for(const s of n){const n=_.join(t,s);try{p.statSync(n).isDirectory()&&".git"!==s&&e(n,o)}catch{}}}catch{}}(e,e),n}(e.directory),i={cwd:e.directory,absolute:!0,onlyFiles:!0,ignore:[],dot:!e.no_hidden,followSymbolicLinks:e.follow_links};let l=0,r=0,c=null,a=0;try{const n=h.default.sync("**/*",i).map(e=>"string"==typeof e?e:e.path||String(e));e.show_progress&&!e.quiet&&(c=new xe(n.length));for(const i of n){if(a+=1,c&&c.update(a,r),void 0!==e.max_depth&&ge(i,e.directory,e.max_depth))continue;const n=_.relative(e.directory,i);if(s.ignores(n))continue;try{if(!p.statSync(i).isFile())continue}catch{continue}if(ue(i,e,o))continue;const d=he(i);if(d.error){e.quiet||console.error(`Warning: Could not read metadata for ${i}: ${d.error}`),r+=1;continue}const u=d.metadata.size,m=me(i);if(e.rm_comments){const n=m.toLowerCase().replace(/^\./,"");if(ae.map(e=>e.toLowerCase()).includes(n))continue;if((()=>{if(!0===e.rm_comments)return!0;if("string"==typeof e.rm_comments){const t=j(e.rm_comments).map(e=>e.toLowerCase().replace(/^\./,""));return t.includes(n)||t.includes(`.${n}`)}return!1})()){const n=N(i);if(n.success){if(n.commentsFound){if(!e.quiet){const n=_.relative(e.directory,i);console.log(`β Removed comments from ${n}`)}l+=1}}else{if(!e.quiet){const n=_.relative(e.directory,i);console.error(`β Failed to remove comments from ${n}`)}r+=1}}continue}l+=1;let f=null,y=null,h=null,g=null,x=null,b=null,$=null;if(!e.files_only){const n=_e(i,e);n.error?(e.quiet||console.error(`Warning: Could not count lines in ${i}: ${n.error.message}`),r+=1):(f=n.lines,y=n.commentLines,h=n.codeLines,g=n.fullLineComments,x=n.inlineComments,b=n.blankLines,$=fe(n))}pe(t,m,u,f,$),t.details.push(ye(i,u,m,f,y,h,g,x,b))}}catch(e){return L.io(`Failed to scan directory: ${e instanceof Error?e.message:String(e)}`,e instanceof Error?e:void 0)}return $e(e,n,l,r),e.rm_comments?{...t,_commentsRemoved:l}:t}var ke=null,Le=!1,we=null;function Ce(e){const n=z(e.directory);if(n.error)return n.error;const t=n.path;if(!p.statSync(t).isDirectory())return L.notADirectory(e.directory);e.directory=t;const o=ve(e);if(w(o))return o;le(o,e)}function je(e,n=500){ke&&clearTimeout(ke),ke=setTimeout(()=>{if(Le)return;Le=!0,e.quiet||(process.stdout.isTTY&&console.log("[2J[H"),console.log(y.default.cyan("π Changes detected. Rescanning...\n")));const n=Ce(e);w(n)?e.quiet||(console.error(y.default.red(`\nβ Error: ${n.message}`)),n.suggestion&&console.error(y.default.yellow(`\nπ‘ Suggestion: ${n.suggestion}`))):e.quiet||(console.log(y.default.gray("\n"+"β".repeat(60))),console.log(y.default.gray(`π Watching for changes... (Press ${y.default.yellow("Ctrl+C")} to stop)`))),Le=!1},n)}function Se(e){if(e.version)return void console.log(`LocIO ${k()}`);if(e.watch)return void function(e){const n=z(e.directory);n.error&&(console.error(`Error: ${n.error.message}`),process.exit(1));const t=n.path;p.statSync(t).isDirectory()||(console.error(`Error: Not a directory: ${e.directory}`),process.exit(1)),e.quiet||console.log(y.default.cyan("π Starting watch mode...\n"));const o=Ce(e);w(o)&&(console.error(`Error: ${o.message}`),process.exit(1)),e.quiet||(console.log(y.default.gray("\n"+"β".repeat(60))),console.log(y.default.gray(`π Watching for changes... (Press ${y.default.yellow("Ctrl+C")} to stop)`)));try{(we=p.watch(t,{recursive:!0},(n,t)=>{t&&(e.export&&t.startsWith("LocIO-report.")||je(e,500))})).on("error",n=>{e.quiet||console.error(y.default.red(`\nWatch error: ${n.message}`))})}catch(e){console.error(y.default.red(`Failed to start watch mode: ${e instanceof Error?e.message:String(e)}`)),console.error(y.default.yellow("Note: Recursive watching may not be supported on all systems.")),process.exit(1)}const s=()=>{ke&&clearTimeout(ke),we&&we.close(),e.quiet||console.log(y.default.gray("\n\nπ Watch mode stopped.")),process.exit(0)};process.on("SIGINT",s),process.on("SIGTERM",s)}(e);const n=z(e.directory);if(n.error)return n.error;const t=n.path,o=p.statSync(t);let s;if(o.isDirectory()&&!e.quiet){const e=W(t);"unknown"!==e&&console.log(`${y.default.cyan("Detected project type:")} ${y.default.blue.bold(ne(e))}\n`)}if(e.directory=t,e.rm_comments){if(e.quiet||console.log(y.default.cyan("Removing comments from files...\n")),s=o.isFile()?be(e):ve(e),w(s))return s;const n=s._commentsRemoved||0;return void(e.quiet||(n>0?console.log(y.default.green(`\nβ Comments removed successfully from ${n} file(s)!\n`)):console.log(y.default.yellow("\nβΉ No comments found in any files.\n"))))}if(s=o.isFile()?be(e):ve(e),w(s))return s;le(s,e)}(async function(){if(2===m.argv.length&&m.stdin.isTTY){if(!await new Promise((e,n)=>{const t=k();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"),m.nextTick(()=>{const t=f.createInterface({input:m.stdin,output:m.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 . # Quick scan"),console.log(" locio . --files-only # Show only file counts"),console.log(" locio . --lines-only # Show only line counts"),console.log(' locio . --exclude "target" # Ignore patterns'),console.log(" locio . --include-ext ts,js # Filter by extension"),console.log(" locio . --export json # Export to JSON\n"),t.close(),e(!1);break;case"3":console.log(),F().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}!function(e){const n=Se(e);w(n)&&(console.error(function(e){let n=`\nβ Error: ${e.message}\n`;return e.suggestion&&(n+=`\nπ‘ Suggestion:\n${e.suggestion}\n`),e.cause&&(n+=`\nπ Details: ${e.cause.message}\n`),n}(n)),process.exit(1)),e.watch||process.exit(0)}(function(){const e=F();e.parse();const n=e.opts(),t=e.args,o=n.excludeExt?j(n.excludeExt):[],s=n.includeExt?j(n.includeExt):[];return{directory:t[0]||".",files_only:n.filesOnly||!1,lines_only:n.linesOnly||!1,exclude_patterns:n.exclude||[],exclude_extensions:o,include_extensions:s,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:!0!==n.noProgress,no_binary:n.noBinary||!1,ignore_case:n.ignoreCase||!1,quiet:n.quiet||!1,export:S(n.export),export_path:n.exportPath,version:!1,watch:n.watch||!1,comments:!0!==n.noComments,code_vs_comments:n.codeVsComments||!1,rm_comments:!!n.rmComments&&(!0===n.rmComments||n.rmComments),top_files:n.topFiles,top_dirs:n.topDirs}}())})().catch(e=>{console.error("Unexpected error:",e),m.exit(1)});
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
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)});
|
|
2
|
+
import*as e from"process";import*as n from"readline";import{Command as t}from"commander";import*as o from"fs";import{readFileSync as s}from"fs";import*as i from"path";import{dirname as r,join as l}from"path";import{fileURLToPath as c}from"url";import a from"chalk";import d from"fast-glob";import m from"ignore";var u=Object.defineProperty,f=(e,n,t)=>((e,n,t)=>n in e?u(e,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[n]=t)(e,"symbol"!=typeof n?n+"":n,t),p=r(c(import.meta.url));function _(){try{const e=[l(p,"../package.json"),l(p,"../../package.json"),l(process.cwd(),"package.json")];for(const n of e)try{const e=JSON.parse(s(n,"utf-8"));if(e.version)return e.version}catch{continue}return"0.0.0"}catch(e){return"0.0.0"}}var y=class e extends Error{constructor(e,n,t){super(e),this.cause=n,f(this,"suggestion"),this.name="LineCounterError",this.suggestion=t}static io(n,t){return new e(`IO error: ${n}`,t,"Check if the file/directory exists, you have read permissions, and there's sufficient disk space.")}static invalidSizeFormat(n){return new e(`Invalid size format: ${n}`,void 0,"Size format should be a number followed by a unit (e.g., '5MB', '1KB', '500B').\nValid units: B, KB, MB, GB, TB (case-insensitive).")}static invalidRegex(n,t){return new e(`Invalid regex pattern: ${n}${t?`: ${t.message}`:""}`,t,"Check your regex pattern syntax. Common issues:\n - Escape special characters with backslash (\\* for literal *)\n - Use proper grouping syntax (parentheses, brackets)\n - Verify quantifiers are properly placed\n - Test your pattern at https://regex101.com")}static directoryNotFound(n){let t;try{t=i.resolve(n)}catch{t=n}return new e(`Directory not found: ${n}`,void 0,`The path "${n}" does not exist.\n - Check if the path is correct (resolved: ${t})\n - Use relative paths like '.' for current directory\n - Verify you have read permissions\n - Check if it's a file instead of a directory (use the file path directly)`)}static notADirectory(n){return new e(`Not a directory: ${n}`,void 0,`"${n}" exists but is not a directory.\n - If it's a file, you can scan it directly: locio <file-path>\n - If you meant a directory, check the path spelling\n - Use 'locio .' to scan the current directory`)}static fileNotFound(n){return new e(`File not found: ${n}`,void 0,`The file "${n}" does not exist.\n - Check if the file path is correct\n - Verify the file extension\n - Ensure you have read permissions`)}static exportPathError(n,t){return new e(`Export path error: ${n}`,void 0,`Cannot write to export path "${n}": ${t}\n - Ensure the directory exists or can be created\n - Check write permissions\n - Verify there's sufficient disk space\n - Use an absolute path if relative paths aren't working`)}};function h(e){return e instanceof y}function g(e,n){return n&&Array.isArray(n)?[...n,e]:[e]}function x(e){return e.split(",").map(e=>e.trim()).filter(Boolean)}function b(e){if(void 0===e)return;if(!0===e)return"human";const n={json:"json",csv:"csv",tsv:"tsv",markdown:"markdown",md:"markdown",html:"html",human:"human",txt:"human"},t=x(e).map(e=>n[e.toLowerCase()]).filter(e=>void 0!==e);return t.length>0?1===t.length?t[0]:t:void 0}function $(e){const n=i.resolve(e);if(!o.existsSync(n))return{path:null,error:y.directoryNotFound(e)};const t=o.statSync(n);return t.isDirectory()||t.isFile()?{path:n,error:null}:{path:null,error:y.notADirectory(e)}}function v(e,n){const t=e.length>n.length?e:n;if(0===t.length)return 1;const o=function(e,n){const t=[];for(let e=0;e<=n.length;e++)t[e]=[e];for(let n=0;n<=e.length;n++)t[0][n]=n;for(let o=1;o<=n.length;o++)for(let s=1;s<=e.length;s++)n.charAt(o-1)===e.charAt(s-1)?t[o][s]=t[o-1][s-1]:t[o][s]=Math.min(t[o-1][s-1]+1,t[o][s-1]+1,t[o-1][s]+1);return t[n.length][e.length]}(e,n);return(t.length-o)/t.length}function k(){const e=new t,n=["files-only","lines-only","exclude","exclude-ext","include-ext","exclude-dir","include-dir","exclude-name","include-name","max-size","min-size","no-hidden","no-empty","follow-links","max-depth","stats","no-progress","no-binary","ignore-case","quiet","export","export-path","watch","no-comments","code-vs-comments","rm-comments","top-files","top-dirs","version"];return e.configureOutput({writeErr:e=>{if(e.includes("unknown option")){const t=e.match(/unknown option ['"]--?([^'"]+)['"]/);if(t){const e=t[1],o=function(e,n,t=3){return n.map(n=>({option:n,score:v(e,n)})).sort((e,n)=>n.score-e.score).filter(e=>e.score>.3).slice(0,t).map(e=>e.option)}(e,n);if(o.length>0){const n=1===o.length?"Did you mean this?":"Did you mean one of these?";process.stderr.write(`\nβ Unknown option: '--${e}'\n\nπ‘ ${n}\n`+o.map(e=>` β’ --${e}`).join("\n")+"\n\nRun 'locio --help' to see all available options.\n\n"),process.exit(1)}process.stderr.write(`\nβ Unknown option: '--${e}'\n\nπ‘ This option doesn't exist. Run 'locio --help' to see all available options.\n\n`),process.exit(1)}}process.stderr.write(e)}}),e.name("LocIO").description("A powerful CLI tool to count lines and files in directories").version(_(),"-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",g).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",g).option("--include-dir <pattern>","Include only directories matching pattern",g).option("--exclude-name <pattern>","Exclude files by name pattern",g).option("--include-name <pattern>","Include only files by name pattern",g).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("--no-progress","Disable progress indicator (enabled by default)").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, markdown, html). Multiple formats can be specified comma-separated (e.g., json,html,markdown)").option("--export-path <dir>","Specify output directory for exported reports. Files will use default naming (LocIO-report.{ext}). Directories will be created automatically if they don't exist").option("-w, --watch","Watch directory for changes and auto-rescan").option("--no-comments","Disable comment counting (enabled by default)").option("--code-vs-comments","Show code vs comments ratio (automatically enables --comments)").option("--rm-comments [extensions]","Remove comments from files (modifies files in place). Optionally specify file extensions (comma-separated, e.g., js,ts,py). If no extensions specified, all files are processed.").option("--top-files <n>","Show top N largest files by size",parseInt).option("--top-dirs <n>","Show top N directories with most files",parseInt),e}var L=[{type:"nextjs",files:["next.config.js","next.config.ts","next.config.mjs","next.config.cjs"],packageJsonDeps:["next"],packageJsonDevDeps:["next"],priority:100},{type:"angular",files:["angular.json","angular-cli.json"],packageJsonDeps:["@angular/core"],packageJsonDevDeps:["@angular/cli","@angular/core"],priority:90},{type:"vue",files:["vue.config.js","vue.config.ts","vite.config.js","vite.config.ts"],packageJsonDeps:["vue"],packageJsonDevDeps:["vue","@vitejs/plugin-vue","vite"],dirs:[".nuxt"],priority:85},{type:"react",files:["react-scripts"],packageJsonDeps:["react"],packageJsonDevDeps:["react","react-scripts","@vitejs/plugin-react","vite"],dirs:["node_modules/react"],priority:80},{type:"typescript",files:["tsconfig.json","tsconfig.app.json","tsconfig.base.json"],priority:70},{type:"nodejs",files:["package.json"],priority:75},{type:"rust",files:["Cargo.toml","Cargo.lock"],priority:100},{type:"python",files:["requirements.txt","setup.py","pyproject.toml","Pipfile","poetry.lock","manage.py","setup.cfg","Pipfile.lock"],dirs:["__pycache__"],priority:100},{type:"go",files:["go.mod","go.sum","Gopkg.toml","Gopkg.lock"],priority:100},{type:"java",files:["pom.xml","build.gradle","build.gradle.kts","settings.gradle"],dirs:[".gradle"],priority:100},{type:"csharp",files:["*.csproj","*.sln","project.json","*.fsproj","*.vbproj"],dirs:[".vs"],priority:100},{type:"ruby",files:["Gemfile","Rakefile","Gemfile.lock"],dirs:[".bundle"],priority:100},{type:"php",files:["composer.json","composer.lock","artisan"],dirs:["vendor"],priority:100},{type:"swift",files:["Package.swift","*.xcodeproj","*.xcworkspace"],dirs:[".build"],priority:100},{type:"kotlin",files:["build.gradle.kts","settings.gradle.kts"],dirs:[".gradle"],priority:100},{type:"dart",files:["pubspec.yaml","pubspec.yml","pubspec.lock"],dirs:[".dart_tool"],priority:100}],w={nodejs:{exclude_dirs:["node_modules",".next",".nuxt",".cache","dist","build",".turbo",".vercel",".output"],exclude_extensions:[],exclude_names:["package-lock.json","yarn.lock","pnpm-lock.yaml"]},nextjs:{exclude_dirs:["node_modules",".next",".vercel","out","dist","build",".turbo"],exclude_extensions:[],exclude_names:["package-lock.json","yarn.lock","pnpm-lock.yaml"]},react:{exclude_dirs:["node_modules","build","dist",".cache","coverage",".nyc_output"],exclude_extensions:[],exclude_names:["package-lock.json","yarn.lock","pnpm-lock.yaml"]},vue:{exclude_dirs:["node_modules","dist",".nuxt",".cache","coverage",".output"],exclude_extensions:[],exclude_names:["package-lock.json","yarn.lock","pnpm-lock.yaml"]},angular:{exclude_dirs:["node_modules","dist",".angular","coverage",".nyc_output"],exclude_extensions:[],exclude_names:["package-lock.json","yarn.lock","pnpm-lock.yaml"]},typescript:{exclude_dirs:["node_modules","dist","build",".cache","coverage",".nyc_output"],exclude_extensions:[],exclude_names:["package-lock.json","yarn.lock","pnpm-lock.yaml"]},rust:{exclude_dirs:["target",".cargo"],exclude_extensions:[],exclude_names:["Cargo.lock"]},python:{exclude_dirs:["__pycache__",".pytest_cache",".mypy_cache",".ruff_cache",".venv","venv","env",".env","build","dist",".*\\.egg-info",".tox",".coverage","htmlcov",".hypothesis"],exclude_extensions:["pyc","pyo","pyd","so"],exclude_names:[".python-version","pip-log.txt","pip-delete-this-directory.txt"]},go:{exclude_dirs:["vendor",".cache"],exclude_extensions:[],exclude_names:["go.sum"]},java:{exclude_dirs:["target","build",".gradle","out",".idea",".classpath",".settings"],exclude_extensions:["class","jar","war","ear"],exclude_names:[".project",".*\\.iml"]},csharp:{exclude_dirs:["bin","obj",".vs","packages","TestResults","[Bb]in","[Oo]bj"],exclude_extensions:["dll","exe","pdb"],exclude_names:[]},ruby:{exclude_dirs:["vendor",".bundle","tmp","log"],exclude_extensions:[],exclude_names:["Gemfile.lock"]},php:{exclude_dirs:["vendor","node_modules"],exclude_extensions:[],exclude_names:["composer.lock"]},swift:{exclude_dirs:[".build",".swiftpm","DerivedData"],exclude_extensions:[],exclude_names:["Package.resolved"]},kotlin:{exclude_dirs:["build",".gradle","out",".idea",".classpath",".settings"],exclude_extensions:["class","jar"],exclude_names:[".project",".*\\.iml"]},dart:{exclude_dirs:[".dart_tool","build"],exclude_extensions:[],exclude_names:["pubspec.lock"]},unknown:{exclude_dirs:[],exclude_extensions:[],exclude_names:[]}};function C(e,n,t){if(!e||!n&&!t)return!1;const o={...e.dependencies||{},...e.devDependencies||{}};if(n)for(const e of n)if(o[e])return!0;if(t)for(const e of t)if(o[e])return!0;return!1}function S(e,n){if(!e||!n||!e.scripts)return!1;for(const t of n)if(e.scripts[t])return!0;return!1}function j(e,n){if(n.includes("*"))try{const t=o.readdirSync(e),s=n.replace(/\*/g,".*"),r=new RegExp(`^${s}$`);return t.some(n=>{const t=i.join(e,n);try{const e=o.statSync(t);return(e.isFile()||e.isDirectory())&&r.test(n)}catch{return!1}})}catch{return!1}else{const t=i.join(e,n);try{if(o.existsSync(t)){return o.statSync(t).isFile()}}catch{}}return!1}function z(e,n){const t=i.join(e,n);try{if(o.existsSync(t)){return o.statSync(t).isDirectory()}}catch{}return!1}function E(e,n=2){try{const t=o.readdirSync(e);for(const s of t){const t=i.join(e,s);try{const e=o.statSync(t);if(e.isFile()&&(s.endsWith(".ts")||s.endsWith(".tsx")))return!0;if(e.isDirectory()&&n>0&&!s.startsWith(".")&&"node_modules"!==s&&E(t,n-1))return!0}catch{}}}catch{}return!1}function F(e){const n=i.resolve(e);let t=n;try{o.statSync(n).isFile()&&(t=i.dirname(n))}catch{}const s=new Map,r=function(e){const n=i.join(e,"package.json");try{if(o.existsSync(n)){const e=o.readFileSync(n,"utf-8");return JSON.parse(e)}}catch{}return null}(t);for(const e of L){let n=0;const l=[];for(const o of e.files)j(t,o)&&(n+=30,l.push(`file:${o}`));if(e.dirs)for(const o of e.dirs)z(t,o)&&(n+=20,l.push(`dir:${o}`));if((e.packageJsonDeps||e.packageJsonDevDeps)&&C(r,e.packageJsonDeps,e.packageJsonDevDeps)){n+=50;const t=[...e.packageJsonDeps||[],...e.packageJsonDevDeps||[]];l.push(`dep:${t.join(",")}`)}if(e.packageJsonScripts&&S(r,e.packageJsonScripts)&&(n+=15,l.push(`script:${e.packageJsonScripts.join(",")}`)),"typescript"===e.type&&(j(t,"tsconfig.json")&&(n+=30,l.push("file:tsconfig.json")),E(t)&&(n+=20,l.push("typescript-files")),r&&j(t,"package.json"))){C(r,["express","koa","fastify","nest","@nestjs/core"],["ts-node","ts-node-dev"])&&(n=Math.floor(.5*n),l.push("nodejs-backend-penalty"))}if("nodejs"===e.type&&j(t,"package.json")&&(j(t,"tsconfig.json")||E(t))&&(n+=40,l.push("nodejs-with-typescript")),"react"===e.type)try{const e=o.readdirSync(t);e.some(e=>{const n=i.join(t,e);try{return o.statSync(n).isFile()&&(e.endsWith(".jsx")||e.endsWith(".tsx"))}catch{return!1}})&&(n+=15,l.push("jsx-files"))}catch{}n=Math.floor(n*(1+e.priority/100)),n>0&&s.set(e.type,{type:e.type,score:n,indicators:l})}if(r){if(!Array.from(s.keys()).some(e=>"react"===e||"vue"===e||"angular"===e||"nextjs"===e)){const e=j(t,"tsconfig.json")||E(t);if(e&&j(t,"package.json")){C(r,["express","koa","fastify","nest","@nestjs/core"],["ts-node","ts-node-dev"])&&(s.has("nodejs")||s.set("nodejs",{type:"nodejs",score:55,indicators:["package.json","nodejs-backend-with-typescript"]})),s.has("typescript")||s.set("typescript",{type:"typescript",score:40,indicators:["tsconfig-or-ts-files"]})}else e?s.has("typescript")||s.set("typescript",{type:"typescript",score:40,indicators:["tsconfig-or-ts-files"]}):s.has("nodejs")||s.set("nodejs",{type:"nodejs",score:30,indicators:["package.json"]})}}return Array.from(s.values()).sort((e,n)=>n.score-e.score)}function D(e){const n=F(e);return 0===n.length?"unknown":n[0].type}function T(e){const n=[];let t="",o="",s=!1;switch(e.toLowerCase().replace(/^\./,"")){case"js":case"jsx":case"ts":case"tsx":case"c":case"cpp":case"cc":case"cxx":case"h":case"hpp":case"java":case"cs":case"php":case"swift":case"go":case"rust":case"rs":case"dart":case"kt":case"scala":case"sc":n.push("//"),t="/*",o="*/",s=!0;break;case"sh":case"bash":case"zsh":case"fish":case"py":case"python":case"rb":case"ruby":case"r":case"pl":case"perl":case"yaml":case"yml":case"toml":case"conf":case"ini":case"cfg":case"dockerfile":case"makefile":case"make":case"cmake":case"ps1":case"psm1":case"ex":case"exs":n.push("#");break;case"html":case"htm":case"xml":case"xhtml":case"svg":n.push("\x3c!--"),t="\x3c!--",o="--\x3e",s=!0;break;case"css":case"scss":case"sass":case"less":case"styl":t="/*",o="*/",s=!0;break;case"sql":n.push("--"),t="/*",o="*/",s=!0;break;case"lua":n.push("--"),t="--[[",o="]]",s=!0;break;case"pas":case"p":case"pp":case"fs":case"fsi":case"fsx":n.push("//"),t="(*",o="*)",s=!0;break;case"hs":case"lhs":n.push("--"),t="{-",o="-}",s=!0;break;case"erl":case"hrl":case"m":case"matlab":n.push("%");break;case"vhd":case"vhdl":n.push("--");break;case"bat":case"cmd":n.push("::");break;case"vbs":n.push("'");break;case"clj":case"cljs":case"cljc":case"lisp":case"lsp":case"el":case"rkt":case"rktl":n.push(";");break;case"ml":case"mli":t="(*",o="*)",s=!0;break;default:n.push("//","#","--")}return{singleLine:n,multiLineStart:t,multiLineEnd:o,supportsMultiLine:s}}function O(e,n,t){let o=0,s=!1,i=0,r=-1;const l=[];let c=-1,a=-1;for(;i<e.length;){const d=e[i];if(s)s=!1,i++;else if("\\"!==d||0===o){if(3===o&&"$"===d&&i+1<e.length&&"{"===e[i+1]){let n=1;for(i+=2;i<e.length&&n>0;)"{"===e[i]?n++:"}"===e[i]&&n--,i++;continue}if(0===o){if('"'===d)o=2;else if("'"===d)o=1;else if("`"===d)o=3;else if("/"===d&&i+1<e.length){const t=e[i+1];if("/"===t||"*"===t){for(const t of n.singleLine)if(e.substring(i).startsWith(t)){l.push({pos:i,marker:t});break}n.supportsMultiLine&&-1===c&&e.substring(i).startsWith(n.multiLineStart)&&(c=i),i++;continue}{const n=i>0?e[i-1]:" ";/[\s,;=([{!&|?:]/.test(n)&&(o=4,r=i)}}}else if(2===o&&'"'===d)o=0;else if(1===o&&"'"===d)o=0;else if(3===o&&"`"===d)o=0;else if(4===o){if("\\"===d){i+1<e.length?i+=2:i++;continue}if("/"===d)if(i+1<e.length){const n=e[i+1];if(/[gimsuvy]/.test(n)){let n=i+1;for(;n<e.length&&/[gimsuvy]/.test(e[n]);)n++;(n>=e.length||!/[a-zA-Z0-9_]/.test(e[n]))&&(o=0,r=-1,i=n-1)}else/[a-zA-Z0-9_]/.test(n)||(o=0,r=-1)}else o=0,r=-1;else if(" "===d||"\t"===d){const n=i-r-1;let t=!0;for(let n=r+1;n<i;n++)if(" "!==e[n]&&"\t"!==e[n]){t=!1;break}if(t&&n<=2){let n=i+1;for(;n<e.length&&(" "===e[n]||"\t"===e[n]);)n++;n<e.length&&/[0-9;,)}\]\]]/.test(e[n])&&(o=0,r=-1)}}else/[;,)}\]\]]/.test(d)&&(o=0,r=-1)}if(0===o){for(const t of n.singleLine)if(e.substring(i).startsWith(t)){l.push({pos:i,marker:t});break}if(n.supportsMultiLine&&-1===c&&e.substring(i).startsWith(n.multiLineStart)&&(c=i),n.supportsMultiLine&&t&&e.substring(i).startsWith(n.multiLineEnd)){a=i;break}}i++}else s=!0,i++}if(t){if(-1!==a){const t=e.substring(0,a).trim(),o=e.substring(a+n.multiLineEnd.length).trim();return{commentStart:0,commentEnd:a+n.multiLineEnd.length,isMultiLine:!0,endsMultiLine:!0,commentMarker:n.multiLineEnd,hasCodeBefore:t.length>0,hasCodeAfter:o.length>0}}return{commentStart:0,commentEnd:e.length,isMultiLine:!0,endsMultiLine:!1,commentMarker:n.multiLineEnd,hasCodeBefore:!1,hasCodeAfter:!1}}if(n.supportsMultiLine&&-1!==c){const t=e.substring(0,c).trim(),o=e.indexOf(n.multiLineEnd,c),s=-1!==o,i=s?e.substring(o+n.multiLineEnd.length).trim():"";return{commentStart:c,commentEnd:s?o+n.multiLineEnd.length:e.length,isMultiLine:!0,endsMultiLine:s,commentMarker:n.multiLineStart,hasCodeBefore:t.length>0,hasCodeAfter:i.length>0}}if(l.length>0){const n=l[0],t=e.substring(0,n.pos).trim();return{commentStart:n.pos,commentEnd:e.length,isMultiLine:!1,endsMultiLine:!1,commentMarker:n.marker,hasCodeBefore:t.length>0,hasCodeAfter:!1}}return null}function M(e){try{const n=o.readFileSync(e,"utf-8"),t=n.split(/\r?\n/),s=T(i.extname(e));let r=!1;const l=[];let c=!1;for(const e of t){const n=e,t=R(e,s,r);t.line!==n&&(c=!0),!t.line.trim()&&t.isEmpty||l.push(t.line),r=t.inMultiLineComment}const a=l.join("\n");return c||a!==n?(o.writeFileSync(e,a,"utf-8"),{success:!0,commentsFound:!0}):{success:!0,commentsFound:!1}}catch{return{success:!1,commentsFound:!1}}}function I(e){const n=e.replace(/^\/\//,"").replace(/^\/\*/,"").replace(/\*\/$/,"").trim().toLowerCase();return n.startsWith("eslint")||n.startsWith("@eslint")||n.includes("eslint-disable")||n.includes("eslint-enable")}function R(e,n,t){if(t){const t=e.indexOf(n.multiLineEnd);if(-1!==t){const o=e.substring(0,t+n.multiLineEnd.length),s=e.substring(t+n.multiLineEnd.length);return I(o)?{line:e.trimEnd(),inMultiLineComment:!1,isEmpty:0===e.trim().length}:{line:s.trimEnd(),inMultiLineComment:!1,isEmpty:0===s.trim().length}}return I(e)?{line:e.trimEnd(),inMultiLineComment:!0,isEmpty:0===e.trim().length}:{line:"",inMultiLineComment:!0,isEmpty:!0}}let o=0,s=!1,i=0,r=-1;const l=[];let c=-1;for(;i<e.length;){const t=e[i];if(s)s=!1,i++;else if("\\"!==t||0===o){if(3===o&&"$"===t&&i+1<e.length&&"{"===e[i+1]){let n=1;for(i+=2;i<e.length&&n>0;)"{"===e[i]?n++:"}"===e[i]&&n--,i++;continue}if(0===o){if('"'===t)o=2;else if("'"===t)o=1;else if("`"===t)o=3;else if("/"===t&&i+1<e.length){const t=e[i+1];if("/"===t||"*"===t){for(const t of n.singleLine)if(e.substring(i).startsWith(t)){l.push(i);break}n.supportsMultiLine&&-1===c&&e.substring(i).startsWith(n.multiLineStart)&&(c=i),i++;continue}{const n=i>0?e[i-1]:" ";/[\s,;=([{!&|?:]/.test(n)&&(o=4,r=i)}}}else if(2===o&&'"'===t)o=0;else if(1===o&&"'"===t)o=0;else if(3===o&&"`"===t)o=0;else if(4===o){if("\\"===t){i+1<e.length?i+=2:i++;continue}if("/"===t)if(i+1<e.length){const n=e[i+1];if(/[gimsuvy]/.test(n)){let n=i+1;for(;n<e.length&&/[gimsuvy]/.test(e[n]);)n++;(n>=e.length||!/[a-zA-Z0-9_]/.test(e[n]))&&(o=0,r=-1,i=n-1)}else/[a-zA-Z0-9_]/.test(n)||(o=0,r=-1)}else o=0,r=-1;else if(" "===t||"\t"===t){const n=i-r-1;let t=!0;for(let n=r+1;n<i;n++)if(" "!==e[n]&&"\t"!==e[n]){t=!1;break}if(t&&n<=2){let n=i+1;for(;n<e.length&&(" "===e[n]||"\t"===e[n]);)n++;n<e.length&&/[0-9;,)}\]\]]/.test(e[n])&&(o=0,r=-1)}}else/[;,)}\]\]]/.test(t)&&(o=0,r=-1)}if(0===o){for(const t of n.singleLine)if(e.substring(i).startsWith(t)){l.push(i);break}n.supportsMultiLine&&-1===c&&e.substring(i).startsWith(n.multiLineStart)&&(c=i)}i++}else s=!0,i++}if(-1!==c){const t=e.substring(0,c),o=e.indexOf(n.multiLineEnd,c+n.multiLineStart.length);if(-1!==o){const s=e.substring(c,o+n.multiLineEnd.length),i=e.substring(o+n.multiLineEnd.length);if(I(s))return{line:e.trimEnd(),inMultiLineComment:!1,isEmpty:0===e.trim().length};const r=(t+i).trimEnd();return{line:r,inMultiLineComment:!1,isEmpty:0===r.length}}{if(I(e.substring(c)))return{line:e.trimEnd(),inMultiLineComment:!0,isEmpty:0===e.trim().length};const n=t.trimEnd();return{line:n,inMultiLineComment:!0,isEmpty:0===n.length}}}if(l.length>0){const t=l[0];for(const o of n.singleLine)if(e.substring(t).startsWith(o)){if(I(e.substring(t+o.length)))return{line:e.trimEnd(),inMultiLineComment:!1,isEmpty:0===e.trim().length};break}const o=e.substring(0,t).trimEnd();return{line:o,inMultiLineComment:!1,isEmpty:0===o.length}}return{line:e,inMultiLineComment:!1,isEmpty:!1}}function q(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 B(e){return{codeLines:e.code_lines||0,commentLines:e.comment_lines||0,fullLineComments:e.full_line_comments||0,inlineComments:e.inline_comments||0}}function W(e,n,t,o,s){let i=` (${e} code, ${n} comments`;return void 0!==s&&s>0&&(i+=`, ${s} blank`),(t>0||o>0)&&(i+=`: ${t} full-line, ${o} inline`),i+=")",i}function A(e,n,t,o,s){let i=` ${a.gray(`(${a.blue(e)} code, ${a.cyan(n)} comments`)}`;return void 0!==s&&s>0&&(i+=a.gray(`, ${a.gray(s)} blank`)),(t>0||o>0)&&(i+=a.gray(`: ${a.yellow(t)} full-line, ${a.magenta(o)} inline`)),i+=a.gray(")"),i}function J(e,n){return(e.comments||e.show_stats)&&!e.files_only&&n}function N(e,n,t){return{sizeStr:q(e),linesStr:null===n||t.files_only?"":` | ${n} lines`}}function P(e){const n={};for(const t of e)n[t.directory]||(n[t.directory]=[]),n[t.directory].push(t);return n}function U(e){try{return o.statSync(e.directory).isFile()}catch{return!1}}function G(e){const n=e.directory;try{if(o.statSync(n).isFile())return i.basename(n)}catch{}return"."===n?"current":n}function V(e){return{nodejs:"Node.js",rust:"Rust",python:"Python",go:"Go",java:"Java",csharp:"C#",ruby:"Ruby",php:"PHP",swift:"Swift",kotlin:"Kotlin",dart:"Dart",typescript:"TypeScript",vue:"Vue.js",react:"React",angular:"Angular",nextjs:"Next.js",unknown:"Unknown"}[e]||e}function K(e,n){return[...e.details].sort((e,n)=>n.size-e.size).slice(0,n)}function H(e,n){const t={};for(const n of e.details)t[n.directory]||(t[n.directory]={fileCount:0,totalSize:0,totalLines:0}),t[n.directory].fileCount+=1,t[n.directory].totalSize+=n.size,null!==n.lines&&(t[n.directory].totalLines+=n.lines);return Object.entries(t).map(([e,n])=>({directory:e,...n})).sort((e,n)=>n.fileCount-e.fileCount).slice(0,n)}function Q(e,n,t){switch(e){case"human":return 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".padStart(37).padEnd(60)+"\n",t+="=".repeat(60)+"\n\n",t+=`Directory: ${G(n)}\n`,n.lines_only||(U(n)?t+=`\nSize: ${q(e.total_size)}\n`:(t+=`\nTotal Files: ${e.total_files}\n`,t+=`\nTotal Files Size: ${q(e.total_size)}\n`)),!n.files_only&&(t+=`\nTotal Lines: ${e.total_lines}\n`,(n.comments||n.show_stats)&&void 0!==e.total_comment_lines&&(t+=`Total Comment Lines: ${e.total_comment_lines}\n`,void 0!==e.total_full_line_comments&&(t+=` - Full Line Comments: ${e.total_full_line_comments}\n`),void 0!==e.total_inline_comments&&(t+=` - Inline Comments: ${e.total_inline_comments}\n`),void 0!==e.total_code_lines&&(t+=`Total Code Lines: ${e.total_code_lines}\n`),void 0!==e.total_blank_lines&&e.total_blank_lines>0&&(t+=`Total Blank Lines: ${e.total_blank_lines}\n`),n.code_vs_comments&&void 0!==e.total_code_lines))&&(t+=`Code vs Comments Ratio: ${e.total_code_lines>0?(e.total_comment_lines/e.total_code_lines).toFixed(2):"0.00"}:1 (${e.total_comment_lines} comments per ${e.total_code_lines} code 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 s of o){const o=e.files_by_extension[s],i=e.size_by_extension[s]||0,r=e.lines_by_extension[s]||0;if(t+=` ${s}: ${o} files`,n.lines_only||(t+=`, ${q(i)}`),!n.files_only&&(t+=`, ${r} lines`,J(n,void 0!==e.comment_lines_by_extension?.[s]))){const o=B({comment_lines:e.comment_lines_by_extension?.[s]||0,code_lines:e.code_lines_by_extension?.[s]||0,full_line_comments:e.full_line_comments_by_extension?.[s]||0,inline_comments:e.inline_comments_by_extension?.[s]||0}),i=e.blank_lines_by_extension?.[s]||0;t+=W(o.codeLines,o.commentLines,o.fullLineComments,o.inlineComments,i),n.code_vs_comments&&o.codeLines>0&&(t+=` [${(o.commentLines/o.codeLines).toFixed(2)}:1]`)}t+="\n"}}if(n.show_stats&&e.details.length>0){t+="\nFiles by Directory:\n",t+="-".repeat(60)+"\n";const o=P(e.details),s=Object.keys(o).sort();for(const e of s){const s=o[e];t+=`Directory: ${e}\n`;for(const e of s){const o=q(e.size),s=null===e.lines||n.files_only?"":` | ${e.lines} lines`;let i="";if(J(n,void 0!==e.comment_lines&&null!==e.comment_lines)){const n=B(e);i=W(n.codeLines,n.commentLines,n.fullLineComments,n.inlineComments,e.blank_lines||void 0)}t+=` - ${e.name} (${e.extension}, ${o}${s}${i})\n`}t+="\n"}}if(n.top_files&&n.top_files>0){const o=K(e,n.top_files);t+=`\nTop ${n.top_files} Largest Files:\n`,t+="-".repeat(60)+"\n";for(const e of o){const{sizeStr:o,linesStr:s}=N(e.size,e.lines,n);t+=` ${o.padEnd(10)} ${e.name} (${e.extension})${s}\n`}}if(n.top_dirs&&n.top_dirs>0){const o=H(e,n.top_dirs);t+=`\nTop ${n.top_dirs} Directories (by file count):\n`,t+="-".repeat(60)+"\n";for(const e of o){const o=q(e.totalSize),s=n.files_only?"":` | ${e.totalLines} lines`;t+=` ${e.fileCount.toString().padEnd(5)} files ${e.directory} (${o}${s})\n`}}return t+="\n",t}(n,t);case"json":return function(e,n){const t=D(n.directory),o={directory:G(n)};if("unknown"!==t&&(o.project_type=t,o.project_type_display=V(t)),U(n)||(o.files=e.total_files,o.size=e.total_size,o.size_formatted=q(e.total_size)),n.files_only||(o.lines=e.total_lines,n.comments&&(o.comment_lines=e.total_comment_lines||0,o.code_lines=e.total_code_lines||0,o.blank_lines=e.total_blank_lines||0,o.full_line_comments=e.total_full_line_comments||0,o.inline_comments=e.total_inline_comments||0,n.code_vs_comments&&void 0!==e.total_code_lines&&(o.code_vs_comments_ratio=e.total_code_lines>0?parseFloat((e.total_comment_lines/e.total_code_lines).toFixed(2)):0))),n.show_stats){const t={};for(const o of Object.keys(e.files_by_extension))t[o]={files:e.files_by_extension[o],lines:e.lines_by_extension[o]||0,size:e.size_by_extension[o]||0},n.comments&&(t[o].comment_lines=e.comment_lines_by_extension?.[o]||0,t[o].code_lines=e.code_lines_by_extension?.[o]||0,t[o].blank_lines=e.blank_lines_by_extension?.[o]||0,t[o].full_line_comments=e.full_line_comments_by_extension?.[o]||0,t[o].inline_comments=e.inline_comments_by_extension?.[o]||0,n.code_vs_comments&&e.code_lines_by_extension?.[o]&&e.code_lines_by_extension[o]>0&&(t[o].code_vs_comments_ratio=parseFloat(((e.comment_lines_by_extension[o]||0)/e.code_lines_by_extension[o]).toFixed(2))));o.by_extension=t}if(n.top_files&&n.top_files>0){const t=K(e,n.top_files);o.top_files=t.map(e=>({name:e.name,directory:e.directory,extension:e.extension,size:e.size,size_formatted:q(e.size),lines:e.lines}))}if(n.top_dirs&&n.top_dirs>0){const t=H(e,n.top_dirs);o.top_directories=t.map(e=>({directory:e.directory,file_count:e.fileCount,total_size:e.totalSize,total_size_formatted:q(e.totalSize),total_lines:e.totalLines}))}return JSON.stringify(o,null,2)}(n,t);case"csv":return function(e,n){const t=D(n.directory);let o=`# Directory,${G(n)}\n`;if("unknown"!==t&&(o+=`# Project Type,${V(t)}\n`),n.comments){o+="Extension,Files,Lines,Code Lines,Comment Lines,Blank Lines,Size",n.code_vs_comments&&(o+=",Code vs Comments Ratio"),o+="\n";for(const t of Object.keys(e.files_by_extension)){const s=e.files_by_extension[t],i=e.lines_by_extension[t]||0,r=e.code_lines_by_extension?.[t]||0,l=e.comment_lines_by_extension?.[t]||0;o+=`${t},${s},${i},${r},${l},${e.blank_lines_by_extension?.[t]||0},${e.size_by_extension[t]||0}`,n.code_vs_comments&&r>0&&(o+=`,${((l||0)/r).toFixed(2)}`),o+="\n"}}else{o+="Extension,Files,Lines,Size\n";for(const n of Object.keys(e.files_by_extension))o+=`${n},${e.files_by_extension[n]},${e.lines_by_extension[n]||0},${e.size_by_extension[n]||0}\n`}return o}(n,t);case"tsv":return function(e,n){const t=D(n.directory);let o=`# Directory\t${G(n)}\n`;if("unknown"!==t&&(o+=`# Project Type\t${V(t)}\n`),n.comments){o+="Extension\tFiles\tLines\tCode Lines\tComment Lines\tBlank Lines\tSize",n.code_vs_comments&&(o+="\tCode vs Comments Ratio"),o+="\n";for(const t of Object.keys(e.files_by_extension)){const s=e.files_by_extension[t],i=e.lines_by_extension[t]||0,r=e.code_lines_by_extension?.[t]||0,l=e.comment_lines_by_extension?.[t]||0;o+=`${t}\t${s}\t${i}\t${r}\t${l}\t${e.blank_lines_by_extension?.[t]||0}\t${e.size_by_extension[t]||0}`,n.code_vs_comments&&r>0&&(o+=`\t${((l||0)/r).toFixed(2)}`),o+="\n"}}else{o+="Extension\tFiles\tLines\tSize\n";for(const n of Object.keys(e.files_by_extension))o+=`${n}\t${e.files_by_extension[n]}\t${e.lines_by_extension[n]||0}\t${e.size_by_extension[n]||0}\n`}return o}(n,t);case"markdown":return function(e,n){const t=D(n.directory);let o="# LocIO Report\n\n";o+=`**Directory:** ${G(n)}\n`,"unknown"!==t&&(o+=`**Project Type:** ${V(t)}\n`),o+="\n",o+="## Summary\n\n",o+="| Metric | Value |\n",o+="|--------|-------|\n",o+=`| Total Files | ${e.total_files} |\n`,o+=`| Total Size | ${q(e.total_size)} |\n`,!n.files_only&&(o+=`| Total Lines | ${e.total_lines} |\n`,n.comments&&void 0!==e.total_comment_lines&&(o+=`| Comment Lines | ${e.total_comment_lines} |\n`,void 0!==e.total_code_lines&&(o+=`| Code Lines | ${e.total_code_lines} |\n`),void 0!==e.total_blank_lines&&e.total_blank_lines>0&&(o+=`| Blank Lines | ${e.total_blank_lines} |\n`),n.code_vs_comments&&void 0!==e.total_code_lines&&e.total_code_lines>0))&&(o+=`| Code vs Comments Ratio | ${(e.total_comment_lines/e.total_code_lines).toFixed(2)}:1 |\n`);if(Object.keys(e.files_by_extension).length>0){o+="\n## Statistics by Extension\n\n",o+="| Extension | Files |",n.lines_only||(o+=" Size |"),n.files_only||(o+=" Lines |",n.comments&&(o+=" Code | Comments |",n.code_vs_comments&&(o+=" Ratio |"))),o+="\n",o+="|----------|-------|",n.lines_only||(o+="------|"),n.files_only||(o+="-------|",n.comments&&(o+="------|-----------|",n.code_vs_comments&&(o+="-------|"))),o+="\n";const t=Object.keys(e.files_by_extension).sort();for(const s of t){const t=e.files_by_extension[s],i=e.size_by_extension[s]||0,r=e.lines_by_extension[s]||0,l=e.code_lines_by_extension?.[s]||0,c=e.comment_lines_by_extension?.[s]||0;o+=`| \`${s}\` | ${t} |`,n.lines_only||(o+=` ${q(i)} |`),!n.files_only&&(o+=` ${r} |`,n.comments)&&(o+=` ${l} | ${c} |`,n.code_vs_comments&&l>0?o+=` ${((c||0)/l).toFixed(2)}:1 |`:n.code_vs_comments&&(o+=" - |")),o+="\n"}}if(n.show_stats&&e.details.length>0){o+="\n## Files by Directory\n\n";const t=P(e.details),s=Object.keys(t).sort();for(const e of s){const s=t[e];o+=`### ${e}\n\n`,o+="| File | Extension | Size |",n.files_only||(o+=" Lines |",(n.comments||n.show_stats)&&(o+=" Code | Comments | Blank | Full-Line | Inline |")),o+="\n",o+="|------|-----------|------|",n.files_only||(o+="-------|",(n.comments||n.show_stats)&&(o+="------|----------|-------|----------|--------|")),o+="\n";for(const e of s)o+=`| ${e.name} | \`${e.extension}\` | ${q(e.size)} |`,!n.files_only&&null!==e.lines&&(o+=` ${e.lines} |`,n.comments||n.show_stats)&&(o+=` ${e.code_lines||0} | ${e.comment_lines||0} | ${e.blank_lines||0} | ${e.full_line_comments||0} | ${e.inline_comments||0} |`),o+="\n";o+="\n"}}if(n.top_files&&n.top_files>0){const t=K(e,n.top_files);o+=`\n## Top ${n.top_files} Largest Files\n\n`,o+="| Size | File | Extension |",n.files_only||(o+=" Lines |"),o+="\n",o+="|------|------|-----------|",n.files_only||(o+="-------|"),o+="\n";for(const e of t)o+=`| ${q(e.size)} | ${e.name} | \`${e.extension}\` |`,n.files_only||null===e.lines||(o+=` ${e.lines} |`),o+="\n";o+="\n"}if(n.top_dirs&&n.top_dirs>0){const t=H(e,n.top_dirs);o+=`\n## Top ${n.top_dirs} Directories (by file count)\n\n`,o+="| Files | Directory | Size |",n.files_only||(o+=" Lines |"),o+="\n",o+="|-------|-----------|------|",n.files_only||(o+="-------|"),o+="\n";for(const e of t)o+=`| ${e.fileCount} | ${e.directory} | ${q(e.totalSize)} |`,n.files_only||(o+=` ${e.totalLines} |`),o+="\n";o+="\n"}return o+="\n---\n\n",o+="*Generated by [LocIO](https://locio.js.org)*\n",o}(n,t);case"html":return function(e,n){const t=D(n.directory),o=Object.keys(e.files_by_extension).sort(),s=o.map(n=>({ext:n,files:e.files_by_extension[n],lines:e.lines_by_extension[n]||0,size:e.size_by_extension[n]||0,codeLines:e.code_lines_by_extension?.[n]||0,commentLines:e.comment_lines_by_extension?.[n]||0,blankLines:e.blank_lines_by_extension?.[n]||0}));return`<!DOCTYPE html>\n<html lang="en">\n<head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n <title>LocIO Report - ${G(n)}</title>\n <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"><\/script>\n <style>\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n min-height: 100vh;\n padding: 20px;\n }\n .container {\n max-width: 1200px;\n margin: 0 auto;\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n overflow: hidden;\n }\n .header {\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n padding: 40px;\n text-align: center;\n }\n .header h1 {\n font-size: 2.5em;\n margin-bottom: 10px;\n }\n .header p {\n opacity: 0.9;\n font-size: 1.1em;\n }\n .content {\n padding: 40px;\n }\n .summary-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 20px;\n margin-bottom: 40px;\n }\n .card {\n background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);\n padding: 25px;\n border-radius: 10px;\n text-align: center;\n box-shadow: 0 4px 6px rgba(0,0,0,0.1);\n }\n .card h3 {\n color: #667eea;\n font-size: 0.9em;\n text-transform: uppercase;\n letter-spacing: 1px;\n margin-bottom: 10px;\n }\n .card .value {\n font-size: 2.5em;\n font-weight: bold;\n color: #2d3748;\n }\n .section {\n margin-bottom: 40px;\n }\n .section h2 {\n color: #2d3748;\n margin-bottom: 20px;\n padding-bottom: 10px;\n border-bottom: 3px solid #667eea;\n }\n .chart-container {\n position: relative;\n height: 400px;\n margin: 20px 0;\n }\n table {\n width: 100%;\n border-collapse: collapse;\n margin-top: 20px;\n background: white;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n }\n th {\n background: #667eea;\n color: white;\n padding: 15px;\n text-align: left;\n font-weight: 600;\n }\n td {\n padding: 12px 15px;\n border-bottom: 1px solid #e2e8f0;\n }\n tr:hover {\n background: #f7fafc;\n }\n .footer {\n text-align: center;\n padding: 20px;\n color: #718096;\n border-top: 1px solid #e2e8f0;\n }\n .footer a {\n color: #667eea;\n text-decoration: none;\n }\n </style>\n</head>\n<body>\n <div class="container">\n <div class="header">\n <h1>LocIO Report</h1>\n <p>Directory: ${G(n)}</p>\n ${"unknown"!==t?`<p>Project Type: <strong>${V(t)}</strong></p>`:""}\n </div>\n <div class="content">\n <div class="summary-cards">\n <div class="card">\n <h3>Total Files</h3>\n <div class="value">${e.total_files}</div>\n </div>\n <div class="card">\n <h3>Total Size</h3>\n <div class="value">${q(e.total_size)}</div>\n </div>\n ${n.files_only?"":`<div class="card">\n <h3>Total Lines</h3>\n <div class="value">${e.total_lines}</div>\n </div>`}\n ${n.comments&&void 0!==e.total_comment_lines?`<div class="card">\n <h3>Comment Lines</h3>\n <div class="value">${e.total_comment_lines}</div>\n </div>\n <div class="card">\n <h3>Code Lines</h3>\n <div class="value">${e.total_code_lines||0}</div>\n </div>\n ${void 0!==e.total_blank_lines&&e.total_blank_lines>0?`<div class="card">\n <h3>Blank Lines</h3>\n <div class="value">${e.total_blank_lines}</div>\n </div>`:""}`:""}\n </div>\n\n ${o.length>0?`<div class="section">\n <h2>π Statistics by Extension</h2>\n <div class="chart-container">\n <canvas id="extensionChart"></canvas>\n </div>\n <table>\n <thead>\n <tr>\n <th>Extension</th>\n <th>Files</th>\n ${n.lines_only?"":"<th>Size</th>"}\n ${n.files_only?"":"<th>Lines</th>"}\n ${n.comments?"<th>Code</th><th>Comments</th><th>Blank</th>":""}\n </tr>\n </thead>\n <tbody>\n ${s.map(e=>`<tr>\n <td><strong>${e.ext}</strong></td>\n <td>${e.files}</td>\n ${n.lines_only?"":`<td>${q(e.size)}</td>`}\n ${n.files_only?"":`<td>${e.lines}</td>`}\n ${n.comments?`<td>${e.codeLines}</td><td>${e.commentLines}</td><td>${e.blankLines}</td>`:""}\n </tr>`).join("")}\n </tbody>\n </table>\n </div>`:""}\n\n ${n.comments&&void 0!==e.total_code_lines&&e.total_code_lines>0?'<div class="section">\n <h2>π¬ Code vs Comments</h2>\n <div class="chart-container">\n <canvas id="commentChart"></canvas>\n </div>\n </div>':""}\n\n ${n.top_files&&n.top_files>0?(()=>{const t=K(e,n.top_files);return`<div class="section">\n <h2>π Top ${n.top_files} Largest Files</h2>\n <table>\n <thead>\n <tr>\n <th>Size</th>\n <th>File</th>\n <th>Extension</th>\n ${n.files_only?"":"<th>Lines</th>"}\n </tr>\n </thead>\n <tbody>\n ${t.map(e=>`<tr>\n <td><strong>${q(e.size)}</strong></td>\n <td>${e.name}</td>\n <td><code>${e.extension}</code></td>\n ${n.files_only||null===e.lines?"":`<td>${e.lines}</td>`}\n </tr>`).join("")}\n </tbody>\n </table>\n </div>`})():""}\n\n ${n.top_dirs&&n.top_dirs>0?(()=>{const t=H(e,n.top_dirs);return`<div class="section">\n <h2>π Top ${n.top_dirs} Directories (by file count)</h2>\n <table>\n <thead>\n <tr>\n <th>Files</th>\n <th>Directory</th>\n <th>Size</th>\n ${n.files_only?"":"<th>Lines</th>"}\n </tr>\n </thead>\n <tbody>\n ${t.map(e=>`<tr>\n <td><strong>${e.fileCount}</strong></td>\n <td>${e.directory}</td>\n <td>${q(e.totalSize)}</td>\n ${n.files_only?"":`<td>${e.totalLines}</td>`}\n </tr>`).join("")}\n </tbody>\n </table>\n </div>`})():""}\n\n ${"html"===n.export?(()=>{const t={};for(const n of e.details)t[n.directory]||(t[n.directory]={fileCount:0,totalSize:0,totalLines:0}),t[n.directory].fileCount+=1,t[n.directory].totalSize+=n.size,null!==n.lines&&(t[n.directory].totalLines+=n.lines);const o=Object.entries(t),s=Math.max(...o.map(([,e])=>e.fileCount)),i=Math.max(...o.map(([,e])=>e.totalSize));return`<div class="section">\n <h2>πΊοΈ Directory Heatmap</h2>\n <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 15px; margin-top: 20px;">\n ${o.map(([e,t])=>{const o=(t.fileCount/s*100+t.totalSize/i*100)/2,r=240-1.2*o;return`<div style="\n background: linear-gradient(135deg, hsl(${r}, 70%, ${85-.3*o}%), hsl(${r}, 70%, ${75-.3*o}%));\n padding: 15px;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n color: ${o>50?"white":"#2d3748"};\n ">\n <div style="font-weight: bold; margin-bottom: 8px; font-size: 0.9em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="${e}">${e.split("/").pop()||e}</div>\n <div style="font-size: 0.8em; opacity: 0.9;">\n <div>π ${t.fileCount} files</div>\n <div>πΎ ${q(t.totalSize)}</div>\n ${n.files_only?"":`<div>π ${t.totalLines} lines</div>`}\n </div>\n </div>`}).join("")}\n </div>\n </div>`})():""}\n </div>\n <div class="footer">\n Generated by <a href="https://locio.js.org">LocIO</a>\n </div>\n </div>\n\n <script>\n ${o.length>0?`const extensionCtx = document.getElementById('extensionChart');\n new Chart(extensionCtx, {\n type: 'bar',\n data: {\n labels: ${JSON.stringify(o)},\n datasets: [\n ${n.files_only?"":`{\n label: 'Lines',\n data: ${JSON.stringify(o.map(n=>e.lines_by_extension[n]||0))},\n backgroundColor: 'rgba(102, 126, 234, 0.8)',\n borderColor: 'rgba(102, 126, 234, 1)',\n borderWidth: 2\n },`}\n {\n label: 'Files',\n data: ${JSON.stringify(o.map(n=>e.files_by_extension[n]))},\n backgroundColor: 'rgba(118, 75, 162, 0.8)',\n borderColor: 'rgba(118, 75, 162, 1)',\n borderWidth: 2\n }\n ]\n },\n options: {\n responsive: true,\n maintainAspectRatio: false,\n plugins: {\n legend: {\n position: 'top',\n },\n title: {\n display: true,\n text: 'Files and Lines by Extension'\n }\n }\n }\n });`:""}\n\n ${n.comments&&void 0!==e.total_code_lines&&e.total_code_lines>0?`const commentCtx = document.getElementById('commentChart');\n new Chart(commentCtx, {\n type: 'doughnut',\n data: {\n labels: ['Code Lines', 'Comment Lines'],\n datasets: [{\n data: [${e.total_code_lines}, ${e.total_comment_lines||0}],\n backgroundColor: [\n 'rgba(102, 126, 234, 0.8)',\n 'rgba(118, 75, 162, 0.8)'\n ],\n borderColor: [\n 'rgba(102, 126, 234, 1)',\n 'rgba(118, 75, 162, 1)'\n ],\n borderWidth: 2\n }]\n },\n options: {\n responsive: true,\n maintainAspectRatio: false,\n plugins: {\n legend: {\n position: 'bottom',\n },\n title: {\n display: true,\n text: 'Code vs Comments Distribution'\n }\n }\n }\n });`:""}\n <\/script>\n</body>\n</html>`}(n,t)}}function Y(e,n,t){const o=function(e){switch(e){case"human":return"txt";case"json":return"json";case"csv":return"csv";case"tsv":return"tsv";case"markdown":return"md";case"html":return"html"}}(e);let s;return s=Array.isArray(n.export)&&n.export.length>1&&void 0!==t?`LocIO-report-${t+1}.${o}`:`LocIO-report.${o}`,n.export_path?i.join(n.export_path,s):s}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"+a.cyan("=".repeat(60))),console.log(a.cyan.bold("LocIO RESULTS".padStart(37).padEnd(60))),console.log(a.cyan("=".repeat(60))),console.log(`\n${a.green.bold("Directory:")} ${G(n)}`),n.lines_only||(U(n)?console.log(`\n${a.green.bold("Size:")} ${a.white(q(e.total_size))}`):(console.log(`\n${a.green.bold("Total Files:")} ${a.yellow(e.total_files)}`),console.log(`\n${a.green.bold("Total Files Size:")} ${a.white(q(e.total_size))}`))),!n.files_only&&(console.log(`\n${a.green.bold("Total Lines:")} ${a.yellow(e.total_lines)}`),(n.comments||n.show_stats)&&void 0!==e.total_comment_lines&&(console.log(`\n${a.green.bold("Total Comment Lines:")} ${a.cyan(e.total_comment_lines)}`),void 0!==e.total_full_line_comments&&console.log(` ${a.gray("β")} ${a.green("Full Line Comments:")} ${a.cyan(e.total_full_line_comments)}`),void 0!==e.total_inline_comments&&console.log(` ${a.gray("β")} ${a.green("Inline Comments:")} ${a.cyan(e.total_inline_comments)}`),void 0!==e.total_code_lines&&console.log(`\n${a.green.bold("Total Code Lines:")} ${a.blue(e.total_code_lines)}`),void 0!==e.total_blank_lines&&e.total_blank_lines>0&&console.log(`\n${a.green.bold("Total Blank Lines:")} ${a.gray(e.total_blank_lines)}`),n.code_vs_comments&&void 0!==e.total_code_lines))){const n=e.total_code_lines>0?(e.total_comment_lines/e.total_code_lines).toFixed(2):"0.00";console.log(`\n${a.green.bold("Code vs Comments Ratio:")} ${a.magenta(n)}:1 ${a.gray(`(${e.total_comment_lines} comments per ${e.total_code_lines} code lines)`)}`)}if(Object.keys(e.files_by_extension).length>0){const n=Object.keys(e.files_by_extension).sort();console.log(`\n${a.green.bold("Extensions:")} ${a.white(n.join(", "))}`)}if(n.show_stats&&Object.keys(e.files_by_extension).length>0){console.log(`\n${a.cyan.bold("Statistics by Extension:")}`),console.log(a.gray("-".repeat(60)));const t=Object.keys(e.files_by_extension).sort();for(const o of t){const t=e.files_by_extension[o],s=e.size_by_extension[o]||0,i=e.lines_by_extension[o]||0;let r=` ${a.white(o)}: ${a.yellow(t)} files`;if(n.lines_only||(r+=`, ${a.white(q(s))}`),!n.files_only&&(r+=`, ${a.yellow(i)} lines`,J(n,void 0!==e.comment_lines_by_extension?.[o]))){const t=B({comment_lines:e.comment_lines_by_extension?.[o]||0,code_lines:e.code_lines_by_extension?.[o]||0,full_line_comments:e.full_line_comments_by_extension?.[o]||0,inline_comments:e.inline_comments_by_extension?.[o]||0}),s=e.blank_lines_by_extension?.[o]||0;if(r+=A(t.codeLines,t.commentLines,t.fullLineComments,t.inlineComments,s),n.code_vs_comments&&t.codeLines>0){const e=(t.commentLines/t.codeLines).toFixed(2);r+=` ${a.magenta(`[${e}:1]`)}`}}console.log(r)}}if(n.show_stats&&e.details.length>0){console.log(`\n${a.cyan.bold("Files by Directory:")}`),console.log(a.gray("-".repeat(60)));const t=P(e.details),o=Object.keys(t).sort();for(const e of o){const o=t[e];console.log(a.green.bold(`Directory: ${e}`));for(const e of o){const t=q(e.size),o=null===e.lines||n.files_only?"":` | ${e.lines} lines`;let s="";if(J(n,void 0!==e.comment_lines&&null!==e.comment_lines)){const n=B(e);s=A(n.codeLines,n.commentLines,n.fullLineComments,n.inlineComments,e.blank_lines||void 0)}console.log(` - ${a.white(e.name)} (${a.blue(e.extension)}, ${a.white(t)}${o}${s})`)}console.log()}}if(n.top_files&&n.top_files>0){const t=K(e,n.top_files);console.log(`\n${a.cyan.bold(`Top ${n.top_files} Largest Files:`)}`),console.log(a.gray("-".repeat(60)));for(const e of t){const{sizeStr:t,linesStr:o}=N(e.size,e.lines,n);console.log(` ${a.yellow(t.padEnd(10))} ${a.white(e.name)} ${a.blue(`(${e.extension})`)}${o}`)}}if(n.top_dirs&&n.top_dirs>0){const t=H(e,n.top_dirs);console.log(`\n${a.cyan.bold(`Top ${n.top_dirs} Directories (by file count):`)}`),console.log(a.gray("-".repeat(60)));for(const e of t){const t=q(e.totalSize),o=n.files_only?"":` | ${e.totalLines} lines`;console.log(` ${a.yellow(e.fileCount.toString().padEnd(5))} files ${a.white(e.directory)} ${a.gray(`(${t}${o})`)}`)}}console.log()}}(e,n):function(e,n){const t=Array.isArray(n.export)?n.export:[n.export||"human"];for(let s=0;s<t.length;s++){const r=t[s],l=Q(r,e,n),c=Y(r,n,s);try{let e;e=n.export_path?n.export_path:i.dirname(c),"."!==e&&e!==c&&o.mkdirSync(e,{recursive:!0}),o.writeFileSync(c,l,"utf-8"),n.quiet||console.log(`Report written to ${c}`)}catch(e){const n=(e instanceof Error?e:new Error(String(e))).message||String(e);let t="";t=n.includes("ENOENT")?`The directory for "${c}" does not exist.\n - Ensure the parent directory exists\n - Check if the path is correct`:n.includes("EACCES")||n.includes("permission")?`Permission denied when writing to "${c}".\n - Check write permissions for the directory\n - Try running with appropriate permissions\n - Use a different output directory`:n.includes("ENOSPC")?"Insufficient disk space.\n - Free up disk space\n - Choose a different location":"Check if the path is valid and you have write permissions.",console.error(`\nβ Failed to create report file ${c}`),console.error(`π Error: ${n}`),t&&console.error(`\nπ‘ Suggestion:\n${t}`)}}}(e,n)}function X(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 s=parseFloat(t);return isNaN(s)?y.invalidSizeFormat(e):Math.floor(s*o)}var ee=["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"],ne=["md","markdown","txt","rst","adoc","asciidoc","org","wiki","json","yaml","yml","toml","ini","cfg","conf","config","properties","env","dotenv","csv","tsv","xml","html","htm","xhtml","log","lock","lockfile"];function te(e){try{if(e.max_size){const n=X(e.max_size);if(n instanceof y)return n}if(e.min_size){const n=X(e.min_size);if(n instanceof y)return n}const n=D(e.directory),t=w[n]||w.unknown,o=e.exclude_patterns.map(n=>{try{return new RegExp(n,e.ignore_case?"i":void 0)}catch(e){throw y.invalidRegex(n,e instanceof Error?e:void 0)}}),s=[...e.exclude_extensions.map(e=>e.replace(/^\./,"").toLowerCase()),...t.exclude_extensions.map(e=>e.toLowerCase()),...ee.map(e=>e.toLowerCase())],i=Array.from(new Set(s)).sort(),r=e.include_extensions.map(e=>e.replace(/^\./,"").toLowerCase()),l=[...e.exclude_dirs,...t.exclude_dirs].map(n=>new RegExp(n,e.ignore_case?"i":void 0)),c=e.include_dirs.map(n=>new RegExp(n,e.ignore_case?"i":void 0)),a=[...e.exclude_names,...t.exclude_names].map(n=>new RegExp(n,e.ignore_case?"i":void 0));return{exclude_patterns:o,exclude_extensions:i,include_extensions:r,exclude_dirs:l,include_dirs:c,exclude_names:a,include_names:e.include_names.map(n=>new RegExp(n,e.ignore_case?"i":void 0)),detected_project_type:n}}catch(e){return e instanceof y?e:y.io(`Failed to create filter patterns: ${e instanceof Error?e.message:String(e)}`)}}function oe(e,n,t){const s=e,r=i.basename(e);for(const e of t.exclude_patterns)if(e.test(s))return!0;const l=i.extname(e).replace(/^\./,"").toLowerCase();if(l){for(const e of t.exclude_extensions)if(l===e.toLowerCase())return!0;if(t.include_extensions.length>0){let e=!1;for(const n of t.include_extensions)if(l===n.toLowerCase()){e=!0;break}if(!e)return!0}}else if(t.include_extensions.length>0)return!0;const c=i.dirname(e);for(const e of t.exclude_dirs)if(e.test(c))return!0;if(t.include_dirs.length>0){let e=!1;for(const n of t.include_dirs)if(n.test(c)){e=!0;break}if(!e)return!0}for(const e of t.exclude_names)if(e.test(r))return!0;if(t.include_names.length>0){let e=!1;for(const n of t.include_names)if(n.test(r)){e=!0;break}if(!e)return!0}if(n.no_hidden&&r.startsWith("."))return!0;try{const t=o.statSync(e).size;if(n.max_size){const e=X(n.max_size);if(!(e instanceof y)&&t>e)return!0}if(n.min_size){const e=X(n.min_size);if(!(e instanceof y)&&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=o.openSync(e,"r"),s=o.readSync(t,n,0,8192,0);if(o.closeSync(t),0===s)return!1;for(let e=0;e<s;e++)if(0===n[e])return!0;return!1}catch{return!1}}(e))}function se(e){return i.extname(e).replace(/^\./,"").toLowerCase()||"no-ext"}function ie(e){const n=null!==e.commentLines,t=null!==e.codeLines&&null!==e.blankLines;return n||t?{totalLines:e.lines||0,commentLines:e.commentLines||0,codeLines:e.codeLines||0,fullLineComments:e.fullLineComments||0,inlineComments:e.inlineComments||0,blankLines:e.blankLines||0}:null}function re(e,n,t,o,s){if(e.total_files+=1,e.total_size+=t,e.files_by_extension[n]=(e.files_by_extension[n]||0)+1,e.size_by_extension[n]=(e.size_by_extension[n]||0)+t,null!==o&&(e.total_lines+=o,e.lines_by_extension[n]=(e.lines_by_extension[n]||0)+o),s){const t=s.codeLines+s.commentLines+s.blankLines;s.totalLines!==t&&(s.totalLines=t),e.total_comment_lines=(e.total_comment_lines||0)+s.commentLines,e.total_code_lines=(e.total_code_lines||0)+s.codeLines,e.total_blank_lines=(e.total_blank_lines||0)+s.blankLines,e.total_full_line_comments=(e.total_full_line_comments||0)+s.fullLineComments,e.total_inline_comments=(e.total_inline_comments||0)+s.inlineComments,e.comment_lines_by_extension[n]=(e.comment_lines_by_extension[n]||0)+s.commentLines,e.code_lines_by_extension[n]=(e.code_lines_by_extension[n]||0)+s.codeLines,e.blank_lines_by_extension||(e.blank_lines_by_extension={}),e.blank_lines_by_extension[n]=(e.blank_lines_by_extension[n]||0)+s.blankLines,e.full_line_comments_by_extension[n]=(e.full_line_comments_by_extension[n]||0)+s.fullLineComments,e.inline_comments_by_extension[n]=(e.inline_comments_by_extension[n]||0)+s.inlineComments}}function le(e,n){const t=i.extname(e).replace(/^\./,"").toLowerCase(),s=ne.map(e=>e.toLowerCase()).includes(t);if(n.comments){if(!s){const n=function(e){try{const n=o.readFileSync(e,"utf-8").split(/\r?\n/),t=T(i.extname(e));let s=n.length,r=0,l=0,c=0,a=0,d=0,m=!1;for(const e of n){if(0===e.trim().length){m?(l++,c++):d++;continue}const n=O(e,t,m);n?(n.isMultiLine&&(m=!n.endsMultiLine),n.hasCodeBefore?(a++,r++,n.hasCodeAfter):(c++,n.hasCodeAfter&&r++),l++):m?(l++,c++):r++}return{totalLines:s,codeLines:r,commentLines:l,fullLineComments:c,inlineComments:a,blankLines:d}}catch{return null}}(e);if(n)return{lines:n.totalLines,commentLines:n.commentLines,codeLines:n.codeLines,fullLineComments:n.fullLineComments,inlineComments:n.inlineComments,blankLines:n.blankLines,error:null}}const n=function(e){try{const n=o.readFileSync(e,"utf-8").split(/\r?\n/);let t=0,s=0;for(const e of n)0===e.trim().length?t++:s++;return{total:n.length,blank:t,code:s}}catch(n){return y.io(`Failed to read file: ${e}`,n instanceof Error?n:void 0)}}(e);return h(n)?{lines:null,commentLines:null,codeLines:null,fullLineComments:null,inlineComments:null,blankLines:null,error:n}:{lines:n.total,commentLines:0,codeLines:n.code,fullLineComments:0,inlineComments:0,blankLines:n.blank,error:null}}const r=function(e){try{return o.readFileSync(e,"utf-8").split(/\r?\n/).length}catch(n){return y.io(`Failed to read file: ${e}`,n instanceof Error?n:void 0)}}(e);return h(r)?{lines:null,commentLines:null,codeLines:null,fullLineComments:null,inlineComments:null,blankLines:null,error:r}:{lines:r,commentLines:null,codeLines:null,fullLineComments:null,inlineComments:null,blankLines:null,error:null}}function ce(e,n,t,o,s,r,l,c,a){return{directory:i.dirname(e),name:i.basename(e),extension:t,size:n,lines:o,comment_lines:s,code_lines:r,blank_lines:a,full_line_comments:l,inline_comments:c}}function ae(e){try{return{metadata:o.statSync(e),error:null}}catch(e){return{metadata:null,error:e instanceof Error?e:new Error(String(e))}}}function de(e,n,t){return i.relative(n,e).split(i.sep).length-1>t}var me=class{constructor(e){f(this,"total"),f(this,"current",0),f(this,"startTime"),f(this,"width",40),f(this,"errors",0),this.total=e,this.startTime=Date.now()}update(e,n=0){this.current=e,this.errors=n,this.render()}increment(e=0){this.current++,e>0&&(this.errors=e),this.render()}formatTime(e){if(e<1e3)return`${e}ms`;if(e<6e4)return`${(e/1e3).toFixed(1)}s`;return`${Math.floor(e/6e4)}m ${Math.floor(e%6e4/1e3)}s`}calculateETA(){if(0===this.current)return"calculating...";const e=Date.now()-this.startTime,n=this.current/e,t=(this.total-this.current)/n;return t<0||!isFinite(t)?"calculating...":this.formatTime(t)}render(){const e=this.total>0?this.current/this.total*100:0,n=e.toFixed(1).padStart(5),t=String(this.current).padStart(String(this.total).length),o=this.errors>0?a.red(` (${this.errors} errors)`):"",s=Date.now()-this.startTime,i=this.formatTime(s),r=this.calculateETA();if(!process.stderr.isTTY)return void(this.current%100!=0&&this.current!==this.total||process.stderr.write(`\rProcessed: ${t}/${this.total} (${n}%) | ${i} elapsed | ETA: ${r}${o}`));const l=Math.round(e/100*this.width),c=this.width-l,d=`\r${a.green("β".repeat(l))+a.gray("β".repeat(c))} ${n}% | ${t}/${this.total} files | ${i} elapsed | ETA: ${r}${o}`;process.stderr.write("[K"+d)}finish(){const e=Date.now()-this.startTime,n=this.formatTime(e),t=this.errors>0?a.red(` (${this.errors} errors)`):"";if(process.stderr.isTTY){const e=100,o=a.green("β".repeat(this.width)),s=String(this.current).padStart(String(this.total).length);process.stderr.write(`\r${o} ${e.toFixed(1).padStart(5)}% | ${s}/${this.total} files | ${n}${t}\n`)}else process.stderr.write(`\rProcessed: ${this.current}/${this.total} files in ${n}${t}\n`)}};function ue(e){const n=Date.now(),t={total_files:0,total_lines:0,total_size:0,total_comment_lines:0,total_code_lines:0,total_blank_lines:0,total_full_line_comments:0,total_inline_comments:0,files_by_extension:{},lines_by_extension:{},comment_lines_by_extension:{},code_lines_by_extension:{},blank_lines_by_extension:{},full_line_comments_by_extension:{},inline_comments_by_extension:{},size_by_extension:{},details:[]},s=te(e);if(h(s))return s;const r=i.resolve(e.directory),l=i.dirname(r),{processed:c,errors:a}=function(e,n,t,s,r){let l=0,c=0;if(void 0!==n.max_depth&&de(e,r,n.max_depth))return{processed:l,errors:c};try{if(!o.statSync(e).isFile())return{processed:l,errors:c}}catch{return{processed:l,errors:c}}if(oe(e,n,s))return{processed:l,errors:c};const a=ae(e);if(a.error)return n.quiet||console.error(`Warning: Could not read metadata for ${e}: ${a.error}`),c+=1,{processed:l,errors:c};const d=a.metadata.size,m=se(e);if(n.rm_comments){const t=m.toLowerCase().replace(/^\./,"");if(ne.map(e=>e.toLowerCase()).includes(t))return{processed:l,errors:c};if((()=>{if(!0===n.rm_comments)return!0;if("string"==typeof n.rm_comments){const e=x(n.rm_comments).map(e=>e.toLowerCase().replace(/^\./,""));return e.includes(t)||e.includes(`.${t}`)}return!1})()){const t=M(e);if(t.success){if(t.commentsFound){if(!n.quiet){const n=i.relative(r,e);console.log(`β Removed comments from ${n}`)}l+=1}}else{if(!n.quiet){const n=i.relative(r,e);console.error(`β Failed to remove comments from ${n}`)}c+=1}}return{processed:l,errors:c}}l+=1;let u=null,f=null,p=null,_=null,y=null,h=null,g=null;if(!n.files_only){const t=le(e,n);t.error?(n.quiet||console.error(`Warning: Could not count lines in ${e}: ${t.error.message}`),c+=1):(u=t.lines,f=t.commentLines,p=t.codeLines,_=t.fullLineComments,y=t.inlineComments,h=t.blankLines,g=ie(t))}return re(t,m,d,u,g),t.details.push(ce(e,d,m,u,f,p,_,y,h)),{processed:l,errors:c}}(r,e,t,s,l);return fe(e,n,c,a),e.rm_comments?{...t,_commentsRemoved:c}:t}function fe(e,n,t,o){if(e.show_progress&&!e.quiet){const e=`${Date.now()-n}ms`;process.stderr.write(`\rProcessed: ${t} files (${o} errors) in ${e}\n`)}}function pe(e){const n=Date.now(),t={total_files:0,total_lines:0,total_size:0,total_comment_lines:0,total_code_lines:0,total_blank_lines:0,total_full_line_comments:0,total_inline_comments:0,files_by_extension:{},lines_by_extension:{},comment_lines_by_extension:{},code_lines_by_extension:{},blank_lines_by_extension:{},full_line_comments_by_extension:{},inline_comments_by_extension:{},size_by_extension:{},details:[]},s=te(e);if(h(s))return s;const r=function(e){const n=m();return n.add(".git"),n.add(".gitignore"),n.add(".lcignore"),function e(t,s){const r=i.join(t,".gitignore");try{if(o.existsSync(r)&&o.statSync(r).isFile()){const e=o.readFileSync(r,"utf-8"),l=i.relative(s,t)||".",c=e.split("\n").map(e=>e.trim()).filter(e=>e&&!e.startsWith("#"));for(const e of c)"."===l?n.add(e):n.add(i.join(l,e))}}catch{}try{const n=o.readdirSync(t);for(const r of n){const n=i.join(t,r);try{o.statSync(n).isDirectory()&&".git"!==r&&e(n,s)}catch{}}}catch{}}(e,e),n}(e.directory),l={cwd:e.directory,absolute:!0,onlyFiles:!0,ignore:[],dot:!e.no_hidden,followSymbolicLinks:e.follow_links};let c=0,a=0,u=null,f=0;try{const n=d.sync("**/*",l).map(e=>"string"==typeof e?e:e.path||String(e));e.show_progress&&!e.quiet&&(u=new me(n.length));for(const l of n){if(f+=1,u&&u.update(f,a),void 0!==e.max_depth&&de(l,e.directory,e.max_depth))continue;const n=i.relative(e.directory,l);if(r.ignores(n))continue;try{if(!o.statSync(l).isFile())continue}catch{continue}if(oe(l,e,s))continue;const d=ae(l);if(d.error){e.quiet||console.error(`Warning: Could not read metadata for ${l}: ${d.error}`),a+=1;continue}const m=d.metadata.size,p=se(l);if(e.rm_comments){const n=p.toLowerCase().replace(/^\./,"");if(ne.map(e=>e.toLowerCase()).includes(n))continue;if((()=>{if(!0===e.rm_comments)return!0;if("string"==typeof e.rm_comments){const t=x(e.rm_comments).map(e=>e.toLowerCase().replace(/^\./,""));return t.includes(n)||t.includes(`.${n}`)}return!1})()){const n=M(l);if(n.success){if(n.commentsFound){if(!e.quiet){const n=i.relative(e.directory,l);console.log(`β Removed comments from ${n}`)}c+=1}}else{if(!e.quiet){const n=i.relative(e.directory,l);console.error(`β Failed to remove comments from ${n}`)}a+=1}}continue}c+=1;let _=null,y=null,h=null,g=null,b=null,$=null,v=null;if(!e.files_only){const n=le(l,e);n.error?(e.quiet||console.error(`Warning: Could not count lines in ${l}: ${n.error.message}`),a+=1):(_=n.lines,y=n.commentLines,h=n.codeLines,g=n.fullLineComments,b=n.inlineComments,$=n.blankLines,v=ie(n))}re(t,p,m,_,v),t.details.push(ce(l,m,p,_,y,h,g,b,$))}}catch(e){return y.io(`Failed to scan directory: ${e instanceof Error?e.message:String(e)}`,e instanceof Error?e:void 0)}return fe(e,n,c,a),e.rm_comments?{...t,_commentsRemoved:c}:t}var _e=null,ye=!1,he=null;function ge(e){const n=$(e.directory);if(n.error)return n.error;const t=n.path;if(!o.statSync(t).isDirectory())return y.notADirectory(e.directory);e.directory=t;const s=pe(e);if(h(s))return s;Z(s,e)}function xe(e,n=500){_e&&clearTimeout(_e),_e=setTimeout(()=>{if(ye)return;ye=!0,e.quiet||(process.stdout.isTTY&&console.log("[2J[H"),console.log(a.cyan("π Changes detected. Rescanning...\n")));const n=ge(e);h(n)?e.quiet||(console.error(a.red(`\nβ Error: ${n.message}`)),n.suggestion&&console.error(a.yellow(`\nπ‘ Suggestion: ${n.suggestion}`))):e.quiet||(console.log(a.gray("\n"+"β".repeat(60))),console.log(a.gray(`π Watching for changes... (Press ${a.yellow("Ctrl+C")} to stop)`))),ye=!1},n)}function be(e){if(e.version)return void console.log(`LocIO ${_()}`);if(e.watch)return void function(e){const n=$(e.directory);n.error&&(console.error(`Error: ${n.error.message}`),process.exit(1));const t=n.path;o.statSync(t).isDirectory()||(console.error(`Error: Not a directory: ${e.directory}`),process.exit(1)),e.quiet||console.log(a.cyan("π Starting watch mode...\n"));const s=ge(e);h(s)&&(console.error(`Error: ${s.message}`),process.exit(1)),e.quiet||(console.log(a.gray("\n"+"β".repeat(60))),console.log(a.gray(`π Watching for changes... (Press ${a.yellow("Ctrl+C")} to stop)`)));try{(he=o.watch(t,{recursive:!0},(n,t)=>{t&&(e.export&&t.startsWith("LocIO-report.")||xe(e,500))})).on("error",n=>{e.quiet||console.error(a.red(`\nWatch error: ${n.message}`))})}catch(e){console.error(a.red(`Failed to start watch mode: ${e instanceof Error?e.message:String(e)}`)),console.error(a.yellow("Note: Recursive watching may not be supported on all systems.")),process.exit(1)}const i=()=>{_e&&clearTimeout(_e),he&&he.close(),e.quiet||console.log(a.gray("\n\nπ Watch mode stopped.")),process.exit(0)};process.on("SIGINT",i),process.on("SIGTERM",i)}(e);const n=$(e.directory);if(n.error)return n.error;const t=n.path,s=o.statSync(t);let i;if(s.isDirectory()&&!e.quiet){const e=D(t);"unknown"!==e&&console.log(`${a.cyan("Detected project type:")} ${a.blue.bold(V(e))}\n`)}if(e.directory=t,e.rm_comments){if(e.quiet||console.log(a.cyan("Removing comments from files...\n")),i=s.isFile()?ue(e):pe(e),h(i))return i;const n=i._commentsRemoved||0;return void(e.quiet||(n>0?console.log(a.green(`\nβ Comments removed successfully from ${n} file(s)!\n`)):console.log(a.yellow("\nβΉ No comments found in any files.\n"))))}if(i=s.isFile()?ue(e):pe(e),h(i))return i;Z(i,e)}(async function(){if(2===e.argv.length&&e.stdin.isTTY){if(!await new Promise((t,o)=>{const s=_();console.log("===================================="),console.log(` LocIO CLI v${s}`),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 s=n.createInterface({input:e.stdin,output:e.stdout}),i=()=>{s.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'),s.close(),t(!0);break;case"2":console.log("\nCommon commands:"),console.log(" locio . # Quick scan"),console.log(" locio . --files-only # Show only file counts"),console.log(" locio . --lines-only # Show only line counts"),console.log(' locio . --exclude "target" # Ignore patterns'),console.log(" locio . --include-ext ts,js # Filter by extension"),console.log(" locio . --export json # Export to JSON\n"),s.close(),t(!1);break;case"3":console.log(),k().outputHelp(),console.log("\n"),s.close(),t(!1);break;case"q":case"Q":console.log("\nThank you for using LocIO."),s.close(),t(!1);break;default:console.log("Invalid choice. Please enter 1, 2, 3, or q.\n"),i()}})};s.on("error",e=>{console.error("\nFailed to read input. Exiting."),s.close(),o(e)}),i()})}))return}!function(e){const n=be(e);h(n)&&(console.error(function(e){let n=`\nβ Error: ${e.message}\n`;return e.suggestion&&(n+=`\nπ‘ Suggestion:\n${e.suggestion}\n`),e.cause&&(n+=`\nπ Details: ${e.cause.message}\n`),n}(n)),process.exit(1)),e.watch||process.exit(0)}(function(){const e=k();e.parse();const n=e.opts(),t=e.args,o=n.excludeExt?x(n.excludeExt):[],s=n.includeExt?x(n.includeExt):[];return{directory:t[0]||".",files_only:n.filesOnly||!1,lines_only:n.linesOnly||!1,exclude_patterns:n.exclude||[],exclude_extensions:o,include_extensions:s,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:!0!==n.noProgress,no_binary:n.noBinary||!1,ignore_case:n.ignoreCase||!1,quiet:n.quiet||!1,export:b(n.export),export_path:n.exportPath,version:!1,watch:n.watch||!1,comments:!0!==n.noComments,code_vs_comments:n.codeVsComments||!1,rm_comments:!!n.rmComments&&(!0===n.rmComments||n.rmComments),top_files:n.topFiles,top_dirs:n.topDirs}}())})().catch(n=>{console.error("Unexpected error:",n),e.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "locio",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "A powerful CLI tool to count lines and files in directories with extensive filtering options",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"locio": "./dist/index.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
+
"start": "node dist/index.js",
|
|
11
12
|
"build": "rm -rf dist && tsup",
|
|
12
13
|
"build:watch": "tsup --watch",
|
|
13
14
|
"format": "prettier --write \"**/*.{js,json,ts,md}\""
|