@kt3k/tku 1.1.0 → 1.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/dist/main.js +115 -4
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -163,10 +163,107 @@ function formatTable(result, omitted = 0) {
|
|
|
163
163
|
lines.push(`${totalDisplay.padStart(maxWidth)} total (${result.totalFiles} files)`);
|
|
164
164
|
return lines.join("\n");
|
|
165
165
|
}
|
|
166
|
+
function buildTree(files) {
|
|
167
|
+
const root = {
|
|
168
|
+
name: ".",
|
|
169
|
+
tokens: 0,
|
|
170
|
+
children: []
|
|
171
|
+
};
|
|
172
|
+
for (const file of files) {
|
|
173
|
+
const parts = file.path.split("/");
|
|
174
|
+
let node = root;
|
|
175
|
+
for (let i = 0; i < parts.length; i++) {
|
|
176
|
+
const name = parts[i];
|
|
177
|
+
const isFile = i === parts.length - 1;
|
|
178
|
+
let child = node.children.find((c) => c.name === name);
|
|
179
|
+
if (!child) {
|
|
180
|
+
child = {
|
|
181
|
+
name,
|
|
182
|
+
tokens: 0,
|
|
183
|
+
children: []
|
|
184
|
+
};
|
|
185
|
+
node.children.push(child);
|
|
186
|
+
}
|
|
187
|
+
if (isFile) {
|
|
188
|
+
child.tokens = file.tokens;
|
|
189
|
+
}
|
|
190
|
+
node = child;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function aggregate(node) {
|
|
194
|
+
if (node.children.length === 0) return node.tokens;
|
|
195
|
+
node.tokens = node.children.reduce((sum, c) => sum + aggregate(c), 0);
|
|
196
|
+
return node.tokens;
|
|
197
|
+
}
|
|
198
|
+
aggregate(root);
|
|
199
|
+
function sortChildren(node) {
|
|
200
|
+
for (const child of node.children) sortChildren(child);
|
|
201
|
+
const dirs = node.children.filter((c) => c.children.length > 0).sort((a, b) => b.tokens - a.tokens);
|
|
202
|
+
const leaves = node.children.filter((c) => c.children.length === 0).sort((a, b) => b.tokens - a.tokens);
|
|
203
|
+
node.children = [
|
|
204
|
+
...dirs,
|
|
205
|
+
...leaves
|
|
206
|
+
];
|
|
207
|
+
}
|
|
208
|
+
sortChildren(root);
|
|
209
|
+
return root;
|
|
210
|
+
}
|
|
211
|
+
function formatTree(result, options = {}) {
|
|
212
|
+
const tree = buildTree(result.files);
|
|
213
|
+
const dirsOnly = options.dirs ?? false;
|
|
214
|
+
const lines = [];
|
|
215
|
+
const allTokens = [];
|
|
216
|
+
function collectTokens(node) {
|
|
217
|
+
if (dirsOnly && node.children.length === 0) return;
|
|
218
|
+
allTokens.push(node.tokens);
|
|
219
|
+
for (const child of node.children) collectTokens(child);
|
|
220
|
+
}
|
|
221
|
+
collectTokens(tree);
|
|
222
|
+
const maxWidth = Math.max("tokens".length, ...allTokens.map((t) => formatTokenCount(t).length));
|
|
223
|
+
function render(node, prefix, isLast, isRoot) {
|
|
224
|
+
const display = formatTokenCount(node.tokens);
|
|
225
|
+
const connector = isRoot ? "" : isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
226
|
+
const name = node.children.length > 0 && !isRoot ? `${node.name}/` : node.name;
|
|
227
|
+
lines.push(`${display.padStart(maxWidth)} ${prefix}${connector}${name}`);
|
|
228
|
+
const visibleChildren = dirsOnly ? node.children.filter((c) => c.children.length > 0) : node.children;
|
|
229
|
+
const childPrefix = isRoot ? "" : prefix + (isLast ? " " : "\u2502 ");
|
|
230
|
+
for (let i = 0; i < visibleChildren.length; i++) {
|
|
231
|
+
render(visibleChildren[i], childPrefix, i === visibleChildren.length - 1, false);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
lines.push(`${"tokens".padStart(maxWidth)} path`);
|
|
235
|
+
render(tree, "", true, true);
|
|
236
|
+
return lines.join("\n");
|
|
237
|
+
}
|
|
238
|
+
function summarizeByDir(result) {
|
|
239
|
+
const dirMap = /* @__PURE__ */ new Map();
|
|
240
|
+
for (const file of result.files) {
|
|
241
|
+
const slashIdx = file.path.indexOf("/");
|
|
242
|
+
if (slashIdx === -1) continue;
|
|
243
|
+
const dir = file.path.slice(0, slashIdx);
|
|
244
|
+
dirMap.set(dir, (dirMap.get(dir) ?? 0) + file.tokens);
|
|
245
|
+
}
|
|
246
|
+
const files = [
|
|
247
|
+
...dirMap.entries()
|
|
248
|
+
].map(([path, tokens]) => ({
|
|
249
|
+
path,
|
|
250
|
+
tokens
|
|
251
|
+
}));
|
|
252
|
+
return {
|
|
253
|
+
...result,
|
|
254
|
+
files
|
|
255
|
+
};
|
|
256
|
+
}
|
|
166
257
|
function formatResult(result, options = {}) {
|
|
167
|
-
const { json = false, top, sort = "tokens" } = options;
|
|
258
|
+
const { json = false, top, sort = "tokens", tree = false, dirs = false } = options;
|
|
259
|
+
if (tree) {
|
|
260
|
+
return formatTree(result, {
|
|
261
|
+
dirs
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
const effective = dirs ? summarizeByDir(result) : result;
|
|
168
265
|
const sorted = [
|
|
169
|
-
...
|
|
266
|
+
...effective.files
|
|
170
267
|
];
|
|
171
268
|
if (sort === "path") {
|
|
172
269
|
sorted.sort((a, b) => a.path.localeCompare(b.path));
|
|
@@ -176,7 +273,7 @@ function formatResult(result, options = {}) {
|
|
|
176
273
|
const filtered = top !== void 0 ? sorted.slice(0, top) : sorted;
|
|
177
274
|
const omitted = sorted.length - filtered.length;
|
|
178
275
|
const adjusted = {
|
|
179
|
-
...
|
|
276
|
+
...effective,
|
|
180
277
|
files: filtered
|
|
181
278
|
};
|
|
182
279
|
return json ? JSON.stringify(adjusted, null, 2) : formatTable(adjusted, omitted);
|
|
@@ -193,6 +290,9 @@ Options:
|
|
|
193
290
|
--json Output results as JSON
|
|
194
291
|
--top <n> Show only the top N files by token count
|
|
195
292
|
--sort <field> Sort by "tokens" or "path" (default: tokens)
|
|
293
|
+
-t, --tree Display results as a directory tree
|
|
294
|
+
(ignores --top, --json, --sort)
|
|
295
|
+
--dirs Summarize by directory (table or tree)
|
|
196
296
|
-h, --help Show this help message`);
|
|
197
297
|
}
|
|
198
298
|
async function main() {
|
|
@@ -223,6 +323,15 @@ async function main() {
|
|
|
223
323
|
type: "string",
|
|
224
324
|
default: "tokens"
|
|
225
325
|
},
|
|
326
|
+
tree: {
|
|
327
|
+
type: "boolean",
|
|
328
|
+
short: "t",
|
|
329
|
+
default: false
|
|
330
|
+
},
|
|
331
|
+
dirs: {
|
|
332
|
+
type: "boolean",
|
|
333
|
+
default: false
|
|
334
|
+
},
|
|
226
335
|
help: {
|
|
227
336
|
type: "boolean",
|
|
228
337
|
short: "h",
|
|
@@ -266,7 +375,9 @@ async function main() {
|
|
|
266
375
|
const output = formatResult(result, {
|
|
267
376
|
json: values.json,
|
|
268
377
|
top,
|
|
269
|
-
sort
|
|
378
|
+
sort,
|
|
379
|
+
tree: values.tree,
|
|
380
|
+
dirs: values.dirs
|
|
270
381
|
});
|
|
271
382
|
console.log(output);
|
|
272
383
|
} catch (e) {
|