make-folder-txt 2.1.4 → 2.2.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/bin/make-folder-txt.js +592 -336
- package/make-folder-txt.txt +607 -339
- package/package.json +1 -1
- package/completion/install-powershell-completion.ps1 +0 -75
- package/completion/make-folder-txt-completion.bash +0 -59
- package/completion/make-folder-txt-completion.ps1 +0 -95
- package/completion/make-folder-txt-completion.zsh +0 -30
package/make-folder-txt.txt
CHANGED
|
@@ -11,12 +11,12 @@ make-folder-txt/
|
|
|
11
11
|
├── .git/ [skipped]
|
|
12
12
|
├── bin/
|
|
13
13
|
│ └── make-folder-txt.js
|
|
14
|
-
├──
|
|
14
|
+
├── .txtconfig
|
|
15
15
|
├── LICENSE
|
|
16
16
|
├── package.json
|
|
17
17
|
└── README.md
|
|
18
18
|
|
|
19
|
-
Total files:
|
|
19
|
+
Total files: 5
|
|
20
20
|
|
|
21
21
|
================================================================================
|
|
22
22
|
FILE CONTENTS
|
|
@@ -476,18 +476,271 @@ function splitBySize(treeLines, filePaths, rootName, splitSize, effectiveMaxSize
|
|
|
476
476
|
return results;
|
|
477
477
|
}
|
|
478
478
|
|
|
479
|
-
// ──
|
|
479
|
+
// ── configuration ────────────────────────────────────────────────────────────────
|
|
480
|
+
|
|
481
|
+
function createInteractiveConfig() {
|
|
482
|
+
const readline = require('readline');
|
|
483
|
+
const fs = require('fs');
|
|
484
|
+
const path = require('path');
|
|
485
|
+
const os = require('os');
|
|
486
|
+
|
|
487
|
+
const rl = readline.createInterface({
|
|
488
|
+
input: process.stdin,
|
|
489
|
+
output: process.stdout
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
console.log('\n🔧 make-folder-txt Configuration Setup');
|
|
493
|
+
console.log('=====================================\n');
|
|
494
|
+
|
|
495
|
+
return new Promise((resolve) => {
|
|
496
|
+
const config = {
|
|
497
|
+
maxFileSize: '500KB',
|
|
498
|
+
splitMethod: 'none',
|
|
499
|
+
splitSize: '5MB',
|
|
500
|
+
copyToClipboard: false,
|
|
501
|
+
ignoreFolders: [],
|
|
502
|
+
ignoreFiles: []
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
let currentStep = 0;
|
|
506
|
+
const questions = [
|
|
507
|
+
{
|
|
508
|
+
key: 'maxFileSize',
|
|
509
|
+
question: 'Maximum file size to include (e.g., 500KB, 2MB, 1GB): ',
|
|
510
|
+
default: '500KB',
|
|
511
|
+
validate: (value) => {
|
|
512
|
+
if (!value.trim()) return true;
|
|
513
|
+
const validUnits = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
514
|
+
const match = value.match(/^(\d+(?:\.\d+)?)\s*([A-Z]+)$/i);
|
|
515
|
+
if (!match) return 'Please enter a valid size (e.g., 500KB, 2MB, 1GB)';
|
|
516
|
+
if (!validUnits.includes(match[2].toUpperCase())) return `Invalid unit. Use: ${validUnits.join(', ')}`;
|
|
517
|
+
return true;
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
key: 'splitMethod',
|
|
522
|
+
question: 'Split output method (none, folder, file, size): ',
|
|
523
|
+
default: 'none',
|
|
524
|
+
validate: (value) => {
|
|
525
|
+
const validMethods = ['none', 'folder', 'file', 'size'];
|
|
526
|
+
if (!validMethods.includes(value.toLowerCase())) return `Please choose: ${validMethods.join(', ')}`;
|
|
527
|
+
return true;
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
key: 'splitSize',
|
|
532
|
+
question: 'Split size when using size method (e.g., 5MB, 10MB): ',
|
|
533
|
+
default: '5MB',
|
|
534
|
+
ask: () => config.splitMethod === 'size',
|
|
535
|
+
validate: (value) => {
|
|
536
|
+
if (!value.trim()) return true;
|
|
537
|
+
const validUnits = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
538
|
+
const match = value.match(/^(\d+(?:\.\d+)?)\s*([A-Z]+)$/i);
|
|
539
|
+
if (!match) return 'Please enter a valid size (e.g., 5MB, 10MB)';
|
|
540
|
+
if (!validUnits.includes(match[2].toUpperCase())) return `Invalid unit. Use: ${validUnits.join(', ')}`;
|
|
541
|
+
return true;
|
|
542
|
+
}
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
key: 'copyToClipboard',
|
|
546
|
+
question: 'Copy to clipboard automatically? (y/n): ',
|
|
547
|
+
default: 'n',
|
|
548
|
+
validate: (value) => {
|
|
549
|
+
const answer = value.toLowerCase();
|
|
550
|
+
if (!['y', 'n', 'yes', 'no'].includes(answer)) return 'Please enter y/n or yes/no';
|
|
551
|
+
return true;
|
|
552
|
+
},
|
|
553
|
+
transform: (value) => ['y', 'yes'].includes(value.toLowerCase())
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
key: 'ignoreFolders',
|
|
557
|
+
question: 'Ignore folders (comma-separated, or press Enter to skip): ',
|
|
558
|
+
default: '',
|
|
559
|
+
transform: (value) => value ? value.split(',').map(f => f.trim()).filter(f => f) : []
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
key: 'ignoreFiles',
|
|
563
|
+
question: 'Ignore files (comma-separated, or press Enter to skip): ',
|
|
564
|
+
default: '',
|
|
565
|
+
transform: (value) => value ? value.split(',').map(f => f.trim()).filter(f => f) : []
|
|
566
|
+
}
|
|
567
|
+
];
|
|
568
|
+
|
|
569
|
+
function askQuestion() {
|
|
570
|
+
if (currentStep >= questions.length) {
|
|
571
|
+
// Save configuration
|
|
572
|
+
saveConfig();
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const q = questions[currentStep];
|
|
577
|
+
|
|
578
|
+
// Skip if conditional ask returns false
|
|
579
|
+
if (q.ask && !q.ask()) {
|
|
580
|
+
currentStep++;
|
|
581
|
+
askQuestion();
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const defaultValue = typeof q.default === 'function' ? q.default() : q.default;
|
|
586
|
+
rl.question(q.question + (defaultValue ? `(${defaultValue}) ` : ''), (answer) => {
|
|
587
|
+
const value = answer.trim() || defaultValue;
|
|
588
|
+
|
|
589
|
+
// Validate input
|
|
590
|
+
if (q.validate) {
|
|
591
|
+
const validation = q.validate(value);
|
|
592
|
+
if (validation !== true) {
|
|
593
|
+
console.log(`❌ ${validation}`);
|
|
594
|
+
askQuestion();
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// Transform value if needed
|
|
600
|
+
if (q.transform) {
|
|
601
|
+
config[q.key] = q.transform(value);
|
|
602
|
+
} else {
|
|
603
|
+
config[q.key] = value;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
currentStep++;
|
|
607
|
+
askQuestion();
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
function saveConfig() {
|
|
612
|
+
try {
|
|
613
|
+
// Create .txtconfig file
|
|
614
|
+
const configPath = path.join(process.cwd(), '.txtconfig');
|
|
615
|
+
const configContent = `{
|
|
616
|
+
"maxFileSize": "${config.maxFileSize}",
|
|
617
|
+
"splitMethod": "${config.splitMethod}",
|
|
618
|
+
"splitSize": "${config.splitSize}",
|
|
619
|
+
"copyToClipboard": ${config.copyToClipboard},
|
|
620
|
+
"ignoreFolders": ${JSON.stringify(config.ignoreFolders)},
|
|
621
|
+
"ignoreFiles": ${JSON.stringify(config.ignoreFiles)}
|
|
622
|
+
}`;
|
|
623
|
+
|
|
624
|
+
fs.writeFileSync(configPath, configContent);
|
|
625
|
+
|
|
626
|
+
// Update .txtignore if there are ignore patterns
|
|
627
|
+
if (config.ignoreFolders.length > 0 || config.ignoreFiles.length > 0) {
|
|
628
|
+
const ignorePath = path.join(process.cwd(), '.txtignore');
|
|
629
|
+
let ignoreContent = '';
|
|
630
|
+
|
|
631
|
+
// Read existing content if file exists
|
|
632
|
+
if (fs.existsSync(ignorePath)) {
|
|
633
|
+
ignoreContent = fs.readFileSync(ignorePath, 'utf8');
|
|
634
|
+
if (!ignoreContent.endsWith('\n')) ignoreContent += '\n';
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// Add new ignore patterns
|
|
638
|
+
const newPatterns = [
|
|
639
|
+
...config.ignoreFolders.map(f => f.endsWith('/') ? f : `${f}/`),
|
|
640
|
+
...config.ignoreFiles
|
|
641
|
+
];
|
|
642
|
+
|
|
643
|
+
if (newPatterns.length > 0) {
|
|
644
|
+
ignoreContent += '\n# Added by make-folder-txt config\n';
|
|
645
|
+
ignoreContent += newPatterns.join('\n') + '\n';
|
|
646
|
+
fs.writeFileSync(ignorePath, ignoreContent);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
480
649
|
|
|
481
|
-
|
|
650
|
+
console.log('\n✅ Configuration saved successfully!');
|
|
651
|
+
console.log(`📄 Config file: ${configPath}`);
|
|
652
|
+
if (config.ignoreFolders.length > 0 || config.ignoreFiles.length > 0) {
|
|
653
|
+
console.log(`📝 Ignore patterns added to .txtignore`);
|
|
654
|
+
}
|
|
655
|
+
console.log('\n💡 You can now run: make-folder-txt --use-config');
|
|
656
|
+
|
|
657
|
+
} catch (err) {
|
|
658
|
+
console.error('❌ Error saving configuration:', err.message);
|
|
659
|
+
} finally {
|
|
660
|
+
rl.close();
|
|
661
|
+
resolve();
|
|
662
|
+
}
|
|
663
|
+
}
|
|
482
664
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
665
|
+
askQuestion();
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function loadConfig() {
|
|
670
|
+
const fs = require('fs');
|
|
671
|
+
const path = require('path');
|
|
672
|
+
|
|
673
|
+
try {
|
|
674
|
+
const configPath = path.join(process.cwd(), '.txtconfig');
|
|
675
|
+
if (!fs.existsSync(configPath)) {
|
|
676
|
+
console.error('❌ .txtconfig file not found. Run --make-config first.');
|
|
677
|
+
process.exit(1);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
681
|
+
return JSON.parse(configContent);
|
|
682
|
+
} catch (err) {
|
|
683
|
+
console.error('❌ Error loading configuration:', err.message);
|
|
684
|
+
process.exit(1);
|
|
685
|
+
}
|
|
487
686
|
}
|
|
488
687
|
|
|
489
|
-
|
|
490
|
-
|
|
688
|
+
// ── main ──────────────────────────────────────────────────────────────────────
|
|
689
|
+
|
|
690
|
+
async function main() {
|
|
691
|
+
const args = process.argv.slice(2);
|
|
692
|
+
|
|
693
|
+
if (args.includes("-v") || args.includes("--version")) {
|
|
694
|
+
console.log(`v${version}`);
|
|
695
|
+
console.log("Built by Muhammad Saad Amin");
|
|
696
|
+
process.exit(0);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
if (args.includes("--make-config")) {
|
|
700
|
+
await createInteractiveConfig();
|
|
701
|
+
process.exit(0);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
if (args.includes("--use-config")) {
|
|
705
|
+
const config = loadConfig();
|
|
706
|
+
|
|
707
|
+
// Apply config to command line arguments
|
|
708
|
+
const newArgs = [];
|
|
709
|
+
|
|
710
|
+
// Add max file size if not default
|
|
711
|
+
if (config.maxFileSize !== '500KB') {
|
|
712
|
+
newArgs.push('--skip-large', config.maxFileSize);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// Add split method if not none
|
|
716
|
+
if (config.splitMethod !== 'none') {
|
|
717
|
+
newArgs.push('--split-method', config.splitMethod);
|
|
718
|
+
if (config.splitMethod === 'size') {
|
|
719
|
+
newArgs.push('--split-size', config.splitSize);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// Add copy to clipboard if true
|
|
724
|
+
if (config.copyToClipboard) {
|
|
725
|
+
newArgs.push('--copy');
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// Add ignore folders
|
|
729
|
+
if (config.ignoreFolders.length > 0) {
|
|
730
|
+
newArgs.push('--ignore-folder', ...config.ignoreFolders);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// Add ignore files
|
|
734
|
+
if (config.ignoreFiles.length > 0) {
|
|
735
|
+
newArgs.push('--ignore-file', ...config.ignoreFiles);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// Replace args with config-based args
|
|
739
|
+
args.splice(0, args.length, ...newArgs);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
743
|
+
console.log(`
|
|
491
744
|
\x1b[33mmake-folder-txt\x1b[0m
|
|
492
745
|
Dump an entire project folder into a single readable .txt file.
|
|
493
746
|
|
|
@@ -505,6 +758,8 @@ Dump an entire project folder into a single readable .txt file.
|
|
|
505
758
|
--split-size <size> Split output when size exceeds limit (requires --split-method size)
|
|
506
759
|
--copy Copy output to clipboard
|
|
507
760
|
--force Include everything (overrides all ignore patterns)
|
|
761
|
+
--make-config Create interactive configuration
|
|
762
|
+
--use-config Use configuration from .txtconfig file
|
|
508
763
|
--help, -h Show this help message
|
|
509
764
|
--version, -v Show version information
|
|
510
765
|
|
|
@@ -526,6 +781,8 @@ Dump an entire project folder into a single readable .txt file.
|
|
|
526
781
|
make-folder-txt -ofo src docs
|
|
527
782
|
make-folder-txt --only-file package.json README.md
|
|
528
783
|
make-folder-txt -ofi package.json README.md
|
|
784
|
+
make-folder-txt --make-config
|
|
785
|
+
make-folder-txt --use-config
|
|
529
786
|
|
|
530
787
|
\x1b[33m.TXTIGNORE FILE\x1b[0m
|
|
531
788
|
Create a .txtignore file in your project root to specify files/folders to ignore.
|
|
@@ -538,378 +795,389 @@ Dump an entire project folder into a single readable .txt file.
|
|
|
538
795
|
coverage/
|
|
539
796
|
LICENSE
|
|
540
797
|
`);
|
|
541
|
-
|
|
542
|
-
}
|
|
798
|
+
process.exit(0);
|
|
799
|
+
}
|
|
543
800
|
|
|
544
|
-
const ignoreDirs = new Set(IGNORE_DIRS);
|
|
545
|
-
const ignoreFiles = new Set(IGNORE_FILES);
|
|
546
|
-
const onlyFolders = new Set();
|
|
547
|
-
const onlyFiles = new Set();
|
|
548
|
-
let outputArg = null;
|
|
549
|
-
let copyToClipboardFlag = false;
|
|
550
|
-
let forceFlag = false;
|
|
551
|
-
let maxFileSize = 500 * 1024; // Default 500KB
|
|
552
|
-
let noSkipFlag = false;
|
|
553
|
-
let splitMethod = null; // 'folder', 'file', 'size'
|
|
554
|
-
let splitSize = null; // size in bytes
|
|
555
|
-
|
|
556
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
801
|
+
const ignoreDirs = new Set(IGNORE_DIRS);
|
|
802
|
+
const ignoreFiles = new Set(IGNORE_FILES);
|
|
803
|
+
const onlyFolders = new Set();
|
|
804
|
+
const onlyFiles = new Set();
|
|
805
|
+
let outputArg = null;
|
|
806
|
+
let copyToClipboardFlag = false;
|
|
807
|
+
let forceFlag = false;
|
|
808
|
+
let maxFileSize = 500 * 1024; // Default 500KB
|
|
809
|
+
let noSkipFlag = false;
|
|
810
|
+
let splitMethod = null; // 'folder', 'file', 'size'
|
|
811
|
+
let splitSize = null; // size in bytes
|
|
812
|
+
|
|
813
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
814
|
+
const arg = args[i];
|
|
815
|
+
|
|
816
|
+
if (arg === "--copy") {
|
|
817
|
+
copyToClipboardFlag = true;
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
563
820
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
821
|
+
if (arg === "--force") {
|
|
822
|
+
forceFlag = true;
|
|
823
|
+
continue;
|
|
824
|
+
}
|
|
568
825
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
826
|
+
if (arg === "--no-skip") {
|
|
827
|
+
noSkipFlag = true;
|
|
828
|
+
continue;
|
|
829
|
+
}
|
|
573
830
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
831
|
+
if (arg === "--skip-large") {
|
|
832
|
+
if (i + 1 >= args.length || args[i + 1].startsWith("-")) {
|
|
833
|
+
console.error("Error: --skip-large requires a size value (e.g., 400KB, 5GB).");
|
|
834
|
+
process.exit(1);
|
|
835
|
+
}
|
|
836
|
+
maxFileSize = parseFileSize(args[i + 1]);
|
|
837
|
+
i += 1;
|
|
838
|
+
continue;
|
|
839
|
+
}
|
|
583
840
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
841
|
+
if (arg.startsWith("--skip-large=")) {
|
|
842
|
+
const value = arg.slice("--skip-large=".length);
|
|
843
|
+
if (!value) {
|
|
844
|
+
console.error("Error: --skip-large requires a size value (e.g., 400KB, 5GB).");
|
|
845
|
+
process.exit(1);
|
|
846
|
+
}
|
|
847
|
+
maxFileSize = parseFileSize(value);
|
|
848
|
+
continue;
|
|
849
|
+
}
|
|
593
850
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
851
|
+
if (arg === "--split-method") {
|
|
852
|
+
if (i + 1 >= args.length || args[i + 1].startsWith("-")) {
|
|
853
|
+
console.error("Error: --split-method requires a method (folder, file, or size).");
|
|
854
|
+
process.exit(1);
|
|
855
|
+
}
|
|
856
|
+
const method = args[i + 1].toLowerCase();
|
|
857
|
+
if (!['folder', 'file', 'size'].includes(method)) {
|
|
858
|
+
console.error("Error: --split-method must be one of: folder, file, size");
|
|
859
|
+
process.exit(1);
|
|
860
|
+
}
|
|
861
|
+
splitMethod = method;
|
|
862
|
+
i += 1;
|
|
863
|
+
continue;
|
|
864
|
+
}
|
|
608
865
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
866
|
+
if (arg.startsWith("--split-method=")) {
|
|
867
|
+
const value = arg.slice("--split-method=".length);
|
|
868
|
+
if (!value) {
|
|
869
|
+
console.error("Error: --split-method requires a method (folder, file, or size).");
|
|
870
|
+
process.exit(1);
|
|
871
|
+
}
|
|
872
|
+
const method = value.toLowerCase();
|
|
873
|
+
if (!['folder', 'file', 'size'].includes(method)) {
|
|
874
|
+
console.error("Error: --split-method must be one of: folder, file, size");
|
|
875
|
+
process.exit(1);
|
|
876
|
+
}
|
|
877
|
+
splitMethod = method;
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
623
880
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
881
|
+
if (arg === "--split-size") {
|
|
882
|
+
if (i + 1 >= args.length || args[i + 1].startsWith("-")) {
|
|
883
|
+
console.error("Error: --split-size requires a size value (e.g., 5MB, 10MB).");
|
|
884
|
+
process.exit(1);
|
|
885
|
+
}
|
|
886
|
+
splitSize = parseFileSize(args[i + 1]);
|
|
887
|
+
i += 1;
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
633
890
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
891
|
+
if (arg.startsWith("--split-size=")) {
|
|
892
|
+
const value = arg.slice("--split-size=".length);
|
|
893
|
+
if (!value) {
|
|
894
|
+
console.error("Error: --split-size requires a size value (e.g., 5MB, 10MB).");
|
|
895
|
+
process.exit(1);
|
|
896
|
+
}
|
|
897
|
+
splitSize = parseFileSize(value);
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
643
900
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
901
|
+
if (arg === "--ignore-folder" || arg === "-ifo") {
|
|
902
|
+
let consumed = 0;
|
|
903
|
+
while (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
904
|
+
// Normalize the folder name: remove backslashes, trailing slashes, and leading ./
|
|
905
|
+
let folderName = args[i + 1];
|
|
906
|
+
folderName = folderName.replace(/\\/g, '/'); // Convert backslashes to forward slashes
|
|
907
|
+
folderName = folderName.replace(/^\.?\//, ''); // Remove leading ./ or /
|
|
908
|
+
folderName = folderName.replace(/\/+$/, ''); // Remove trailing slashes
|
|
909
|
+
ignoreDirs.add(folderName);
|
|
910
|
+
i += 1;
|
|
911
|
+
consumed += 1;
|
|
912
|
+
}
|
|
913
|
+
if (consumed === 0) {
|
|
914
|
+
console.error("Error: --ignore-folder requires at least one folder name.");
|
|
915
|
+
process.exit(1);
|
|
916
|
+
}
|
|
917
|
+
continue;
|
|
918
|
+
}
|
|
662
919
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
920
|
+
if (arg.startsWith("--ignore-folder=") || arg.startsWith("-ifo=")) {
|
|
921
|
+
const value = arg.startsWith("--ignore-folder=")
|
|
922
|
+
? arg.slice("--ignore-folder=".length)
|
|
923
|
+
: arg.slice("-ifo=".length);
|
|
924
|
+
if (!value) {
|
|
925
|
+
console.error("Error: --ignore-folder requires a folder name.");
|
|
926
|
+
process.exit(1);
|
|
927
|
+
}
|
|
928
|
+
// Normalize the folder name
|
|
929
|
+
let folderName = value;
|
|
930
|
+
folderName = folderName.replace(/\\/g, '/'); // Convert backslashes to forward slashes
|
|
931
|
+
folderName = folderName.replace(/^\.?\//, ''); // Remove leading ./ or /
|
|
932
|
+
folderName = folderName.replace(/\/+$/, ''); // Remove trailing slashes
|
|
933
|
+
ignoreDirs.add(folderName);
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
679
936
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
937
|
+
if (arg === "--ignore-file" || arg === "-ifi") {
|
|
938
|
+
let consumed = 0;
|
|
939
|
+
while (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
940
|
+
ignoreFiles.add(args[i + 1]);
|
|
941
|
+
i += 1;
|
|
942
|
+
consumed += 1;
|
|
943
|
+
}
|
|
944
|
+
if (consumed === 0) {
|
|
945
|
+
console.error("Error: --ignore-file requires at least one file name.");
|
|
946
|
+
process.exit(1);
|
|
947
|
+
}
|
|
948
|
+
continue;
|
|
949
|
+
}
|
|
693
950
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
951
|
+
if (arg.startsWith("--ignore-file=") || arg.startsWith("-ifi=")) {
|
|
952
|
+
const value = arg.startsWith("--ignore-file=")
|
|
953
|
+
? arg.slice("--ignore-file=".length)
|
|
954
|
+
: arg.slice("-ifi=".length);
|
|
955
|
+
if (!value) {
|
|
956
|
+
console.error("Error: --ignore-file requires a file name.");
|
|
957
|
+
process.exit(1);
|
|
958
|
+
}
|
|
959
|
+
ignoreFiles.add(value);
|
|
960
|
+
continue;
|
|
961
|
+
}
|
|
705
962
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
963
|
+
if (arg === "--only-folder" || arg === "-ofo") {
|
|
964
|
+
let consumed = 0;
|
|
965
|
+
while (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
966
|
+
// Normalize the folder name
|
|
967
|
+
let folderName = args[i + 1];
|
|
968
|
+
folderName = folderName.replace(/\\/g, '/'); // Convert backslashes to forward slashes
|
|
969
|
+
folderName = folderName.replace(/^\.?\//, ''); // Remove leading ./ or /
|
|
970
|
+
folderName = folderName.replace(/\/+$/, ''); // Remove trailing slashes
|
|
971
|
+
onlyFolders.add(folderName);
|
|
972
|
+
i += 1;
|
|
973
|
+
consumed += 1;
|
|
974
|
+
}
|
|
975
|
+
if (consumed === 0) {
|
|
976
|
+
console.error("Error: --only-folder requires at least one folder name.");
|
|
977
|
+
process.exit(1);
|
|
978
|
+
}
|
|
979
|
+
continue;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
if (arg.startsWith("--only-folder=") || arg.startsWith("-ofo=")) {
|
|
983
|
+
const value = arg.startsWith("--only-folder=")
|
|
984
|
+
? arg.slice("--only-folder=".length)
|
|
985
|
+
: arg.slice("-ofo=".length);
|
|
986
|
+
if (!value) {
|
|
987
|
+
console.error("Error: --only-folder requires a folder name.");
|
|
988
|
+
process.exit(1);
|
|
989
|
+
}
|
|
990
|
+
// Normalize the folder name
|
|
991
|
+
let folderName = value;
|
|
992
|
+
folderName = folderName.replace(/\\/g, '/'); // Convert backslashes to forward slashes
|
|
993
|
+
folderName = folderName.replace(/^\.?\//, ''); // Remove leading ./ or /
|
|
994
|
+
folderName = folderName.replace(/\/+$/, ''); // Remove trailing slashes
|
|
995
|
+
onlyFolders.add(folderName);
|
|
996
|
+
continue;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
if (arg === "--only-file" || arg === "-ofi") {
|
|
1000
|
+
let consumed = 0;
|
|
1001
|
+
while (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
1002
|
+
onlyFiles.add(args[i + 1]);
|
|
1003
|
+
i += 1;
|
|
1004
|
+
consumed += 1;
|
|
1005
|
+
}
|
|
1006
|
+
if (consumed === 0) {
|
|
1007
|
+
console.error("Error: --only-file requires at least one file name.");
|
|
1008
|
+
process.exit(1);
|
|
1009
|
+
}
|
|
1010
|
+
continue;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
if (arg.startsWith("--only-file=") || arg.startsWith("-ofi=")) {
|
|
1014
|
+
const value = arg.startsWith("--only-file=")
|
|
1015
|
+
? arg.slice("--only-file=".length)
|
|
1016
|
+
: arg.slice("-ofi=".length);
|
|
1017
|
+
if (!value) {
|
|
1018
|
+
console.error("Error: --only-file requires a file name.");
|
|
1019
|
+
process.exit(1);
|
|
1020
|
+
}
|
|
1021
|
+
onlyFiles.add(value);
|
|
1022
|
+
continue;
|
|
1023
|
+
}
|
|
724
1024
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
: arg.slice("-ofo=".length);
|
|
729
|
-
if (!value) {
|
|
730
|
-
console.error("Error: --only-folder requires a folder name.");
|
|
1025
|
+
// Unknown argument
|
|
1026
|
+
console.error(`Error: Unknown option "${arg}"`);
|
|
1027
|
+
console.error("Use --help for available options.");
|
|
731
1028
|
process.exit(1);
|
|
732
1029
|
}
|
|
733
|
-
// Normalize the folder name
|
|
734
|
-
let folderName = value;
|
|
735
|
-
folderName = folderName.replace(/\\/g, '/'); // Convert backslashes to forward slashes
|
|
736
|
-
folderName = folderName.replace(/^\.?\//, ''); // Remove leading ./ or /
|
|
737
|
-
folderName = folderName.replace(/\/+$/, ''); // Remove trailing slashes
|
|
738
|
-
onlyFolders.add(folderName);
|
|
739
|
-
continue;
|
|
740
|
-
}
|
|
741
1030
|
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
onlyFiles.add(args[i + 1]);
|
|
746
|
-
i += 1;
|
|
747
|
-
consumed += 1;
|
|
748
|
-
}
|
|
749
|
-
if (consumed === 0) {
|
|
750
|
-
console.error("Error: --only-file requires at least one file name.");
|
|
1031
|
+
// Validate split options
|
|
1032
|
+
if (splitMethod === 'size' && !splitSize) {
|
|
1033
|
+
console.error("Error: --split-method size requires --split-size to be specified");
|
|
751
1034
|
process.exit(1);
|
|
752
1035
|
}
|
|
753
|
-
continue;
|
|
754
|
-
}
|
|
755
1036
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
? arg.slice("--only-file=".length)
|
|
759
|
-
: arg.slice("-ofi=".length);
|
|
760
|
-
if (!value) {
|
|
761
|
-
console.error("Error: --only-file requires a file name.");
|
|
1037
|
+
if (splitSize && splitMethod !== 'size') {
|
|
1038
|
+
console.error("Error: --split-size can only be used with --split-method size");
|
|
762
1039
|
process.exit(1);
|
|
763
1040
|
}
|
|
764
|
-
onlyFiles.add(value);
|
|
765
|
-
continue;
|
|
766
|
-
}
|
|
767
1041
|
|
|
768
|
-
|
|
769
|
-
console.error(`Error: Unknown option "${arg}".`);
|
|
770
|
-
process.exit(1);
|
|
771
|
-
}
|
|
1042
|
+
// ── config ────────────────────────────────────────────────────────────────────────
|
|
772
1043
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
}
|
|
1044
|
+
const folderPath = process.cwd();
|
|
1045
|
+
const rootName = path.basename(folderPath);
|
|
1046
|
+
const txtIgnore = readTxtIgnore(folderPath);
|
|
777
1047
|
|
|
778
|
-
|
|
779
|
-
process.exit(1);
|
|
780
|
-
}
|
|
1048
|
+
// ── build tree & collect file paths ───────────────────────────────────────────────
|
|
781
1049
|
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
1050
|
+
const { lines: treeLines, filePaths } = collectFiles(
|
|
1051
|
+
folderPath,
|
|
1052
|
+
folderPath,
|
|
1053
|
+
ignoreDirs,
|
|
1054
|
+
ignoreFiles,
|
|
1055
|
+
onlyFolders,
|
|
1056
|
+
onlyFiles,
|
|
1057
|
+
{ rootName, txtIgnore, force: forceFlag }
|
|
1058
|
+
);
|
|
787
1059
|
|
|
788
|
-
|
|
789
|
-
console.error("Error: --split-size can only be used with --split-method size.");
|
|
790
|
-
process.exit(1);
|
|
791
|
-
}
|
|
1060
|
+
// ── build output filename ───────────────────────────────────────────────────────────
|
|
792
1061
|
|
|
793
|
-
|
|
794
|
-
const rootName = path.basename(folderPath);
|
|
1062
|
+
let outputFile = outputArg || path.join(folderPath, `${rootName}.txt`);
|
|
795
1063
|
|
|
796
|
-
//
|
|
797
|
-
const txtIgnore = readTxtIgnore(folderPath);
|
|
1064
|
+
// ── handle output splitting ─────────────────────────────────────────────────────────
|
|
798
1065
|
|
|
799
|
-
const
|
|
800
|
-
? path.resolve(outputArg)
|
|
801
|
-
: path.join(process.cwd(), `${rootName}.txt`);
|
|
1066
|
+
const effectiveMaxSize = noSkipFlag ? Infinity : maxFileSize;
|
|
802
1067
|
|
|
803
|
-
|
|
1068
|
+
if (splitMethod) {
|
|
1069
|
+
console.log(`🔧 Splitting output by: ${splitMethod}`);
|
|
1070
|
+
|
|
1071
|
+
let results;
|
|
1072
|
+
|
|
1073
|
+
if (splitMethod === 'folder') {
|
|
1074
|
+
results = splitByFolders(treeLines, filePaths, rootName, effectiveMaxSize, forceFlag);
|
|
1075
|
+
} else if (splitMethod === 'file') {
|
|
1076
|
+
results = splitByFiles(filePaths, rootName, effectiveMaxSize, forceFlag);
|
|
1077
|
+
} else if (splitMethod === 'size') {
|
|
1078
|
+
results = splitBySize(treeLines, filePaths, rootName, splitSize, effectiveMaxSize, forceFlag);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
console.log(`✅ Done! Created ${results.length} split files:`);
|
|
1082
|
+
console.log('');
|
|
1083
|
+
|
|
1084
|
+
results.forEach((result, index) => {
|
|
1085
|
+
if (splitMethod === 'folder') {
|
|
1086
|
+
console.log(`📁 Folder: ${result.folder}`);
|
|
1087
|
+
} else if (splitMethod === 'file') {
|
|
1088
|
+
console.log(`📄 File: ${result.fileName}`);
|
|
1089
|
+
} else if (splitMethod === 'size') {
|
|
1090
|
+
console.log(`📦 Part ${result.part}`);
|
|
1091
|
+
}
|
|
1092
|
+
console.log(`📄 Output : ${result.file}`);
|
|
1093
|
+
console.log(`📊 Size : ${result.size} KB`);
|
|
1094
|
+
console.log(`🗂️ Files : ${result.files}`);
|
|
1095
|
+
console.log('');
|
|
1096
|
+
});
|
|
1097
|
+
|
|
1098
|
+
if (copyToClipboardFlag) {
|
|
1099
|
+
console.log('⚠️ --copy flag is not compatible with splitting - clipboard copy skipped');
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
process.exit(0);
|
|
1103
|
+
}
|
|
804
1104
|
|
|
805
|
-
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
ignoreDirs,
|
|
810
|
-
ignoreFiles,
|
|
811
|
-
onlyFolders,
|
|
812
|
-
onlyFiles,
|
|
813
|
-
{ hasOnlyFilters, rootName, txtIgnore, force: forceFlag },
|
|
814
|
-
);
|
|
1105
|
+
// ── build output (no splitting) ───────────────────────────────────────────────────
|
|
1106
|
+
const out = [];
|
|
1107
|
+
const divider = "=".repeat(80);
|
|
1108
|
+
const subDivider = "-".repeat(80);
|
|
815
1109
|
|
|
816
|
-
|
|
817
|
-
|
|
1110
|
+
out.push(divider);
|
|
1111
|
+
out.push(`START OF FOLDER: ${rootName}`);
|
|
1112
|
+
out.push(divider);
|
|
1113
|
+
out.push("");
|
|
818
1114
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
if (splitMethod === 'folder') {
|
|
825
|
-
results = splitByFolders(treeLines, filePaths, rootName, effectiveMaxSize, forceFlag);
|
|
826
|
-
} else if (splitMethod === 'file') {
|
|
827
|
-
results = splitByFiles(filePaths, rootName, effectiveMaxSize, forceFlag);
|
|
828
|
-
} else if (splitMethod === 'size') {
|
|
829
|
-
results = splitBySize(treeLines, filePaths, rootName, splitSize, effectiveMaxSize, forceFlag);
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
console.log(`✅ Done! Created ${results.length} split files:`);
|
|
833
|
-
console.log('');
|
|
834
|
-
|
|
835
|
-
results.forEach((result, index) => {
|
|
836
|
-
if (splitMethod === 'folder') {
|
|
837
|
-
console.log(`📁 Folder: ${result.folder}`);
|
|
838
|
-
} else if (splitMethod === 'file') {
|
|
839
|
-
console.log(`📄 File: ${result.fileName}`);
|
|
840
|
-
} else if (splitMethod === 'size') {
|
|
841
|
-
console.log(`📦 Part ${result.part}`);
|
|
842
|
-
}
|
|
843
|
-
console.log(`📄 Output : ${result.file}`);
|
|
844
|
-
console.log(`📊 Size : ${result.size} KB`);
|
|
845
|
-
console.log(`🗂️ Files : ${result.files}`);
|
|
846
|
-
console.log('');
|
|
847
|
-
});
|
|
848
|
-
|
|
849
|
-
if (copyToClipboardFlag) {
|
|
850
|
-
console.log('⚠️ --copy flag is not compatible with splitting - clipboard copy skipped');
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
process.exit(0);
|
|
854
|
-
}
|
|
1115
|
+
out.push(divider);
|
|
1116
|
+
out.push("PROJECT STRUCTURE");
|
|
1117
|
+
out.push(divider);
|
|
1118
|
+
out.push(`Root: ${folderPath}\n`);
|
|
855
1119
|
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
out.push(
|
|
863
|
-
out.push(
|
|
864
|
-
out.push(
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
out.push("
|
|
868
|
-
out.push(
|
|
869
|
-
out.push(`
|
|
870
|
-
out.push(
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
out.push("");
|
|
875
|
-
|
|
876
|
-
out.push(
|
|
877
|
-
out.push(
|
|
878
|
-
out.push(divider);
|
|
879
|
-
|
|
880
|
-
filePaths.forEach(({ abs, rel }) => {
|
|
881
|
-
out.push("");
|
|
882
|
-
out.push(subDivider);
|
|
883
|
-
out.push(`FILE: ${rel}`);
|
|
884
|
-
out.push(subDivider);
|
|
885
|
-
const effectiveMaxSize = noSkipFlag ? Infinity : maxFileSize;
|
|
886
|
-
out.push(readContent(abs, forceFlag, effectiveMaxSize));
|
|
887
|
-
});
|
|
1120
|
+
out.push(`${rootName}/`);
|
|
1121
|
+
treeLines.forEach(l => out.push(l));
|
|
1122
|
+
out.push("");
|
|
1123
|
+
out.push(`Total files: ${filePaths.length}`);
|
|
1124
|
+
out.push("");
|
|
1125
|
+
|
|
1126
|
+
out.push(divider);
|
|
1127
|
+
out.push("FILE CONTENTS");
|
|
1128
|
+
out.push(divider);
|
|
1129
|
+
|
|
1130
|
+
filePaths.forEach(({ abs, rel }) => {
|
|
1131
|
+
out.push("");
|
|
1132
|
+
out.push(subDivider);
|
|
1133
|
+
out.push(`FILE: ${rel}`);
|
|
1134
|
+
out.push(subDivider);
|
|
1135
|
+
out.push(readContent(abs, forceFlag, effectiveMaxSize));
|
|
1136
|
+
});
|
|
1137
|
+
|
|
1138
|
+
out.push("");
|
|
1139
|
+
out.push(divider);
|
|
1140
|
+
out.push(`END OF FOLDER: ${rootName}`);
|
|
1141
|
+
out.push(divider);
|
|
888
1142
|
|
|
889
|
-
out.
|
|
890
|
-
out.push(divider);
|
|
891
|
-
out.push(`END OF FOLDER: ${rootName}`);
|
|
892
|
-
out.push(divider);
|
|
1143
|
+
fs.writeFileSync(outputFile, out.join("\n"), "utf8");
|
|
893
1144
|
|
|
894
|
-
fs.
|
|
1145
|
+
const sizeKB = (fs.statSync(outputFile).size / 1024).toFixed(1);
|
|
1146
|
+
console.log(`✅ Done!`);
|
|
1147
|
+
console.log(`📄 Output : ${outputFile}`);
|
|
1148
|
+
console.log(`📊 Size : ${sizeKB} KB`);
|
|
1149
|
+
console.log(`🗂️ Files : ${filePaths.length}`);
|
|
895
1150
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
console.log(
|
|
1151
|
+
if (copyToClipboardFlag) {
|
|
1152
|
+
const content = fs.readFileSync(outputFile, 'utf8');
|
|
1153
|
+
const success = copyToClipboard(content);
|
|
1154
|
+
if (success) {
|
|
1155
|
+
console.log(`📋 Copied to clipboard!`);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
901
1158
|
|
|
902
|
-
|
|
903
|
-
const content = fs.readFileSync(outputFile, 'utf8');
|
|
904
|
-
const success = copyToClipboard(content);
|
|
905
|
-
if (success) {
|
|
906
|
-
console.log(`📋 Copied to clipboard!`);
|
|
907
|
-
}
|
|
1159
|
+
console.log('');
|
|
908
1160
|
}
|
|
909
1161
|
|
|
910
|
-
|
|
1162
|
+
// Run the main function
|
|
1163
|
+
main().catch(err => {
|
|
1164
|
+
console.error('❌ Error:', err.message);
|
|
1165
|
+
process.exit(1);
|
|
1166
|
+
});
|
|
911
1167
|
|
|
912
1168
|
|
|
1169
|
+
--------------------------------------------------------------------------------
|
|
1170
|
+
FILE: /.txtconfig
|
|
1171
|
+
--------------------------------------------------------------------------------
|
|
1172
|
+
{
|
|
1173
|
+
"maxFileSize": "400KB",
|
|
1174
|
+
"splitMethod": "none",
|
|
1175
|
+
"splitSize": "5MB",
|
|
1176
|
+
"copyToClipboard": false,
|
|
1177
|
+
"ignoreFolders": ["skip"],
|
|
1178
|
+
"ignoreFiles": ["skip"]
|
|
1179
|
+
}
|
|
1180
|
+
|
|
913
1181
|
--------------------------------------------------------------------------------
|
|
914
1182
|
FILE: /LICENSE
|
|
915
1183
|
--------------------------------------------------------------------------------
|
|
@@ -941,7 +1209,7 @@ FILE: /package.json
|
|
|
941
1209
|
--------------------------------------------------------------------------------
|
|
942
1210
|
{
|
|
943
1211
|
"name": "make-folder-txt",
|
|
944
|
-
"version": "2.
|
|
1212
|
+
"version": "2.2.0",
|
|
945
1213
|
"description": "Generate a single .txt file containing the full folder structure and file contents of any project, ignoring node_modules and other junk.",
|
|
946
1214
|
"main": "bin/make-folder-txt.js",
|
|
947
1215
|
"bin": {
|