@hackersheet/next-document-content-components 0.1.0-alpha.3 → 0.1.0-alpha.30

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 (100) hide show
  1. package/dist/cjs/components/code-block/__tests__/parse-tree-output.unit.test.d.ts +2 -0
  2. package/dist/cjs/components/code-block/__tests__/parse-tree-output.unit.test.js +627 -0
  3. package/dist/cjs/components/code-block/__tests__/parse-tree-output.unit.test.js.map +1 -0
  4. package/dist/cjs/components/code-block/code-block-copy-button.d.ts +22 -2
  5. package/dist/cjs/components/code-block/code-block-copy-button.js +3 -2
  6. package/dist/cjs/components/code-block/code-block-copy-button.js.map +1 -0
  7. package/dist/cjs/components/code-block/code-block-header.d.ts +34 -0
  8. package/dist/cjs/components/{index.js → code-block/code-block-header.js} +10 -27
  9. package/dist/cjs/components/code-block/code-block-header.js.map +1 -0
  10. package/dist/cjs/components/code-block/code-block-icon.d.ts +36 -4
  11. package/dist/cjs/components/code-block/code-block-icon.js +13 -0
  12. package/dist/cjs/components/code-block/code-block-icon.js.map +1 -0
  13. package/dist/cjs/components/code-block/code-block.d.ts +14 -0
  14. package/dist/cjs/components/code-block/code-block.js +3 -2
  15. package/dist/cjs/components/code-block/code-block.js.map +1 -0
  16. package/dist/cjs/components/code-block/directory-tree-item.d.ts +23 -0
  17. package/dist/cjs/components/code-block/directory-tree-item.js +39 -0
  18. package/dist/cjs/components/code-block/directory-tree-item.js.map +1 -0
  19. package/dist/cjs/components/code-block/directory-tree.d.ts +18 -0
  20. package/dist/cjs/components/code-block/directory-tree.js +44 -0
  21. package/dist/cjs/components/code-block/directory-tree.js.map +1 -0
  22. package/dist/cjs/components/code-block/parse-tree-output.d.ts +31 -0
  23. package/dist/cjs/components/code-block/parse-tree-output.js +150 -0
  24. package/dist/cjs/components/code-block/parse-tree-output.js.map +1 -0
  25. package/dist/cjs/components/code-block/shiki.js +26 -7
  26. package/dist/cjs/components/code-block/shiki.js.map +1 -0
  27. package/dist/cjs/components/gist/gist.d.ts +6 -0
  28. package/dist/cjs/components/gist/gist.js +56 -0
  29. package/dist/cjs/components/gist/gist.js.map +1 -0
  30. package/dist/cjs/components/heading/heading.d.ts +6 -0
  31. package/dist/cjs/components/heading/heading.js +40 -0
  32. package/dist/cjs/components/heading/heading.js.map +1 -0
  33. package/dist/cjs/components/image/image.js +2 -2
  34. package/dist/cjs/components/image/image.js.map +1 -0
  35. package/dist/cjs/components/link/link.js +2 -1
  36. package/dist/cjs/components/link/link.js.map +1 -0
  37. package/dist/cjs/components/link-card/link-card.js +2 -2
  38. package/dist/cjs/components/link-card/link-card.js.map +1 -0
  39. package/dist/cjs/components/mermaid/mermaid.d.ts +5 -0
  40. package/dist/cjs/components/mermaid/mermaid.js +71 -23
  41. package/dist/cjs/components/mermaid/mermaid.js.map +1 -0
  42. package/dist/cjs/components/x-post/x-post.js +1 -0
  43. package/dist/cjs/components/x-post/x-post.js.map +1 -0
  44. package/dist/cjs/components/youtube/youtube.js +2 -1
  45. package/dist/cjs/components/youtube/youtube.js.map +1 -0
  46. package/dist/cjs/index.d.ts +3 -0
  47. package/dist/cjs/index.js +49 -5
  48. package/dist/cjs/index.js.map +1 -0
  49. package/dist/esm/components/code-block/__tests__/parse-tree-output.unit.test.d.mts +2 -0
  50. package/dist/esm/components/code-block/__tests__/parse-tree-output.unit.test.mjs +626 -0
  51. package/dist/esm/components/code-block/__tests__/parse-tree-output.unit.test.mjs.map +1 -0
  52. package/dist/esm/components/code-block/code-block-copy-button.d.mts +22 -2
  53. package/dist/esm/components/code-block/code-block-copy-button.mjs +3 -2
  54. package/dist/esm/components/code-block/code-block-copy-button.mjs.map +1 -0
  55. package/dist/esm/components/code-block/code-block-header.d.mts +34 -0
  56. package/dist/esm/components/code-block/code-block-header.mjs +9 -0
  57. package/dist/esm/components/code-block/code-block-header.mjs.map +1 -0
  58. package/dist/esm/components/code-block/code-block-icon.d.mts +36 -4
  59. package/dist/esm/components/code-block/code-block-icon.mjs +26 -1
  60. package/dist/esm/components/code-block/code-block-icon.mjs.map +1 -0
  61. package/dist/esm/components/code-block/code-block.d.mts +14 -0
  62. package/dist/esm/components/code-block/code-block.mjs +5 -4
  63. package/dist/esm/components/code-block/code-block.mjs.map +1 -0
  64. package/dist/esm/components/code-block/directory-tree-item.d.mts +23 -0
  65. package/dist/esm/components/code-block/directory-tree-item.mjs +9 -0
  66. package/dist/esm/components/code-block/directory-tree-item.mjs.map +1 -0
  67. package/dist/esm/components/code-block/directory-tree.d.mts +18 -0
  68. package/dist/esm/components/code-block/directory-tree.mjs +14 -0
  69. package/dist/esm/components/code-block/directory-tree.mjs.map +1 -0
  70. package/dist/esm/components/code-block/parse-tree-output.d.mts +31 -0
  71. package/dist/esm/components/code-block/parse-tree-output.mjs +126 -0
  72. package/dist/esm/components/code-block/parse-tree-output.mjs.map +1 -0
  73. package/dist/esm/components/code-block/shiki.mjs +22 -8
  74. package/dist/esm/components/code-block/shiki.mjs.map +1 -0
  75. package/dist/esm/components/gist/gist.d.mts +6 -0
  76. package/dist/esm/components/gist/gist.mjs +26 -0
  77. package/dist/esm/components/gist/gist.mjs.map +1 -0
  78. package/dist/esm/components/heading/heading.d.mts +6 -0
  79. package/dist/esm/components/heading/heading.mjs +10 -0
  80. package/dist/esm/components/heading/heading.mjs.map +1 -0
  81. package/dist/esm/components/image/image.mjs +2 -2
  82. package/dist/esm/components/image/image.mjs.map +1 -0
  83. package/dist/esm/components/link/link.mjs +2 -1
  84. package/dist/esm/components/link/link.mjs.map +1 -0
  85. package/dist/esm/components/link-card/link-card.mjs +2 -2
  86. package/dist/esm/components/link-card/link-card.mjs.map +1 -0
  87. package/dist/esm/components/mermaid/mermaid.d.mts +5 -0
  88. package/dist/esm/components/mermaid/mermaid.mjs +72 -24
  89. package/dist/esm/components/mermaid/mermaid.mjs.map +1 -0
  90. package/dist/esm/components/x-post/x-post.mjs +1 -0
  91. package/dist/esm/components/x-post/x-post.mjs.map +1 -0
  92. package/dist/esm/components/youtube/youtube.mjs +2 -1
  93. package/dist/esm/components/youtube/youtube.mjs.map +1 -0
  94. package/dist/esm/index.d.mts +3 -0
  95. package/dist/esm/index.mjs +23 -1
  96. package/dist/esm/index.mjs.map +1 -0
  97. package/package.json +24 -21
  98. package/dist/cjs/components/index.d.ts +0 -9
  99. package/dist/esm/components/index.d.mts +0 -9
  100. package/dist/esm/components/index.mjs +0 -16
@@ -0,0 +1,627 @@
1
+ "use strict";
2
+ var import_vitest = require("vitest");
3
+ var import_parse_tree_output = require("../parse-tree-output");
4
+ function extractStructure(node) {
5
+ if (!node) return null;
6
+ return {
7
+ name: node.name,
8
+ type: node.type,
9
+ children: node.children?.map(extractStructure)
10
+ };
11
+ }
12
+ (0, import_vitest.describe)("parseTreeOutput", () => {
13
+ (0, import_vitest.describe)("basic parsing", () => {
14
+ (0, import_vitest.it)("returns null for empty input", () => {
15
+ (0, import_vitest.expect)((0, import_parse_tree_output.parseTreeOutput)("")).toBeNull();
16
+ (0, import_vitest.expect)((0, import_parse_tree_output.parseTreeOutput)(" ")).toBeNull();
17
+ });
18
+ (0, import_vitest.it)("parses a simple tree with one file", () => {
19
+ const input = `project
20
+ \u2514\u2500\u2500 file.txt`;
21
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
22
+ (0, import_vitest.expect)(extractStructure(result)).toEqual({
23
+ name: "project",
24
+ type: "directory",
25
+ children: [{ name: "file.txt", type: "file", children: void 0 }]
26
+ });
27
+ });
28
+ (0, import_vitest.it)("parses a tree with multiple files at same level", () => {
29
+ const input = `project
30
+ \u251C\u2500\u2500 file1.txt
31
+ \u251C\u2500\u2500 file2.txt
32
+ \u2514\u2500\u2500 file3.txt`;
33
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
34
+ (0, import_vitest.expect)(extractStructure(result)).toEqual({
35
+ name: "project",
36
+ type: "directory",
37
+ children: [
38
+ { name: "file1.txt", type: "file", children: void 0 },
39
+ { name: "file2.txt", type: "file", children: void 0 },
40
+ { name: "file3.txt", type: "file", children: void 0 }
41
+ ]
42
+ });
43
+ });
44
+ (0, import_vitest.it)("parses nested directories", () => {
45
+ const input = `project
46
+ \u251C\u2500\u2500 src
47
+ \u2502 \u251C\u2500\u2500 index.ts
48
+ \u2502 \u2514\u2500\u2500 utils.ts
49
+ \u2514\u2500\u2500 package.json`;
50
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
51
+ (0, import_vitest.expect)(extractStructure(result)).toEqual({
52
+ name: "project",
53
+ type: "directory",
54
+ children: [
55
+ {
56
+ name: "src",
57
+ type: "directory",
58
+ children: [
59
+ { name: "index.ts", type: "file", children: void 0 },
60
+ { name: "utils.ts", type: "file", children: void 0 }
61
+ ]
62
+ },
63
+ { name: "package.json", type: "file", children: void 0 }
64
+ ]
65
+ });
66
+ });
67
+ });
68
+ (0, import_vitest.describe)("deeply nested structures", () => {
69
+ (0, import_vitest.it)("parses 3 levels of nesting", () => {
70
+ const input = `root
71
+ \u2514\u2500\u2500 level1
72
+ \u2514\u2500\u2500 level2
73
+ \u2514\u2500\u2500 level3.txt`;
74
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
75
+ (0, import_vitest.expect)(extractStructure(result)).toEqual({
76
+ name: "root",
77
+ type: "directory",
78
+ children: [
79
+ {
80
+ name: "level1",
81
+ type: "directory",
82
+ children: [
83
+ {
84
+ name: "level2",
85
+ type: "directory",
86
+ children: [{ name: "level3.txt", type: "file", children: void 0 }]
87
+ }
88
+ ]
89
+ }
90
+ ]
91
+ });
92
+ });
93
+ (0, import_vitest.it)("parses complex nested structure with multiple branches", () => {
94
+ const input = `project
95
+ \u251C\u2500\u2500 src
96
+ \u2502 \u251C\u2500\u2500 components
97
+ \u2502 \u2502 \u251C\u2500\u2500 Button.tsx
98
+ \u2502 \u2502 \u2514\u2500\u2500 Input.tsx
99
+ \u2502 \u2514\u2500\u2500 utils
100
+ \u2502 \u2514\u2500\u2500 helpers.ts
101
+ \u251C\u2500\u2500 tests
102
+ \u2502 \u2514\u2500\u2500 unit
103
+ \u2502 \u2514\u2500\u2500 helpers.test.ts
104
+ \u2514\u2500\u2500 README.md`;
105
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
106
+ (0, import_vitest.expect)(extractStructure(result)).toEqual({
107
+ name: "project",
108
+ type: "directory",
109
+ children: [
110
+ {
111
+ name: "src",
112
+ type: "directory",
113
+ children: [
114
+ {
115
+ name: "components",
116
+ type: "directory",
117
+ children: [
118
+ { name: "Button.tsx", type: "file", children: void 0 },
119
+ { name: "Input.tsx", type: "file", children: void 0 }
120
+ ]
121
+ },
122
+ {
123
+ name: "utils",
124
+ type: "directory",
125
+ children: [{ name: "helpers.ts", type: "file", children: void 0 }]
126
+ }
127
+ ]
128
+ },
129
+ {
130
+ name: "tests",
131
+ type: "directory",
132
+ children: [
133
+ {
134
+ name: "unit",
135
+ type: "directory",
136
+ children: [{ name: "helpers.test.ts", type: "file", children: void 0 }]
137
+ }
138
+ ]
139
+ },
140
+ { name: "README.md", type: "file", children: void 0 }
141
+ ]
142
+ });
143
+ });
144
+ });
145
+ (0, import_vitest.describe)("summary line filtering", () => {
146
+ (0, import_vitest.it)('filters out "X directories, Y files" summary', () => {
147
+ const input = `project
148
+ \u251C\u2500\u2500 src
149
+ \u2502 \u2514\u2500\u2500 index.ts
150
+ \u2514\u2500\u2500 README.md
151
+
152
+ 2 directories, 2 files`;
153
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
154
+ (0, import_vitest.expect)(result?.children?.length).toBe(2);
155
+ (0, import_vitest.expect)(result?.children?.some((c) => c.name.includes("directories"))).toBe(false);
156
+ });
157
+ (0, import_vitest.it)('filters out "X directories" summary', () => {
158
+ const input = `project
159
+ \u251C\u2500\u2500 dir1
160
+ \u2502 \u2514\u2500\u2500 subdir
161
+ \u2514\u2500\u2500 dir2
162
+
163
+ 3 directories`;
164
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
165
+ (0, import_vitest.expect)(result?.children?.some((c) => c.name.includes("directories"))).toBe(false);
166
+ });
167
+ (0, import_vitest.it)('filters out "X files" summary', () => {
168
+ const input = `project
169
+ \u251C\u2500\u2500 file1.txt
170
+ \u2514\u2500\u2500 file2.txt
171
+
172
+ 2 files`;
173
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
174
+ (0, import_vitest.expect)(result?.children?.length).toBe(2);
175
+ });
176
+ });
177
+ (0, import_vitest.describe)("edge cases", () => {
178
+ (0, import_vitest.it)("handles files with spaces in names", () => {
179
+ const input = `project
180
+ \u2514\u2500\u2500 my file with spaces.txt`;
181
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
182
+ (0, import_vitest.expect)(result?.children?.[0]?.name).toBe("my file with spaces.txt");
183
+ });
184
+ (0, import_vitest.it)("handles files with special characters", () => {
185
+ const input = `project
186
+ \u251C\u2500\u2500 file-with-dashes.txt
187
+ \u251C\u2500\u2500 file_with_underscores.txt
188
+ \u2514\u2500\u2500 file.multiple.dots.txt`;
189
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
190
+ (0, import_vitest.expect)(result?.children?.map((c) => c.name)).toEqual([
191
+ "file-with-dashes.txt",
192
+ "file_with_underscores.txt",
193
+ "file.multiple.dots.txt"
194
+ ]);
195
+ });
196
+ (0, import_vitest.it)("handles dotfiles", () => {
197
+ const input = `project
198
+ \u251C\u2500\u2500 .gitignore
199
+ \u251C\u2500\u2500 .env
200
+ \u2514\u2500\u2500 .github
201
+ \u2514\u2500\u2500 workflows
202
+ \u2514\u2500\u2500 ci.yml`;
203
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
204
+ (0, import_vitest.expect)(result?.children?.map((c) => c.name)).toEqual([".gitignore", ".env", ".github"]);
205
+ });
206
+ (0, import_vitest.it)("handles empty directories (directory with no children after it)", () => {
207
+ const input = `project
208
+ \u251C\u2500\u2500 empty-dir
209
+ \u251C\u2500\u2500 file.txt
210
+ \u2514\u2500\u2500 another-dir
211
+ \u2514\u2500\u2500 nested.txt`;
212
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
213
+ (0, import_vitest.expect)(result?.children?.[0]?.name).toBe("empty-dir");
214
+ (0, import_vitest.expect)(result?.children?.[1]?.name).toBe("file.txt");
215
+ });
216
+ (0, import_vitest.it)("handles Windows-style CRLF line endings", () => {
217
+ const input = `project\r
218
+ \u251C\u2500\u2500 file1.txt\r
219
+ \u2514\u2500\u2500 file2.txt`;
220
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
221
+ (0, import_vitest.expect)(result?.children?.length).toBe(2);
222
+ });
223
+ (0, import_vitest.it)("handles tabs instead of spaces", () => {
224
+ const input = `project
225
+ \u251C\u2500\u2500 src
226
+ \u2502 \u2514\u2500\u2500 index.ts
227
+ \u2514\u2500\u2500 README.md`;
228
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
229
+ (0, import_vitest.expect)(extractStructure(result)).toEqual({
230
+ name: "project",
231
+ type: "directory",
232
+ children: [
233
+ {
234
+ name: "src",
235
+ type: "directory",
236
+ children: [{ name: "index.ts", type: "file", children: void 0 }]
237
+ },
238
+ { name: "README.md", type: "file", children: void 0 }
239
+ ]
240
+ });
241
+ });
242
+ });
243
+ (0, import_vitest.describe)("file extension detection", () => {
244
+ (0, import_vitest.it)("extracts file extensions correctly", () => {
245
+ const input = `project
246
+ \u251C\u2500\u2500 script.ts
247
+ \u251C\u2500\u2500 style.css
248
+ \u251C\u2500\u2500 data.json
249
+ \u2514\u2500\u2500 noextension`;
250
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
251
+ (0, import_vitest.expect)(result?.children?.[0]?.extension).toBe("ts");
252
+ (0, import_vitest.expect)(result?.children?.[1]?.extension).toBe("css");
253
+ (0, import_vitest.expect)(result?.children?.[2]?.extension).toBe("json");
254
+ (0, import_vitest.expect)(result?.children?.[3]?.extension).toBeUndefined();
255
+ });
256
+ (0, import_vitest.it)("does not set extension for directories", () => {
257
+ const input = `project
258
+ \u2514\u2500\u2500 src.backup
259
+ \u2514\u2500\u2500 file.ts`;
260
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
261
+ (0, import_vitest.expect)(result?.children?.[0]?.extension).toBeUndefined();
262
+ });
263
+ });
264
+ (0, import_vitest.describe)("alternative tree formats", () => {
265
+ (0, import_vitest.it)("handles tree output without connectors (indentation only)", () => {
266
+ const input = `project
267
+ src
268
+ index.ts
269
+ README.md`;
270
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
271
+ (0, import_vitest.expect)(result).not.toBeNull();
272
+ });
273
+ (0, import_vitest.it)("handles ASCII tree format (using +-- instead of \u251C\u2500\u2500)", () => {
274
+ const input = `project
275
+ +-- src
276
+ | +-- index.ts
277
+ +-- README.md`;
278
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
279
+ (0, import_vitest.expect)(result).not.toBeNull();
280
+ });
281
+ });
282
+ (0, import_vitest.describe)("real-world tree outputs", () => {
283
+ (0, import_vitest.it)("parses typical Next.js project structure", () => {
284
+ const input = `my-app
285
+ \u251C\u2500\u2500 app
286
+ \u2502 \u251C\u2500\u2500 globals.css
287
+ \u2502 \u251C\u2500\u2500 layout.tsx
288
+ \u2502 \u2514\u2500\u2500 page.tsx
289
+ \u251C\u2500\u2500 components
290
+ \u2502 \u2514\u2500\u2500 ui
291
+ \u2502 \u251C\u2500\u2500 button.tsx
292
+ \u2502 \u2514\u2500\u2500 input.tsx
293
+ \u251C\u2500\u2500 lib
294
+ \u2502 \u2514\u2500\u2500 utils.ts
295
+ \u251C\u2500\u2500 public
296
+ \u2502 \u2514\u2500\u2500 favicon.ico
297
+ \u251C\u2500\u2500 next.config.js
298
+ \u251C\u2500\u2500 package.json
299
+ \u2514\u2500\u2500 tsconfig.json
300
+
301
+ 5 directories, 10 files`;
302
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
303
+ (0, import_vitest.expect)(result?.name).toBe("my-app");
304
+ (0, import_vitest.expect)(result?.children?.length).toBe(7);
305
+ (0, import_vitest.expect)(result?.children?.find((c) => c.name === "app")?.children?.length).toBe(3);
306
+ (0, import_vitest.expect)(result?.children?.find((c) => c.name === "components")?.children?.[0]?.name).toBe("ui");
307
+ });
308
+ (0, import_vitest.it)("parses tree with symbolic links notation", () => {
309
+ const input = `project
310
+ \u251C\u2500\u2500 link -> /path/to/target
311
+ \u2514\u2500\u2500 file.txt`;
312
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
313
+ (0, import_vitest.expect)(result?.children?.[0]?.name).toBe("link -> /path/to/target");
314
+ });
315
+ });
316
+ (0, import_vitest.describe)("id generation", () => {
317
+ (0, import_vitest.it)("generates unique IDs for each node", () => {
318
+ const input = `project
319
+ \u251C\u2500\u2500 file1.txt
320
+ \u2514\u2500\u2500 file2.txt`;
321
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
322
+ const ids = /* @__PURE__ */ new Set();
323
+ const collectIds = (node) => {
324
+ ids.add(node.id);
325
+ node.children?.forEach(collectIds);
326
+ };
327
+ if (result) collectIds(result);
328
+ (0, import_vitest.expect)(ids.size).toBe(3);
329
+ });
330
+ (0, import_vitest.it)("generates consistent IDs for same input", () => {
331
+ const input = `project
332
+ \u2514\u2500\u2500 file.txt`;
333
+ const result1 = (0, import_parse_tree_output.parseTreeOutput)(input);
334
+ const result2 = (0, import_parse_tree_output.parseTreeOutput)(input);
335
+ (0, import_vitest.expect)(result1?.id).toBe(result2?.id);
336
+ (0, import_vitest.expect)(result1?.children?.[0]?.id).toBe(result2?.children?.[0]?.id);
337
+ });
338
+ });
339
+ (0, import_vitest.describe)("level tracking", () => {
340
+ (0, import_vitest.it)("assigns correct levels to nodes", () => {
341
+ const input = `root
342
+ \u251C\u2500\u2500 level1
343
+ \u2502 \u2514\u2500\u2500 level2
344
+ \u2502 \u2514\u2500\u2500 level3.txt
345
+ \u2514\u2500\u2500 another-level1.txt`;
346
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
347
+ (0, import_vitest.expect)(result?.level).toBe(0);
348
+ (0, import_vitest.expect)(result?.children?.[0]?.level).toBe(1);
349
+ (0, import_vitest.expect)(result?.children?.[0]?.children?.[0]?.level).toBe(2);
350
+ (0, import_vitest.expect)(result?.children?.[0]?.children?.[0]?.children?.[0]?.level).toBe(3);
351
+ (0, import_vitest.expect)(result?.children?.[1]?.level).toBe(1);
352
+ });
353
+ });
354
+ (0, import_vitest.describe)("Japanese and Unicode support", () => {
355
+ (0, import_vitest.it)("handles Japanese file and directory names", () => {
356
+ const input = `\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8
357
+ \u251C\u2500\u2500 \u30BD\u30FC\u30B9\u30B3\u30FC\u30C9
358
+ \u2502 \u251C\u2500\u2500 \u30E1\u30A4\u30F3.ts
359
+ \u2502 \u2514\u2500\u2500 \u30E6\u30FC\u30C6\u30A3\u30EA\u30C6\u30A3.ts
360
+ \u2514\u2500\u2500 \u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB.json`;
361
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
362
+ (0, import_vitest.expect)(extractStructure(result)).toEqual({
363
+ name: "\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8",
364
+ type: "directory",
365
+ children: [
366
+ {
367
+ name: "\u30BD\u30FC\u30B9\u30B3\u30FC\u30C9",
368
+ type: "directory",
369
+ children: [
370
+ { name: "\u30E1\u30A4\u30F3.ts", type: "file", children: void 0 },
371
+ { name: "\u30E6\u30FC\u30C6\u30A3\u30EA\u30C6\u30A3.ts", type: "file", children: void 0 }
372
+ ]
373
+ },
374
+ { name: "\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB.json", type: "file", children: void 0 }
375
+ ]
376
+ });
377
+ });
378
+ (0, import_vitest.it)("handles mixed Japanese and English names", () => {
379
+ const input = `my-project
380
+ \u251C\u2500\u2500 src
381
+ \u2502 \u251C\u2500\u2500 components
382
+ \u2502 \u2502 \u2514\u2500\u2500 \u30DC\u30BF\u30F3.tsx
383
+ \u2502 \u2514\u2500\u2500 utils
384
+ \u2502 \u2514\u2500\u2500 \u6587\u5B57\u5217\u51E6\u7406.ts
385
+ \u251C\u2500\u2500 \u30C6\u30B9\u30C8
386
+ \u2502 \u2514\u2500\u2500 unit
387
+ \u2502 \u2514\u2500\u2500 \u30DC\u30BF\u30F3.test.tsx
388
+ \u2514\u2500\u2500 README.md`;
389
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
390
+ (0, import_vitest.expect)(result?.name).toBe("my-project");
391
+ (0, import_vitest.expect)(result?.children?.find((c) => c.name === "src")?.children?.[0]?.children?.[0]?.name).toBe("\u30DC\u30BF\u30F3.tsx");
392
+ (0, import_vitest.expect)(result?.children?.find((c) => c.name === "\u30C6\u30B9\u30C8")).toBeDefined();
393
+ });
394
+ (0, import_vitest.it)("handles Chinese characters", () => {
395
+ const input = `\u9879\u76EE
396
+ \u251C\u2500\u2500 \u6E90\u4EE3\u7801
397
+ \u2502 \u2514\u2500\u2500 \u4E3B\u7A0B\u5E8F.ts
398
+ \u2514\u2500\u2500 \u914D\u7F6E.json`;
399
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
400
+ (0, import_vitest.expect)(result?.name).toBe("\u9879\u76EE");
401
+ (0, import_vitest.expect)(result?.children?.[0]?.name).toBe("\u6E90\u4EE3\u7801");
402
+ });
403
+ (0, import_vitest.it)("handles Korean characters", () => {
404
+ const input = `\uD504\uB85C\uC81D\uD2B8
405
+ \u251C\u2500\u2500 \uC18C\uC2A4\uCF54\uB4DC
406
+ \u2502 \u2514\u2500\u2500 \uBA54\uC778.ts
407
+ \u2514\u2500\u2500 \uC124\uC815.json`;
408
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
409
+ (0, import_vitest.expect)(result?.name).toBe("\uD504\uB85C\uC81D\uD2B8");
410
+ (0, import_vitest.expect)(result?.children?.[0]?.name).toBe("\uC18C\uC2A4\uCF54\uB4DC");
411
+ });
412
+ (0, import_vitest.it)("handles emoji in file names", () => {
413
+ const input = `project
414
+ \u251C\u2500\u2500 \u{1F4C1} documents
415
+ \u2502 \u2514\u2500\u2500 \u{1F4C4} readme.md
416
+ \u251C\u2500\u2500 \u{1F3A8} styles.css
417
+ \u2514\u2500\u2500 \u{1F680} app.ts`;
418
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
419
+ (0, import_vitest.expect)(result?.children?.map((c) => c.name)).toEqual(["\u{1F4C1} documents", "\u{1F3A8} styles.css", "\u{1F680} app.ts"]);
420
+ });
421
+ (0, import_vitest.it)("handles full-width characters", () => {
422
+ const input = `\u30D5\u30A9\u30EB\u30C0
423
+ \u251C\u2500\u2500 \uFF26\uFF29\uFF2C\uFF25\uFF11.txt
424
+ \u2514\u2500\u2500 \uFF26\uFF29\uFF2C\uFF25\uFF12.txt`;
425
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
426
+ (0, import_vitest.expect)(result?.children?.[0]?.name).toBe("\uFF26\uFF29\uFF2C\uFF25\uFF11.txt");
427
+ });
428
+ });
429
+ (0, import_vitest.describe)("special characters and edge cases", () => {
430
+ (0, import_vitest.it)("handles parentheses and brackets in names", () => {
431
+ const input = `project
432
+ \u251C\u2500\u2500 file (1).txt
433
+ \u251C\u2500\u2500 file [backup].txt
434
+ \u251C\u2500\u2500 file {temp}.txt
435
+ \u2514\u2500\u2500 file <draft>.txt`;
436
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
437
+ (0, import_vitest.expect)(result?.children?.map((c) => c.name)).toEqual([
438
+ "file (1).txt",
439
+ "file [backup].txt",
440
+ "file {temp}.txt",
441
+ "file <draft>.txt"
442
+ ]);
443
+ });
444
+ (0, import_vitest.it)("handles quotes in file names", () => {
445
+ const input = `project
446
+ \u251C\u2500\u2500 "quoted".txt
447
+ \u251C\u2500\u2500 'single-quoted'.txt
448
+ \u2514\u2500\u2500 \`backtick\`.txt`;
449
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
450
+ (0, import_vitest.expect)(result?.children?.[0]?.name).toBe('"quoted".txt');
451
+ (0, import_vitest.expect)(result?.children?.[1]?.name).toBe("'single-quoted'.txt");
452
+ });
453
+ (0, import_vitest.it)("handles hash and at symbols", () => {
454
+ const input = `project
455
+ \u251C\u2500\u2500 #1-issue.md
456
+ \u251C\u2500\u2500 @types
457
+ \u2502 \u2514\u2500\u2500 index.d.ts
458
+ \u2514\u2500\u2500 file@2x.png`;
459
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
460
+ (0, import_vitest.expect)(result?.children?.[0]?.name).toBe("#1-issue.md");
461
+ (0, import_vitest.expect)(result?.children?.[1]?.name).toBe("@types");
462
+ });
463
+ (0, import_vitest.it)("handles ampersand and percent", () => {
464
+ const input = `project
465
+ \u251C\u2500\u2500 Tom & Jerry.txt
466
+ \u251C\u2500\u2500 100%.txt
467
+ \u2514\u2500\u2500 a&b&c.txt`;
468
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
469
+ (0, import_vitest.expect)(result?.children?.[0]?.name).toBe("Tom & Jerry.txt");
470
+ (0, import_vitest.expect)(result?.children?.[1]?.name).toBe("100%.txt");
471
+ });
472
+ (0, import_vitest.it)("handles very long file names", () => {
473
+ const longName = "a".repeat(200) + ".txt";
474
+ const input = `project
475
+ \u2514\u2500\u2500 ${longName}`;
476
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
477
+ (0, import_vitest.expect)(result?.children?.[0]?.name).toBe(longName);
478
+ });
479
+ (0, import_vitest.it)("handles file names with colons (Windows-style paths preserved)", () => {
480
+ const input = `project
481
+ \u2514\u2500\u2500 note: important.txt`;
482
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
483
+ (0, import_vitest.expect)(result?.children?.[0]?.name).toBe("note: important.txt");
484
+ });
485
+ (0, import_vitest.it)("handles equals and plus signs", () => {
486
+ const input = `project
487
+ \u251C\u2500\u2500 a=b.txt
488
+ \u251C\u2500\u2500 a+b.txt
489
+ \u2514\u2500\u2500 a==b.txt`;
490
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
491
+ (0, import_vitest.expect)(result?.children?.map((c) => c.name)).toEqual(["a=b.txt", "a+b.txt", "a==b.txt"]);
492
+ });
493
+ });
494
+ (0, import_vitest.describe)("deeply nested and large structures", () => {
495
+ (0, import_vitest.it)("handles 5 levels of nesting", () => {
496
+ const input = `root
497
+ \u2514\u2500\u2500 l1
498
+ \u2514\u2500\u2500 l2
499
+ \u2514\u2500\u2500 l3
500
+ \u2514\u2500\u2500 l4
501
+ \u2514\u2500\u2500 l5.txt`;
502
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
503
+ (0, import_vitest.expect)(result?.name).toBe("root");
504
+ let current = result;
505
+ const expectedPath = ["l1", "l2", "l3", "l4", "l5.txt"];
506
+ for (const expectedName of expectedPath) {
507
+ (0, import_vitest.expect)(current?.children?.length).toBe(1);
508
+ current = current?.children?.[0] ?? null;
509
+ (0, import_vitest.expect)(current?.name).toBe(expectedName);
510
+ }
511
+ (0, import_vitest.expect)(current?.type).toBe("file");
512
+ });
513
+ (0, import_vitest.it)("handles many files at same level", () => {
514
+ const files = Array.from({ length: 20 }, (_, i) => `file${i + 1}.txt`);
515
+ const input = `project
516
+ ${files.map((f, i) => `${i === files.length - 1 ? "\u2514" : "\u251C"}\u2500\u2500 ${f}`).join("\n")}`;
517
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
518
+ (0, import_vitest.expect)(result?.children?.length).toBe(20);
519
+ (0, import_vitest.expect)(result?.children?.map((c) => c.name)).toEqual(files);
520
+ });
521
+ (0, import_vitest.it)("handles wide tree with many branches at each level", () => {
522
+ const input = `project
523
+ \u251C\u2500\u2500 dir1
524
+ \u2502 \u251C\u2500\u2500 file1.txt
525
+ \u2502 \u251C\u2500\u2500 file2.txt
526
+ \u2502 \u2514\u2500\u2500 file3.txt
527
+ \u251C\u2500\u2500 dir2
528
+ \u2502 \u251C\u2500\u2500 file4.txt
529
+ \u2502 \u251C\u2500\u2500 file5.txt
530
+ \u2502 \u2514\u2500\u2500 file6.txt
531
+ \u251C\u2500\u2500 dir3
532
+ \u2502 \u251C\u2500\u2500 file7.txt
533
+ \u2502 \u251C\u2500\u2500 file8.txt
534
+ \u2502 \u2514\u2500\u2500 file9.txt
535
+ \u2514\u2500\u2500 dir4
536
+ \u251C\u2500\u2500 file10.txt
537
+ \u251C\u2500\u2500 file11.txt
538
+ \u2514\u2500\u2500 file12.txt`;
539
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
540
+ (0, import_vitest.expect)(result?.children?.length).toBe(4);
541
+ result?.children?.forEach((dir) => {
542
+ (0, import_vitest.expect)(dir.type).toBe("directory");
543
+ (0, import_vitest.expect)(dir.children?.length).toBe(3);
544
+ });
545
+ });
546
+ });
547
+ (0, import_vitest.describe)("various tree command outputs", () => {
548
+ (0, import_vitest.it)("handles tree output with file sizes", () => {
549
+ const input = `project
550
+ \u251C\u2500\u2500 [4.0K] src
551
+ \u2502 \u2514\u2500\u2500 [1.2K] index.ts
552
+ \u2514\u2500\u2500 [ 512] README.md`;
553
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
554
+ (0, import_vitest.expect)(result?.children?.length).toBe(2);
555
+ (0, import_vitest.expect)(result?.children?.[0]?.name).toContain("src");
556
+ });
557
+ (0, import_vitest.it)("handles tree output with permissions", () => {
558
+ const input = `project
559
+ \u251C\u2500\u2500 [-rw-r--r--] file1.txt
560
+ \u2514\u2500\u2500 [drwxr-xr-x] dir1
561
+ \u2514\u2500\u2500 [-rw-r--r--] file2.txt`;
562
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
563
+ (0, import_vitest.expect)(result?.children?.length).toBe(2);
564
+ });
565
+ (0, import_vitest.it)("handles tree -F output (with type indicators)", () => {
566
+ const input = `project/
567
+ \u251C\u2500\u2500 src/
568
+ \u2502 \u251C\u2500\u2500 index.ts
569
+ \u2502 \u2514\u2500\u2500 utils/
570
+ \u2502 \u2514\u2500\u2500 helper.ts
571
+ \u251C\u2500\u2500 package.json
572
+ \u2514\u2500\u2500 README.md`;
573
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
574
+ (0, import_vitest.expect)(result?.name).toBe("project/");
575
+ (0, import_vitest.expect)(result?.children?.find((c) => c.name === "src/")?.type).toBe("directory");
576
+ });
577
+ (0, import_vitest.it)("handles tree with trailing slash for directories", () => {
578
+ const input = `project
579
+ \u251C\u2500\u2500 src/
580
+ \u2502 \u2514\u2500\u2500 index.ts
581
+ \u2514\u2500\u2500 dist/
582
+ \u2514\u2500\u2500 bundle.js`;
583
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
584
+ (0, import_vitest.expect)(result?.children?.[0]?.name).toBe("src/");
585
+ (0, import_vitest.expect)(result?.children?.[0]?.type).toBe("directory");
586
+ });
587
+ });
588
+ (0, import_vitest.describe)("error handling and robustness", () => {
589
+ (0, import_vitest.it)("handles single line input (root only)", () => {
590
+ const input = `project`;
591
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
592
+ (0, import_vitest.expect)(result?.name).toBe("project");
593
+ (0, import_vitest.expect)(result?.children).toEqual([]);
594
+ });
595
+ (0, import_vitest.it)("handles input with only whitespace lines between entries", () => {
596
+ const input = `project
597
+ \u251C\u2500\u2500 file1.txt
598
+
599
+ \u251C\u2500\u2500 file2.txt
600
+
601
+ \u2514\u2500\u2500 file3.txt`;
602
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
603
+ (0, import_vitest.expect)(result?.children?.length).toBe(3);
604
+ });
605
+ (0, import_vitest.it)("handles malformed lines gracefully", () => {
606
+ const input = `project
607
+ \u251C\u2500\u2500 valid-file.txt
608
+ some random text
609
+ \u2514\u2500\u2500 another-valid.txt`;
610
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
611
+ (0, import_vitest.expect)(result).not.toBeNull();
612
+ });
613
+ (0, import_vitest.it)("handles input with leading/trailing empty lines", () => {
614
+ const input = `
615
+
616
+ project
617
+ \u251C\u2500\u2500 file1.txt
618
+ \u2514\u2500\u2500 file2.txt
619
+
620
+ `;
621
+ const result = (0, import_parse_tree_output.parseTreeOutput)(input);
622
+ (0, import_vitest.expect)(result?.name).toBe("project");
623
+ (0, import_vitest.expect)(result?.children?.length).toBe(2);
624
+ });
625
+ });
626
+ });
627
+ //# sourceMappingURL=parse-tree-output.unit.test.js.map