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 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
- - **Export reports** - save results as `LocIO-report.{txt,json,csv,tsv}` files
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(""+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(""),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(""+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(""),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",
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}\""