fln 1.0.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.
Files changed (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +330 -0
  3. package/dist/api/fln.d.ts +3 -0
  4. package/dist/api/fln.d.ts.map +1 -0
  5. package/dist/api/fln.js +71 -0
  6. package/dist/api/index.d.ts +3 -0
  7. package/dist/api/index.d.ts.map +1 -0
  8. package/dist/api/index.js +2 -0
  9. package/dist/api/types.d.ts +34 -0
  10. package/dist/api/types.d.ts.map +1 -0
  11. package/dist/api/types.js +1 -0
  12. package/dist/cli/commandLine.d.ts +2 -0
  13. package/dist/cli/commandLine.d.ts.map +1 -0
  14. package/dist/cli/commandLine.js +120 -0
  15. package/dist/cli/help.d.ts +2 -0
  16. package/dist/cli/help.d.ts.map +1 -0
  17. package/dist/cli/help.js +40 -0
  18. package/dist/cli/index.d.ts +2 -0
  19. package/dist/cli/index.d.ts.map +1 -0
  20. package/dist/cli/index.js +1 -0
  21. package/dist/cli/main.d.ts +3 -0
  22. package/dist/cli/main.d.ts.map +1 -0
  23. package/dist/cli/main.js +9 -0
  24. package/dist/cli/output/components/breakdown.d.ts +2 -0
  25. package/dist/cli/output/components/breakdown.d.ts.map +1 -0
  26. package/dist/cli/output/components/breakdown.js +21 -0
  27. package/dist/cli/output/components/errors.d.ts +6 -0
  28. package/dist/cli/output/components/errors.d.ts.map +1 -0
  29. package/dist/cli/output/components/errors.js +13 -0
  30. package/dist/cli/output/components/progressBar.d.ts +7 -0
  31. package/dist/cli/output/components/progressBar.d.ts.map +1 -0
  32. package/dist/cli/output/components/progressBar.js +38 -0
  33. package/dist/cli/output/components/summary.d.ts +8 -0
  34. package/dist/cli/output/components/summary.d.ts.map +1 -0
  35. package/dist/cli/output/components/summary.js +12 -0
  36. package/dist/cli/output/components/warnings.d.ts +6 -0
  37. package/dist/cli/output/components/warnings.d.ts.map +1 -0
  38. package/dist/cli/output/components/warnings.js +11 -0
  39. package/dist/cli/output/formatter.d.ts +5 -0
  40. package/dist/cli/output/formatter.d.ts.map +1 -0
  41. package/dist/cli/output/formatter.js +28 -0
  42. package/dist/cli/output/index.d.ts +8 -0
  43. package/dist/cli/output/index.d.ts.map +1 -0
  44. package/dist/cli/output/index.js +4 -0
  45. package/dist/cli/output/renderer.d.ts +21 -0
  46. package/dist/cli/output/renderer.d.ts.map +1 -0
  47. package/dist/cli/output/renderer.js +121 -0
  48. package/dist/cli/output/styles.d.ts +23 -0
  49. package/dist/cli/output/styles.d.ts.map +1 -0
  50. package/dist/cli/output/styles.js +26 -0
  51. package/dist/config/defaults.d.ts +3 -0
  52. package/dist/config/defaults.d.ts.map +1 -0
  53. package/dist/config/defaults.js +2 -0
  54. package/dist/config/index.d.ts +6 -0
  55. package/dist/config/index.d.ts.map +1 -0
  56. package/dist/config/index.js +5 -0
  57. package/dist/config/loader.d.ts +3 -0
  58. package/dist/config/loader.d.ts.map +1 -0
  59. package/dist/config/loader.js +11 -0
  60. package/dist/config/resolver.d.ts +8 -0
  61. package/dist/config/resolver.d.ts.map +1 -0
  62. package/dist/config/resolver.js +66 -0
  63. package/dist/config/types.d.ts +40 -0
  64. package/dist/config/types.d.ts.map +1 -0
  65. package/dist/config/types.js +1 -0
  66. package/dist/config/utils.d.ts +7 -0
  67. package/dist/config/utils.d.ts.map +1 -0
  68. package/dist/config/utils.js +161 -0
  69. package/dist/core/ignoreMatcher.d.ts +15 -0
  70. package/dist/core/ignoreMatcher.d.ts.map +1 -0
  71. package/dist/core/ignoreMatcher.js +97 -0
  72. package/dist/core/index.d.ts +8 -0
  73. package/dist/core/index.d.ts.map +1 -0
  74. package/dist/core/index.js +7 -0
  75. package/dist/core/renderOutput.d.ts +4 -0
  76. package/dist/core/renderOutput.d.ts.map +1 -0
  77. package/dist/core/renderOutput.js +218 -0
  78. package/dist/core/renderTree.d.ts +3 -0
  79. package/dist/core/renderTree.d.ts.map +1 -0
  80. package/dist/core/renderTree.js +23 -0
  81. package/dist/core/scanTree.d.ts +4 -0
  82. package/dist/core/scanTree.d.ts.map +1 -0
  83. package/dist/core/scanTree.js +348 -0
  84. package/dist/core/size.d.ts +4 -0
  85. package/dist/core/size.d.ts.map +1 -0
  86. package/dist/core/size.js +32 -0
  87. package/dist/core/statsCollector.d.ts +4 -0
  88. package/dist/core/statsCollector.d.ts.map +1 -0
  89. package/dist/core/statsCollector.js +28 -0
  90. package/dist/core/types.d.ts +53 -0
  91. package/dist/core/types.d.ts.map +1 -0
  92. package/dist/core/types.js +1 -0
  93. package/dist/index.d.ts +4 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +3 -0
  96. package/dist/infra/countTokens.d.ts +2 -0
  97. package/dist/infra/countTokens.d.ts.map +1 -0
  98. package/dist/infra/countTokens.js +186 -0
  99. package/dist/infra/datetime.d.ts +3 -0
  100. package/dist/infra/datetime.d.ts.map +1 -0
  101. package/dist/infra/datetime.js +15 -0
  102. package/dist/infra/index.d.ts +7 -0
  103. package/dist/infra/index.d.ts.map +1 -0
  104. package/dist/infra/index.js +6 -0
  105. package/dist/infra/logger.d.ts +19 -0
  106. package/dist/infra/logger.d.ts.map +1 -0
  107. package/dist/infra/logger.js +99 -0
  108. package/dist/infra/outputWriter.d.ts +15 -0
  109. package/dist/infra/outputWriter.d.ts.map +1 -0
  110. package/dist/infra/outputWriter.js +35 -0
  111. package/dist/infra/terminal.d.ts +91 -0
  112. package/dist/infra/terminal.d.ts.map +1 -0
  113. package/dist/infra/terminal.js +189 -0
  114. package/dist/infra/usageTracker.d.ts +3 -0
  115. package/dist/infra/usageTracker.d.ts.map +1 -0
  116. package/dist/infra/usageTracker.js +39 -0
  117. package/dist/version.d.ts +2 -0
  118. package/dist/version.d.ts.map +1 -0
  119. package/dist/version.js +1 -0
  120. package/package.json +79 -0
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import { runCommandLine } from "./commandLine";
3
+ try {
4
+ await runCommandLine();
5
+ }
6
+ catch (error) {
7
+ console.error(`ERROR ${String(error)}`);
8
+ process.exit(1);
9
+ }
@@ -0,0 +1,2 @@
1
+ export declare function renderBreakdown(stats: Map<string, number>, useColors: boolean): string;
2
+ //# sourceMappingURL=breakdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breakdown.d.ts","sourceRoot":"","sources":["../../../../src/cli/output/components/breakdown.ts"],"names":[],"mappings":"AAIA,wBAAgB,eAAe,CAC9B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC1B,SAAS,EAAE,OAAO,GAChB,MAAM,CAwBR"}
@@ -0,0 +1,21 @@
1
+ import { formatFileCount } from "../formatter";
2
+ import { applyColor, colors, symbols } from "../styles";
3
+ export function renderBreakdown(stats, useColors) {
4
+ const entries = Array.from(stats.entries())
5
+ .sort((a, b) => b[1] - a[1])
6
+ .slice(0, 10);
7
+ if (entries.length === 0)
8
+ return "";
9
+ const maxExtLength = Math.max(...entries.map(([ext]) => ext.length));
10
+ const lines = entries.map(([ext, count], index) => {
11
+ const isLast = index === entries.length - 1;
12
+ const branch = isLast ? symbols.lastBranch : symbols.branch;
13
+ const branchSymbol = applyColor(branch, colors.dim, useColors);
14
+ const padding = " ".repeat(maxExtLength - ext.length);
15
+ const extension = applyColor(ext, colors.info, useColors);
16
+ const label = applyColor(formatFileCount(count), colors.success, useColors);
17
+ return ` ${branchSymbol} ${extension}${padding} ${label}`;
18
+ });
19
+ const title = useColors ? colors.bold("Breakdown") : "Breakdown";
20
+ return [title, ...lines].join("\n");
21
+ }
@@ -0,0 +1,6 @@
1
+ export type FileError = {
2
+ path: string;
3
+ reason: string;
4
+ };
5
+ export declare function renderErrors(errors: FileError[], useColors: boolean, verbose: boolean): string;
6
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../../src/cli/output/components/errors.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,SAAS,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAgB,YAAY,CAC3B,MAAM,EAAE,SAAS,EAAE,EACnB,SAAS,EAAE,OAAO,EAClB,OAAO,EAAE,OAAO,GACd,MAAM,CAiBR"}
@@ -0,0 +1,13 @@
1
+ import { applyColor, colors, symbols } from "../styles";
2
+ export function renderErrors(errors, useColors, verbose) {
3
+ if (errors.length === 0)
4
+ return "";
5
+ const symbol = applyColor(symbols.error, colors.error, useColors);
6
+ const count = errors.length;
7
+ if (!verbose)
8
+ return `${symbol} ${count} ${count === 1 ? "file" : "files"} failed — run with --verbose for details`;
9
+ const lines = [`${symbol} ${count} ${count === 1 ? "file" : "files"} failed`, ""];
10
+ for (const error of errors)
11
+ lines.push(` ${error.path}`, ` ${applyColor(error.reason, colors.dim, useColors)}`, "");
12
+ return lines.join("\n");
13
+ }
@@ -0,0 +1,7 @@
1
+ export declare class ProgressBar {
2
+ #private;
3
+ constructor(total: number, useColors: boolean);
4
+ increment(message?: string): void;
5
+ clear(): void;
6
+ }
7
+ //# sourceMappingURL=progressBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progressBar.d.ts","sourceRoot":"","sources":["../../../../src/cli/output/components/progressBar.ts"],"names":[],"mappings":"AAGA,qBAAa,WAAW;;gBAOX,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO;IAM7C,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAYjC,KAAK,IAAI,IAAI;CAoCb"}
@@ -0,0 +1,38 @@
1
+ import { applyColor, colors, symbols } from "../styles";
2
+ export class ProgressBar {
3
+ #total;
4
+ #current = 0;
5
+ #visible = false;
6
+ #isTTY;
7
+ #useColors;
8
+ constructor(total, useColors) {
9
+ this.#total = total;
10
+ this.#isTTY = Boolean(process.stdout.isTTY);
11
+ this.#useColors = useColors;
12
+ }
13
+ increment(message) {
14
+ this.#current++;
15
+ if (!this.#isTTY)
16
+ return;
17
+ if (!this.#visible)
18
+ this.#visible = true;
19
+ this.#render(message);
20
+ }
21
+ clear() {
22
+ if (!this.#visible || !this.#isTTY)
23
+ return;
24
+ process.stdout.write(`\r${" ".repeat(80)}\r`);
25
+ this.#visible = false;
26
+ }
27
+ #render(message) {
28
+ const percent = Math.floor((this.#current / this.#total) * 100);
29
+ const filledCount = Math.floor(percent / 5);
30
+ const emptyCount = 20 - filledCount;
31
+ const filledBar = applyColor(symbols.barFull.repeat(filledCount), colors.info, this.#useColors);
32
+ const emptyBar = applyColor(symbols.barEmpty.repeat(emptyCount), colors.dim, this.#useColors);
33
+ const bar = filledBar + emptyBar;
34
+ const text = message ?? "Scanning...";
35
+ const counter = applyColor(`${this.#current}/${this.#total}`, colors.dim, this.#useColors);
36
+ process.stdout.write(`\r${symbols.pancake} ${text} ${bar} ${percent}% (${counter} files)`);
37
+ }
38
+ }
@@ -0,0 +1,8 @@
1
+ export declare function renderSummary(data: {
2
+ outputPath: string;
3
+ files: number;
4
+ tokens: number;
5
+ useColors: boolean;
6
+ verbose?: boolean;
7
+ }): string;
8
+ //# sourceMappingURL=summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../../../src/cli/output/components/summary.ts"],"names":[],"mappings":"AAKA,wBAAgB,aAAa,CAAC,IAAI,EAAE;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,MAAM,CAWT"}
@@ -0,0 +1,12 @@
1
+ import { basename } from "node:path";
2
+ import { formatFileCount, formatTokenCount } from "../formatter";
3
+ import { applyColor, colors, symbols } from "../styles";
4
+ export function renderSummary(data) {
5
+ const fileName = basename(data.outputPath);
6
+ const successSymbol = applyColor(symbols.success, colors.success, data.useColors);
7
+ if (data.verbose)
8
+ return `${successSymbol} ${fileName} created`;
9
+ const filesText = applyColor(formatFileCount(data.files), colors.success, data.useColors);
10
+ const tokenCount = applyColor(formatTokenCount(data.tokens), colors.success, data.useColors);
11
+ return `${successSymbol} ${fileName} (${filesText}, ${tokenCount} tokens)`;
12
+ }
@@ -0,0 +1,6 @@
1
+ export type Warning = {
2
+ type: "large_output";
3
+ tokens: number;
4
+ };
5
+ export declare function renderWarnings(warnings: Warning[], useColors: boolean): string;
6
+ //# sourceMappingURL=warnings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warnings.d.ts","sourceRoot":"","sources":["../../../../src/cli/output/components/warnings.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,OAAO,GAAG;IACrB,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,CAY9E"}
@@ -0,0 +1,11 @@
1
+ import { applyColor, colors, symbols } from "../styles";
2
+ export function renderWarnings(warnings, useColors) {
3
+ if (warnings.length === 0)
4
+ return "";
5
+ const lines = warnings.map(warning => {
6
+ const symbol = applyColor(symbols.warning, colors.warning, useColors);
7
+ const tokens = Math.round(warning.tokens / 1000);
8
+ return `${symbol} Output size is large (~${tokens}K tokens) — consider using --exclude`;
9
+ });
10
+ return lines.join("\n");
11
+ }
@@ -0,0 +1,5 @@
1
+ export declare function formatTime(ms: number): string;
2
+ export declare function formatTokenCount(tokens: number): string;
3
+ export declare function formatFileCount(count: number): string;
4
+ export declare function formatByteSize(bytes: number): string;
5
+ //# sourceMappingURL=formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../../src/cli/output/formatter.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAW7C;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAQvD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWpD"}
@@ -0,0 +1,28 @@
1
+ export function formatTime(ms) {
2
+ if (ms < 1000)
3
+ return `${ms}ms`;
4
+ if (ms < 60_000)
5
+ return `${(ms / 1000).toFixed(1)}s`;
6
+ const minutes = Math.floor(ms / 60_000);
7
+ const seconds = Math.floor((ms % 60_000) / 1000);
8
+ return `${minutes}m ${seconds}s`;
9
+ }
10
+ export function formatTokenCount(tokens) {
11
+ if (tokens < 1_000)
12
+ return `${tokens}`;
13
+ if (tokens < 1_000_000)
14
+ return `~${Math.round(tokens / 1000)}K`;
15
+ return `~${(tokens / 1_000_000).toFixed(1)}M`;
16
+ }
17
+ export function formatFileCount(count) {
18
+ return count === 1 ? "1 file" : `${count} files`;
19
+ }
20
+ export function formatByteSize(bytes) {
21
+ if (bytes < 1024)
22
+ return `${bytes}B`;
23
+ if (bytes < 1024 * 1024)
24
+ return `${(bytes / 1024).toFixed(1)}KB`;
25
+ if (bytes < 1024 * 1024 * 1024)
26
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
27
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}GB`;
28
+ }
@@ -0,0 +1,8 @@
1
+ export type { FileError } from "./components/errors";
2
+ export { ProgressBar } from "./components/progressBar";
3
+ export type { Warning } from "./components/warnings";
4
+ export * from "./formatter";
5
+ export { OutputRenderer } from "./renderer";
6
+ export type { RendererOptions, SuccessData } from "./renderer";
7
+ export * from "./styles";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/output/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC/D,cAAc,UAAU,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { ProgressBar } from "./components/progressBar";
2
+ export * from "./formatter";
3
+ export { OutputRenderer } from "./renderer";
4
+ export * from "./styles";
@@ -0,0 +1,21 @@
1
+ import type { FlnResult } from "$api";
2
+ import type { LogLevel } from "$core";
3
+ import { ProgressBar } from "./components/progressBar";
4
+ export type RendererOptions = {
5
+ logLevel: LogLevel;
6
+ useAnsi: boolean;
7
+ };
8
+ export type SuccessData = {
9
+ outputPath: string;
10
+ result: FlnResult;
11
+ elapsedMs: number;
12
+ breakdown?: Map<string, number>;
13
+ processedFiles?: string[];
14
+ };
15
+ export declare class OutputRenderer {
16
+ #private;
17
+ constructor(options: RendererOptions);
18
+ createProgressBar(total: number): ProgressBar;
19
+ renderSuccess(data: SuccessData): void;
20
+ }
21
+ //# sourceMappingURL=renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/cli/output/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGtC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAOvD,MAAM,MAAM,eAAe,GAAG;IAC7B,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AAEF,qBAAa,cAAc;;gBAId,OAAO,EAAE,eAAe;IAKpC,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW;IAI7C,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;CAsItC"}
@@ -0,0 +1,121 @@
1
+ import { renderBreakdown } from "./components/breakdown";
2
+ import { renderErrors } from "./components/errors";
3
+ import { ProgressBar } from "./components/progressBar";
4
+ import { renderSummary } from "./components/summary";
5
+ import { renderWarnings } from "./components/warnings";
6
+ import { formatTime } from "./formatter";
7
+ import { applyColor, colors, symbols } from "./styles";
8
+ export class OutputRenderer {
9
+ #logLevel;
10
+ #useColors;
11
+ constructor(options) {
12
+ this.#logLevel = options.logLevel;
13
+ this.#useColors = options.useAnsi;
14
+ }
15
+ createProgressBar(total) {
16
+ return new ProgressBar(total, this.#useColors);
17
+ }
18
+ renderSuccess(data) {
19
+ if (this.#logLevel === "silent")
20
+ return;
21
+ switch (this.#logLevel) {
22
+ case "normal":
23
+ this.#renderNormal(data);
24
+ break;
25
+ case "verbose":
26
+ this.#renderVerbose(data);
27
+ break;
28
+ case "debug":
29
+ this.#renderDebug(data);
30
+ break;
31
+ }
32
+ }
33
+ #renderNormal(data) {
34
+ const { result, outputPath } = data;
35
+ const summary = renderSummary({
36
+ outputPath,
37
+ files: result.files,
38
+ tokens: result.outputTokenCount,
39
+ useColors: this.#useColors
40
+ });
41
+ console.info(summary);
42
+ const parts = [];
43
+ if (result.skipped > 0) {
44
+ const count = result.skipped;
45
+ parts.push(`${count} ${count === 1 ? "file" : "files"} skipped`);
46
+ }
47
+ if (result.binary > 0) {
48
+ const count = result.binary;
49
+ parts.push(`${count} binary ${count === 1 ? "file" : "files"}`);
50
+ }
51
+ if (parts.length > 0) {
52
+ const symbol = applyColor(symbols.info, colors.dim, this.#useColors);
53
+ const text = parts.join(", ");
54
+ console.info(`${symbol} ${applyColor(text, colors.dim, this.#useColors)}`);
55
+ }
56
+ const warnings = this.#collectWarnings(result);
57
+ if (warnings.length > 0) {
58
+ const warningsText = renderWarnings(warnings, this.#useColors);
59
+ if (warningsText)
60
+ console.info(warningsText);
61
+ }
62
+ if (result.errors > 0) {
63
+ const errorsText = renderErrors([], this.#useColors, false);
64
+ if (errorsText)
65
+ console.error(errorsText);
66
+ }
67
+ }
68
+ #renderVerbose(data) {
69
+ const { result, outputPath, elapsedMs, breakdown } = data;
70
+ console.info("");
71
+ const summary = renderSummary({
72
+ outputPath,
73
+ files: result.files,
74
+ tokens: result.outputTokenCount,
75
+ useColors: this.#useColors,
76
+ verbose: true
77
+ });
78
+ console.info(summary);
79
+ console.info("");
80
+ const maxLabelLength = 6;
81
+ const filesLabel = applyColor("Files".padEnd(maxLabelLength), colors.dim, this.#useColors);
82
+ const filesProcessed = applyColor(result.files, colors.success, this.#useColors);
83
+ const filesSkipped = result.skipped > 0 ? `, ${result.skipped} skipped` : "";
84
+ const filesBinary = result.binary > 0 ? `, ${result.binary} binary` : "";
85
+ const filesErrors = result.errors > 0 ? `, ${applyColor(result.errors, colors.error, this.#useColors)} errors` : "";
86
+ console.info(`${filesLabel} ${filesProcessed} processed${filesSkipped}${filesBinary}${filesErrors}`);
87
+ const tokensLabel = applyColor("Tokens".padEnd(maxLabelLength), colors.dim, this.#useColors);
88
+ const tokensValue = applyColor(`~${Math.round(result.outputTokenCount / 1000)}K`, colors.success, this.#useColors);
89
+ console.info(`${tokensLabel} ${tokensValue}`);
90
+ const timeLabel = applyColor("Time".padEnd(maxLabelLength), colors.dim, this.#useColors);
91
+ const timeValue = applyColor(formatTime(elapsedMs), colors.success, this.#useColors);
92
+ console.info(`${timeLabel} ${timeValue}`);
93
+ if (breakdown && breakdown.size > 0) {
94
+ console.info("");
95
+ const breakdownText = renderBreakdown(breakdown, this.#useColors);
96
+ console.info(breakdownText);
97
+ }
98
+ }
99
+ #renderDebug(data) {
100
+ const { processedFiles } = data;
101
+ this.#renderVerbose(data);
102
+ if (processedFiles && processedFiles.length > 0) {
103
+ console.info("");
104
+ const title = this.#useColors ? colors.bold("Processed files") : "Processed files";
105
+ console.info(title);
106
+ for (const file of processedFiles) {
107
+ const filePath = applyColor(`./${file}`, colors.dim, this.#useColors);
108
+ console.info(` ${filePath}`);
109
+ }
110
+ }
111
+ }
112
+ #collectWarnings(result) {
113
+ const warnings = [];
114
+ if (result.outputTokenCount > 200_000)
115
+ warnings.push({
116
+ type: "large_output",
117
+ tokens: result.outputTokenCount
118
+ });
119
+ return warnings;
120
+ }
121
+ }
@@ -0,0 +1,23 @@
1
+ export type StyleFunction = (text: number | string) => string;
2
+ export declare const colors: {
3
+ readonly success: import("picocolors/types").Formatter;
4
+ readonly warning: import("picocolors/types").Formatter;
5
+ readonly error: import("picocolors/types").Formatter;
6
+ readonly info: import("picocolors/types").Formatter;
7
+ readonly dim: import("picocolors/types").Formatter;
8
+ readonly bold: import("picocolors/types").Formatter;
9
+ readonly reset: import("picocolors/types").Formatter;
10
+ };
11
+ export declare const symbols: {
12
+ readonly success: "✓";
13
+ readonly warning: "⚠";
14
+ readonly error: "✗";
15
+ readonly info: "ℹ";
16
+ readonly pancake: "🥞";
17
+ readonly branch: "├─";
18
+ readonly lastBranch: "└─";
19
+ readonly barFull: "█";
20
+ readonly barEmpty: "░";
21
+ };
22
+ export declare function applyColor(text: number | string, colorFn: StyleFunction, useColors: boolean): string;
23
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../src/cli/output/styles.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,KAAK,MAAM,CAAC;AAE9D,eAAO,MAAM,MAAM;;;;;;;;CAQT,CAAC;AAEX,eAAO,MAAM,OAAO;;;;;;;;;;CAUV,CAAC;AAEX,wBAAgB,UAAU,CACzB,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,OAAO,GAChB,MAAM,CAKR"}
@@ -0,0 +1,26 @@
1
+ import pc from "picocolors";
2
+ export const colors = {
3
+ success: pc.green,
4
+ warning: pc.yellow,
5
+ error: pc.red,
6
+ info: pc.cyan,
7
+ dim: pc.dim,
8
+ bold: pc.bold,
9
+ reset: pc.reset
10
+ };
11
+ export const symbols = {
12
+ success: "✓",
13
+ warning: "⚠",
14
+ error: "✗",
15
+ info: "ℹ",
16
+ pancake: "🥞",
17
+ branch: "├─",
18
+ lastBranch: "└─",
19
+ barFull: "█",
20
+ barEmpty: "░"
21
+ };
22
+ export function applyColor(text, colorFn, useColors) {
23
+ if (!useColors)
24
+ return String(text);
25
+ return colorFn(String(text));
26
+ }
@@ -0,0 +1,3 @@
1
+ export declare const defaultMaximumFileSizeBytes: number;
2
+ export declare const defaultConfigFileName = ".fln.json";
3
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,2BAA2B,QAAmB,CAAC;AAC5D,eAAO,MAAM,qBAAqB,cAAc,CAAC"}
@@ -0,0 +1,2 @@
1
+ export const defaultMaximumFileSizeBytes = 10 * 1024 * 1024;
2
+ export const defaultConfigFileName = ".fln.json";
@@ -0,0 +1,6 @@
1
+ export * from "./defaults";
2
+ export * from "./loader";
3
+ export * from "./resolver";
4
+ export * from "./types";
5
+ export * from "./utils";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from "./defaults";
2
+ export * from "./loader";
3
+ export * from "./resolver";
4
+ export * from "./types";
5
+ export * from "./utils";
@@ -0,0 +1,3 @@
1
+ import type { RawConfigFile } from "./types";
2
+ export declare function loadConfigFile(configPath: string): Promise<RawConfigFile>;
3
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAG7C,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAS/E"}
@@ -0,0 +1,11 @@
1
+ import { readFile } from "node:fs/promises";
2
+ export async function loadConfigFile(configPath) {
3
+ try {
4
+ const content = await readFile(configPath, "utf8");
5
+ const parsed = JSON.parse(content);
6
+ return parsed;
7
+ }
8
+ catch {
9
+ return {};
10
+ }
11
+ }
@@ -0,0 +1,8 @@
1
+ import type { FlnConfig, RawConfigFile } from "./types";
2
+ type ConfigOverrides = Partial<Pick<FlnConfig, "banner" | "excludePatterns" | "followSymlinks" | "footer" | "generatedDate" | "includeContents" | "includeHidden" | "includePatterns" | "includeTree" | "logLevel" | "maximumFileSizeBytes" | "maximumTotalSizeBytes" | "outputFile" | "useAnsi" | "useGitignore">> & Partial<{
3
+ format: string;
4
+ }>;
5
+ export declare function normalizeConfigFile(fileConfig: RawConfigFile): ConfigOverrides;
6
+ export declare function resolveConfig(rootDirectory: string, fileConfig: ConfigOverrides, userConfig: ConfigOverrides): FlnConfig;
7
+ export {};
8
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/config/resolver.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAGxD,KAAK,eAAe,GAAG,OAAO,CAAC,IAAI,CAClC,SAAS,EACT,QAAQ,GACR,iBAAiB,GACjB,gBAAgB,GAChB,QAAQ,GACR,eAAe,GACf,iBAAiB,GACjB,eAAe,GACf,iBAAiB,GACjB,aAAa,GACb,UAAU,GACV,sBAAsB,GACtB,uBAAuB,GACvB,YAAY,GACZ,SAAS,GACT,cAAc,CACd,CAAC,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAkBjC,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,aAAa,GAAG,eAAe,CAmB9E;AAED,wBAAgB,aAAa,CAC5B,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,eAAe,EAC3B,UAAU,EAAE,eAAe,GACzB,SAAS,CAgCX"}
@@ -0,0 +1,66 @@
1
+ import { parseByteSize } from "$core";
2
+ import { parseGeneratedDate } from "$infra";
3
+ import { defaultMaximumFileSizeBytes } from "./defaults";
4
+ function parseOptionalSize(value) {
5
+ if (value === undefined)
6
+ return undefined;
7
+ return typeof value === "number" ? value : parseByteSize(value);
8
+ }
9
+ function resolveFormat(value) {
10
+ return value === "json" ? "json" : "md";
11
+ }
12
+ function getDefaultOutputFile(format) {
13
+ return format === "json" ? "output.json" : "output.md";
14
+ }
15
+ export function normalizeConfigFile(fileConfig) {
16
+ return {
17
+ outputFile: fileConfig.outputFile,
18
+ excludePatterns: fileConfig.excludePatterns,
19
+ includePatterns: fileConfig.includePatterns,
20
+ includeHidden: fileConfig.includeHidden,
21
+ useGitignore: fileConfig.useGitignore,
22
+ maximumFileSizeBytes: parseOptionalSize(fileConfig.maximumFileSizeBytes),
23
+ maximumTotalSizeBytes: parseOptionalSize(fileConfig.maximumTotalSizeBytes),
24
+ includeTree: fileConfig.includeTree,
25
+ includeContents: fileConfig.includeContents,
26
+ format: fileConfig.format,
27
+ followSymlinks: fileConfig.followSymlinks,
28
+ useAnsi: fileConfig.useAnsi,
29
+ logLevel: fileConfig.logLevel,
30
+ generatedDate: fileConfig.generatedDate,
31
+ banner: fileConfig.banner,
32
+ footer: fileConfig.footer
33
+ };
34
+ }
35
+ export function resolveConfig(rootDirectory, fileConfig, userConfig) {
36
+ const format = resolveFormat(userConfig.format ?? fileConfig.format);
37
+ const outputFile = userConfig.outputFile ?? fileConfig.outputFile ?? getDefaultOutputFile(format);
38
+ const rawGeneratedDate = userConfig.generatedDate ?? fileConfig.generatedDate;
39
+ const generatedDate = rawGeneratedDate === undefined ? undefined : parseGeneratedDate(rawGeneratedDate);
40
+ return {
41
+ rootDirectory,
42
+ outputFile,
43
+ excludePatterns: [
44
+ ...(fileConfig.excludePatterns ?? []),
45
+ ...(userConfig.excludePatterns ?? [])
46
+ ],
47
+ includePatterns: [
48
+ ...(fileConfig.includePatterns ?? []),
49
+ ...(userConfig.includePatterns ?? [])
50
+ ],
51
+ excludedPaths: [],
52
+ includeHidden: userConfig.includeHidden ?? fileConfig.includeHidden ?? false,
53
+ useGitignore: userConfig.useGitignore ?? fileConfig.useGitignore ?? true,
54
+ maximumFileSizeBytes: userConfig.maximumFileSizeBytes ?? fileConfig.maximumFileSizeBytes ?? defaultMaximumFileSizeBytes,
55
+ maximumTotalSizeBytes: userConfig.maximumTotalSizeBytes ?? fileConfig.maximumTotalSizeBytes ?? 0,
56
+ includeContents: userConfig.includeContents ?? fileConfig.includeContents ?? true,
57
+ includeTree: userConfig.includeTree ?? fileConfig.includeTree ?? true,
58
+ format,
59
+ followSymlinks: userConfig.followSymlinks ?? fileConfig.followSymlinks ?? false,
60
+ useAnsi: userConfig.useAnsi ?? fileConfig.useAnsi ?? true,
61
+ logLevel: userConfig.logLevel ?? fileConfig.logLevel ?? "normal",
62
+ generatedDate,
63
+ banner: userConfig.banner ?? fileConfig.banner,
64
+ footer: userConfig.footer ?? fileConfig.footer
65
+ };
66
+ }
@@ -0,0 +1,40 @@
1
+ import type { LogLevel, OutputFormat } from "$core";
2
+ export type RawConfigFile = Partial<{
3
+ outputFile: string;
4
+ excludePatterns: string[];
5
+ includePatterns: string[];
6
+ includeHidden: boolean;
7
+ useGitignore: boolean;
8
+ maximumFileSizeBytes: number | string;
9
+ maximumTotalSizeBytes: number | string;
10
+ includeTree: boolean;
11
+ includeContents: boolean;
12
+ format: OutputFormat;
13
+ followSymlinks: boolean;
14
+ useAnsi: boolean;
15
+ logLevel: LogLevel;
16
+ generatedDate: string;
17
+ banner: string;
18
+ footer: string;
19
+ }>;
20
+ export type FlnConfig = {
21
+ rootDirectory: string;
22
+ outputFile: string;
23
+ excludePatterns: string[];
24
+ includePatterns: string[];
25
+ excludedPaths: string[];
26
+ includeHidden: boolean;
27
+ useGitignore: boolean;
28
+ maximumFileSizeBytes: number;
29
+ maximumTotalSizeBytes: number;
30
+ includeTree: boolean;
31
+ includeContents: boolean;
32
+ format: OutputFormat;
33
+ followSymlinks: boolean;
34
+ useAnsi: boolean;
35
+ logLevel: LogLevel;
36
+ generatedDate?: string;
37
+ banner?: string;
38
+ footer?: string;
39
+ };
40
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAGpD,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,oBAAoB,EAAE,MAAM,GAAG,MAAM,CAAC;IACtC,qBAAqB,EAAE,MAAM,GAAG,MAAM,CAAC;IACvC,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ export declare function normalizeFileToken(rawValue: string): string;
2
+ export declare function getProjectMetadata(rootDirectory: string): Promise<{
3
+ name: string;
4
+ version?: string;
5
+ }>;
6
+ export declare function resolveOutputPath(outputValue: string | undefined, rootDirectory: string, format: "json" | "md"): Promise<string>;
7
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/config/utils.ts"],"names":[],"mappings":"AAIA,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAU3D;AAqCD,wBAAsB,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiG3G;AA+BD,wBAAsB,iBAAiB,CACtC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GAAG,IAAI,GACnB,OAAO,CAAC,MAAM,CAAC,CAsBjB"}