make-folder-txt 1.0.5 ā 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/bin/make-folder-txt.js +115 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -59,6 +59,14 @@ make-folder-txt --ignore-folder examples extensions docs --ignore-file LICENSE
|
|
|
59
59
|
make-folder-txt --ignore-file .env .env.local secrets.txt
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
+
Include only specific folders/files by name (everything else is ignored):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
make-folder-txt --only-folder src docs
|
|
66
|
+
make-folder-txt --only-file package.json README.md
|
|
67
|
+
make-folder-txt --only-folder src --only-file package.json
|
|
68
|
+
```
|
|
69
|
+
|
|
62
70
|
---
|
|
63
71
|
|
|
64
72
|
## šÆ Real World Examples
|
package/bin/make-folder-txt.js
CHANGED
|
@@ -19,12 +19,28 @@ const BINARY_EXTS = new Set([
|
|
|
19
19
|
|
|
20
20
|
// āā helpers āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
21
21
|
|
|
22
|
-
function collectFiles(
|
|
22
|
+
function collectFiles(
|
|
23
|
+
dir,
|
|
24
|
+
rootDir,
|
|
25
|
+
ignoreDirs,
|
|
26
|
+
ignoreFiles,
|
|
27
|
+
onlyFolders,
|
|
28
|
+
onlyFiles,
|
|
29
|
+
options = {},
|
|
30
|
+
) {
|
|
31
|
+
const {
|
|
32
|
+
indent = "",
|
|
33
|
+
lines = [],
|
|
34
|
+
filePaths = [],
|
|
35
|
+
inSelectedFolder = false,
|
|
36
|
+
hasOnlyFilters = false,
|
|
37
|
+
} = options;
|
|
38
|
+
|
|
23
39
|
let entries;
|
|
24
40
|
try {
|
|
25
41
|
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
26
42
|
} catch {
|
|
27
|
-
return { lines, filePaths };
|
|
43
|
+
return { lines, filePaths, hasIncluded: false };
|
|
28
44
|
}
|
|
29
45
|
|
|
30
46
|
entries.sort((a, b) => {
|
|
@@ -39,20 +55,53 @@ function collectFiles(dir, rootDir, ignoreDirs, ignoreFiles, indent = "", lines
|
|
|
39
55
|
|
|
40
56
|
if (entry.isDirectory()) {
|
|
41
57
|
if (ignoreDirs.has(entry.name)) {
|
|
42
|
-
|
|
58
|
+
if (!hasOnlyFilters) {
|
|
59
|
+
lines.push(`${indent}${connector}${entry.name}/ [skipped]`);
|
|
60
|
+
}
|
|
43
61
|
return;
|
|
44
62
|
}
|
|
45
|
-
|
|
46
|
-
|
|
63
|
+
|
|
64
|
+
const childPath = path.join(dir, entry.name);
|
|
65
|
+
const childInSelectedFolder = inSelectedFolder || onlyFolders.has(entry.name);
|
|
66
|
+
const childLines = [];
|
|
67
|
+
const childFiles = [];
|
|
68
|
+
const child = collectFiles(
|
|
69
|
+
childPath,
|
|
70
|
+
rootDir,
|
|
71
|
+
ignoreDirs,
|
|
72
|
+
ignoreFiles,
|
|
73
|
+
onlyFolders,
|
|
74
|
+
onlyFiles,
|
|
75
|
+
{
|
|
76
|
+
indent: childIndent,
|
|
77
|
+
lines: childLines,
|
|
78
|
+
filePaths: childFiles,
|
|
79
|
+
inSelectedFolder: childInSelectedFolder,
|
|
80
|
+
hasOnlyFilters,
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const explicitlySelectedFolder = hasOnlyFilters && onlyFolders.has(entry.name);
|
|
85
|
+
const shouldIncludeDir = !hasOnlyFilters || child.hasIncluded || explicitlySelectedFolder;
|
|
86
|
+
|
|
87
|
+
if (shouldIncludeDir) {
|
|
88
|
+
lines.push(`${indent}${connector}${entry.name}/`);
|
|
89
|
+
lines.push(...child.lines);
|
|
90
|
+
filePaths.push(...child.filePaths);
|
|
91
|
+
}
|
|
47
92
|
} else {
|
|
48
93
|
if (ignoreFiles.has(entry.name)) return;
|
|
94
|
+
|
|
95
|
+
const shouldIncludeFile = !hasOnlyFilters || inSelectedFolder || onlyFiles.has(entry.name);
|
|
96
|
+
if (!shouldIncludeFile) return;
|
|
97
|
+
|
|
49
98
|
lines.push(`${indent}${connector}${entry.name}`);
|
|
50
99
|
const relPath = "/" + path.relative(rootDir, path.join(dir, entry.name)).split(path.sep).join("/");
|
|
51
100
|
filePaths.push({ abs: path.join(dir, entry.name), rel: relPath });
|
|
52
101
|
}
|
|
53
102
|
});
|
|
54
103
|
|
|
55
|
-
return { lines, filePaths };
|
|
104
|
+
return { lines, filePaths, hasIncluded: filePaths.length > 0 || lines.length > 0 };
|
|
56
105
|
}
|
|
57
106
|
|
|
58
107
|
function readContent(absPath) {
|
|
@@ -81,6 +130,8 @@ if (args.includes("-v") || args.includes("--version")) {
|
|
|
81
130
|
|
|
82
131
|
const ignoreDirs = new Set(IGNORE_DIRS);
|
|
83
132
|
const ignoreFiles = new Set(IGNORE_FILES);
|
|
133
|
+
const onlyFolders = new Set();
|
|
134
|
+
const onlyFiles = new Set();
|
|
84
135
|
let outputArg = null;
|
|
85
136
|
|
|
86
137
|
for (let i = 0; i < args.length; i += 1) {
|
|
@@ -134,6 +185,54 @@ for (let i = 0; i < args.length; i += 1) {
|
|
|
134
185
|
continue;
|
|
135
186
|
}
|
|
136
187
|
|
|
188
|
+
if (arg === "--only-folder") {
|
|
189
|
+
let consumed = 0;
|
|
190
|
+
while (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
191
|
+
onlyFolders.add(args[i + 1]);
|
|
192
|
+
i += 1;
|
|
193
|
+
consumed += 1;
|
|
194
|
+
}
|
|
195
|
+
if (consumed === 0) {
|
|
196
|
+
console.error("Error: --only-folder requires at least one folder name.");
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (arg.startsWith("--only-folder=")) {
|
|
203
|
+
const value = arg.slice("--only-folder=".length);
|
|
204
|
+
if (!value) {
|
|
205
|
+
console.error("Error: --only-folder requires a folder name.");
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
onlyFolders.add(value);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (arg === "--only-file") {
|
|
213
|
+
let consumed = 0;
|
|
214
|
+
while (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
215
|
+
onlyFiles.add(args[i + 1]);
|
|
216
|
+
i += 1;
|
|
217
|
+
consumed += 1;
|
|
218
|
+
}
|
|
219
|
+
if (consumed === 0) {
|
|
220
|
+
console.error("Error: --only-file requires at least one file name.");
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (arg.startsWith("--only-file=")) {
|
|
227
|
+
const value = arg.slice("--only-file=".length);
|
|
228
|
+
if (!value) {
|
|
229
|
+
console.error("Error: --only-file requires a file name.");
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
onlyFiles.add(value);
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
|
|
137
236
|
if (arg.startsWith("-")) {
|
|
138
237
|
console.error(`Error: Unknown option "${arg}".`);
|
|
139
238
|
process.exit(1);
|
|
@@ -158,7 +257,16 @@ const outputFile = outputArg
|
|
|
158
257
|
|
|
159
258
|
console.log(`\nš Scanning: ${folderPath}`);
|
|
160
259
|
|
|
161
|
-
const
|
|
260
|
+
const hasOnlyFilters = onlyFolders.size > 0 || onlyFiles.size > 0;
|
|
261
|
+
const { lines: treeLines, filePaths } = collectFiles(
|
|
262
|
+
folderPath,
|
|
263
|
+
folderPath,
|
|
264
|
+
ignoreDirs,
|
|
265
|
+
ignoreFiles,
|
|
266
|
+
onlyFolders,
|
|
267
|
+
onlyFiles,
|
|
268
|
+
{ hasOnlyFilters },
|
|
269
|
+
);
|
|
162
270
|
|
|
163
271
|
// āā build output āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
164
272
|
const out = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "make-folder-txt",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Generate a single .txt file containing the full folder structure and file contents of any project, ignoring node_modules and other junk.",
|
|
5
5
|
"main": "bin/make-folder-txt.js",
|
|
6
6
|
"bin": {
|