rspress-plugin-file-tree 0.3.0 → 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 (38) hide show
  1. package/dist/components/FileTree/FileTree.d.ts +7 -0
  2. package/dist/components/FileTree/FileTree.js +13 -0
  3. package/dist/components/FileTree/FileTree.module.js +5 -0
  4. package/dist/components/FileTree/FileTreeItem.d.ts +8 -0
  5. package/dist/components/FileTree/FileTreeItem.js +80 -0
  6. package/dist/components/FileTree/FileTreeItem.module.js +11 -0
  7. package/dist/components/FileTree/FileTreeItem_module.css +71 -0
  8. package/dist/components/FileTree/FileTree_module.css +12 -0
  9. package/dist/components/FileTree/RemoteSvgIcon.d.ts +11 -0
  10. package/dist/components/FileTree/RemoteSvgIcon.js +26 -0
  11. package/dist/components/FileTree/index.d.ts +4 -0
  12. package/dist/components/FileTree/index.js +4 -0
  13. package/dist/components/folder-icons.d.ts +32 -0
  14. package/dist/components/folder-icons.js +177 -0
  15. package/dist/components/languages.d.ts +7 -0
  16. package/dist/components/languages.js +98 -0
  17. package/dist/components/tree-parser/tree-parser.d.ts +12 -0
  18. package/dist/components/tree-parser/tree-parser.js +68 -0
  19. package/dist/components/tree-parser/types.d.ts +10 -0
  20. package/dist/components/tree-parser/types.js +0 -0
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +18 -17
  23. package/package.json +11 -8
  24. package/components/Tree/Expand.tsx +0 -149
  25. package/components/Tree/FileIcon.tsx +0 -41
  26. package/components/Tree/FileTreeRender.tsx +0 -16
  27. package/components/Tree/Tree.tsx +0 -112
  28. package/components/Tree/TreeContext.tsx +0 -18
  29. package/components/Tree/TreeFile.tsx +0 -69
  30. package/components/Tree/TreeFolder.tsx +0 -108
  31. package/components/Tree/TreeFolderIcon.tsx +0 -40
  32. package/components/Tree/TreeIndents.tsx +0 -26
  33. package/components/Tree/TreeStatusIcon.tsx +0 -45
  34. package/components/Tree/index.less +0 -178
  35. package/components/helpers.ts +0 -42
  36. package/components/presets.ts +0 -5
  37. package/dist/parser.d.ts +0 -7
  38. package/dist/parser.js +0 -37
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import { TreeNode } from '../tree-parser/types';
3
+ interface FileTreeProps {
4
+ nodes: TreeNode[];
5
+ }
6
+ export declare const FileTree: React.FC<FileTreeProps>;
7
+ export default FileTree;
@@ -0,0 +1,13 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import "react";
3
+ import FileTree_module from "./FileTree.module.js";
4
+ import { FileTreeItem } from "./FileTreeItem.js";
5
+ const FileTree = ({ nodes })=>/*#__PURE__*/ jsx("div", {
6
+ className: FileTree_module.container,
7
+ children: nodes.map((node, index)=>/*#__PURE__*/ jsx(FileTreeItem, {
8
+ node: node,
9
+ depth: 0
10
+ }, `${node.name}-${index}`))
11
+ });
12
+ const FileTree_FileTree = FileTree;
13
+ export { FileTree, FileTree_FileTree as default };
@@ -0,0 +1,5 @@
1
+ import "./FileTree_module.css";
2
+ const FileTree_module = {
3
+ container: "container-ZPDb1C"
4
+ };
5
+ export { FileTree_module as default };
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { TreeNode } from '../tree-parser/types';
3
+ interface FileTreeItemProps {
4
+ node: TreeNode;
5
+ depth: number;
6
+ }
7
+ export declare const FileTreeItem: React.FC<FileTreeItemProps>;
8
+ export {};
@@ -0,0 +1,80 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useMemo, useState } from "react";
3
+ import { getFileIcon, getFolderIcon } from "../folder-icons.js";
4
+ import FileTreeItem_module from "./FileTreeItem.module.js";
5
+ import { RemoteSvgIcon } from "./RemoteSvgIcon.js";
6
+ const INDENT_SIZE = 12;
7
+ const FileTreeItem = ({ node, depth })=>{
8
+ const [expanded, setExpanded] = useState(true);
9
+ const icon = useMemo(()=>{
10
+ if ('directory' === node.type) return getFolderIcon(node.name);
11
+ return getFileIcon(node.name);
12
+ }, [
13
+ node.name,
14
+ node.type
15
+ ]);
16
+ const isDirectory = 'directory' === node.type;
17
+ const toggle = (e)=>{
18
+ e.stopPropagation();
19
+ if (isDirectory) setExpanded((p)=>!p);
20
+ };
21
+ return /*#__PURE__*/ jsxs("div", {
22
+ className: FileTreeItem_module.item,
23
+ children: [
24
+ /*#__PURE__*/ jsxs("div", {
25
+ className: FileTreeItem_module.row,
26
+ onClick: toggle,
27
+ style: {
28
+ paddingLeft: `${depth * INDENT_SIZE}px`
29
+ },
30
+ children: [
31
+ /*#__PURE__*/ jsx("div", {
32
+ className: FileTreeItem_module.chevron,
33
+ "data-expanded": expanded,
34
+ style: {
35
+ visibility: isDirectory ? 'visible' : 'hidden'
36
+ },
37
+ children: /*#__PURE__*/ jsx("svg", {
38
+ width: "16",
39
+ height: "16",
40
+ viewBox: "0 0 16 16",
41
+ fill: "currentColor",
42
+ children: /*#__PURE__*/ jsx("path", {
43
+ fillRule: "evenodd",
44
+ clipRule: "evenodd",
45
+ d: "M10.072 8.024L5.715 3.667l.618-.62L11 8.024l-4.667 4.977-.618-.62L10.072 8.024z"
46
+ })
47
+ })
48
+ }),
49
+ /*#__PURE__*/ jsx("div", {
50
+ className: FileTreeItem_module.iconWrapper,
51
+ children: /*#__PURE__*/ jsx(RemoteSvgIcon, {
52
+ content: icon.content,
53
+ className: FileTreeItem_module.iconWrapper
54
+ })
55
+ }),
56
+ /*#__PURE__*/ jsx("span", {
57
+ className: FileTreeItem_module.name,
58
+ children: node.name
59
+ })
60
+ ]
61
+ }),
62
+ isDirectory && node.children.length > 0 && expanded && /*#__PURE__*/ jsxs("div", {
63
+ className: FileTreeItem_module.children,
64
+ children: [
65
+ /*#__PURE__*/ jsx("div", {
66
+ className: FileTreeItem_module.indentGuide,
67
+ style: {
68
+ left: `${depth * INDENT_SIZE + 6}px`
69
+ }
70
+ }),
71
+ node.children.map((child, index)=>/*#__PURE__*/ jsx(FileTreeItem, {
72
+ node: child,
73
+ depth: depth + 1
74
+ }, `${child.name}-${index}`))
75
+ ]
76
+ })
77
+ ]
78
+ });
79
+ };
80
+ export { FileTreeItem };
@@ -0,0 +1,11 @@
1
+ import "./FileTreeItem_module.css";
2
+ const FileTreeItem_module = {
3
+ item: "item-mfHlfR",
4
+ row: "row-AOLrYw",
5
+ chevron: "chevron-Zi120f",
6
+ iconWrapper: "iconWrapper-SwAXs4",
7
+ name: "name-ItNtUc",
8
+ children: "children-yp3kEz",
9
+ indentGuide: "indentGuide-bjr2fi"
10
+ };
11
+ export { FileTreeItem_module as default };
@@ -0,0 +1,71 @@
1
+ .item-mfHlfR {
2
+ flex-direction: column;
3
+ display: flex;
4
+ position: relative;
5
+ }
6
+
7
+ .row-AOLrYw {
8
+ cursor: pointer;
9
+ -webkit-user-select: none;
10
+ user-select: none;
11
+ height: 22px;
12
+ color: inherit;
13
+ opacity: .8;
14
+ align-items: center;
15
+ gap: 6px;
16
+ padding-right: 12px;
17
+ transition: opacity .1s;
18
+ display: flex;
19
+ }
20
+
21
+ .row-AOLrYw:hover {
22
+ background-color: var(--rp-c-text-code-bg);
23
+ opacity: 1;
24
+ }
25
+
26
+ .chevron-Zi120f {
27
+ justify-content: center;
28
+ align-items: center;
29
+ width: 16px;
30
+ height: 16px;
31
+ transition: transform .15s;
32
+ display: flex;
33
+ transform: rotate(0);
34
+ }
35
+
36
+ .chevron-Zi120f[data-expanded="true"] {
37
+ transform: rotate(90deg);
38
+ }
39
+
40
+ .iconWrapper-SwAXs4 {
41
+ flex-shrink: 0;
42
+ justify-content: center;
43
+ align-items: center;
44
+ width: 16px;
45
+ height: 16px;
46
+ display: inline-flex;
47
+ }
48
+
49
+ .name-ItNtUc {
50
+ white-space: nowrap;
51
+ text-overflow: ellipsis;
52
+ overflow: hidden;
53
+ }
54
+
55
+ .children-yp3kEz {
56
+ flex-direction: column;
57
+ display: flex;
58
+ position: relative;
59
+ }
60
+
61
+ .indentGuide-bjr2fi {
62
+ background-color: var(--rp-c-divider);
63
+ opacity: .1;
64
+ pointer-events: none;
65
+ width: 1px;
66
+ position: absolute;
67
+ top: 0;
68
+ bottom: 0;
69
+ left: 6px;
70
+ }
71
+
@@ -0,0 +1,12 @@
1
+ .container-ZPDb1C {
2
+ box-sizing: border-box;
3
+ border-radius: var(--rp-radius);
4
+ border: var(--rp-code-block-border, 1px solid var(--rp-c-divider-light));
5
+ min-height: 100%;
6
+ box-shadow: var(--rp-code-block-shadow, none);
7
+ padding: 8px;
8
+ font-family: inherit;
9
+ font-size: 13px;
10
+ line-height: 22px;
11
+ }
12
+
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ interface RemoteSvgIconProps {
3
+ content: () => Promise<{
4
+ default: string;
5
+ } | string>;
6
+ size?: 'sm' | 'md';
7
+ delay?: number;
8
+ className?: string;
9
+ }
10
+ export declare const RemoteSvgIcon: React.FC<RemoteSvgIconProps>;
11
+ export {};
@@ -0,0 +1,26 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useEffect, useState } from "react";
3
+ const RemoteSvgIcon = ({ content, className })=>{
4
+ const [svgContent, setSvgContent] = useState('');
5
+ useEffect(()=>{
6
+ let cancelled = false;
7
+ content().then((mod)=>{
8
+ if (cancelled) return;
9
+ const svg = 'string' == typeof mod ? mod : mod.default;
10
+ setSvgContent(svg);
11
+ });
12
+ return ()=>{
13
+ cancelled = true;
14
+ };
15
+ }, [
16
+ content
17
+ ]);
18
+ if (!svgContent) return null;
19
+ return /*#__PURE__*/ jsx("span", {
20
+ className: className,
21
+ dangerouslySetInnerHTML: {
22
+ __html: svgContent
23
+ }
24
+ });
25
+ };
26
+ export { RemoteSvgIcon };
@@ -0,0 +1,4 @@
1
+ import { FileTree } from './FileTree';
2
+ export default FileTree;
3
+ export { FileTree };
4
+ export { FileTreeItem } from './FileTreeItem';
@@ -0,0 +1,4 @@
1
+ import { FileTree } from "./FileTree.js";
2
+ import { FileTreeItem } from "./FileTreeItem.js";
3
+ const components_FileTree = FileTree;
4
+ export { FileTree, FileTreeItem, components_FileTree as default };
@@ -0,0 +1,32 @@
1
+ /// <reference path="../../src/env.d.ts" />
2
+ export interface FolderIconDefinition {
3
+ name: string;
4
+ content: () => Promise<typeof import('*.svg')>;
5
+ }
6
+ export interface FileIconDefinition {
7
+ name: string;
8
+ content: () => Promise<typeof import('*.svg')>;
9
+ matcher: RegExp;
10
+ }
11
+ /**
12
+ * Special folder icons mapping
13
+ * Maps folder names to their corresponding icons
14
+ */
15
+ export declare const FOLDER_ICONS: Record<string, FolderIconDefinition>;
16
+ /**
17
+ * Default folder icon
18
+ */
19
+ export declare const DEFAULT_FOLDER_ICON: FolderIconDefinition;
20
+ /**
21
+ * Default file icon
22
+ */
23
+ export declare const DEFAULT_FILE_ICON: FileIconDefinition;
24
+ /**
25
+ * Get folder icon by folder name
26
+ */
27
+ export declare function getFolderIcon(name: string): FolderIconDefinition;
28
+ /**
29
+ * Get file icon by file name
30
+ * Searches through all supported languages for matching icon
31
+ */
32
+ export declare function getFileIcon(fileName: string): FileIconDefinition;
@@ -0,0 +1,177 @@
1
+ import { SUPPORTED_LANGUAGES } from "./languages.js";
2
+ const FOLDER_ICONS = {
3
+ src: {
4
+ name: 'folder-src',
5
+ content: ()=>import("material-icon-theme/icons/folder-src.svg?raw")
6
+ },
7
+ source: {
8
+ name: 'folder-src',
9
+ content: ()=>import("material-icon-theme/icons/folder-src.svg?raw")
10
+ },
11
+ components: {
12
+ name: 'folder-components',
13
+ content: ()=>import("material-icon-theme/icons/folder-components.svg?raw")
14
+ },
15
+ component: {
16
+ name: 'folder-components',
17
+ content: ()=>import("material-icon-theme/icons/folder-components.svg?raw")
18
+ },
19
+ hooks: {
20
+ name: 'folder-hook',
21
+ content: ()=>import("material-icon-theme/icons/folder-hook.svg?raw")
22
+ },
23
+ hook: {
24
+ name: 'folder-hook',
25
+ content: ()=>import("material-icon-theme/icons/folder-hook.svg?raw")
26
+ },
27
+ utils: {
28
+ name: 'folder-utils',
29
+ content: ()=>import("material-icon-theme/icons/folder-utils.svg?raw")
30
+ },
31
+ util: {
32
+ name: 'folder-utils',
33
+ content: ()=>import("material-icon-theme/icons/folder-utils.svg?raw")
34
+ },
35
+ lib: {
36
+ name: 'folder-lib',
37
+ content: ()=>import("material-icon-theme/icons/folder-lib.svg?raw")
38
+ },
39
+ libs: {
40
+ name: 'folder-lib',
41
+ content: ()=>import("material-icon-theme/icons/folder-lib.svg?raw")
42
+ },
43
+ core: {
44
+ name: 'folder-core',
45
+ content: ()=>import("material-icon-theme/icons/folder-core.svg?raw")
46
+ },
47
+ runtime: {
48
+ name: 'folder-core',
49
+ content: ()=>import("material-icon-theme/icons/folder-core.svg?raw")
50
+ },
51
+ locales: {
52
+ name: 'folder-i18n',
53
+ content: ()=>import("material-icon-theme/icons/folder-i18n.svg?raw")
54
+ },
55
+ locale: {
56
+ name: 'folder-i18n',
57
+ content: ()=>import("material-icon-theme/icons/folder-i18n.svg?raw")
58
+ },
59
+ i18n: {
60
+ name: 'folder-i18n',
61
+ content: ()=>import("material-icon-theme/icons/folder-i18n.svg?raw")
62
+ },
63
+ assets: {
64
+ name: 'folder-images',
65
+ content: ()=>import("material-icon-theme/icons/folder-images.svg?raw")
66
+ },
67
+ images: {
68
+ name: 'folder-images',
69
+ content: ()=>import("material-icon-theme/icons/folder-images.svg?raw")
70
+ },
71
+ styles: {
72
+ name: 'folder-css',
73
+ content: ()=>import("material-icon-theme/icons/folder-css.svg?raw")
74
+ },
75
+ css: {
76
+ name: 'folder-css',
77
+ content: ()=>import("material-icon-theme/icons/folder-css.svg?raw")
78
+ },
79
+ test: {
80
+ name: 'folder-test',
81
+ content: ()=>import("material-icon-theme/icons/folder-test.svg?raw")
82
+ },
83
+ tests: {
84
+ name: 'folder-test',
85
+ content: ()=>import("material-icon-theme/icons/folder-test.svg?raw")
86
+ },
87
+ __tests__: {
88
+ name: 'folder-test',
89
+ content: ()=>import("material-icon-theme/icons/folder-test.svg?raw")
90
+ },
91
+ config: {
92
+ name: 'folder-config',
93
+ content: ()=>import("material-icon-theme/icons/folder-config.svg?raw")
94
+ },
95
+ configs: {
96
+ name: 'folder-config',
97
+ content: ()=>import("material-icon-theme/icons/folder-config.svg?raw")
98
+ },
99
+ api: {
100
+ name: 'folder-api',
101
+ content: ()=>import("material-icon-theme/icons/folder-api.svg?raw")
102
+ },
103
+ apis: {
104
+ name: 'folder-api',
105
+ content: ()=>import("material-icon-theme/icons/folder-api.svg?raw")
106
+ },
107
+ public: {
108
+ name: 'folder-public',
109
+ content: ()=>import("material-icon-theme/icons/folder-public.svg?raw")
110
+ },
111
+ dist: {
112
+ name: 'folder-dist',
113
+ content: ()=>import("material-icon-theme/icons/folder-dist.svg?raw")
114
+ },
115
+ build: {
116
+ name: 'folder-dist',
117
+ content: ()=>import("material-icon-theme/icons/folder-dist.svg?raw")
118
+ },
119
+ node_modules: {
120
+ name: 'folder-node',
121
+ content: ()=>import("material-icon-theme/icons/folder-node.svg?raw")
122
+ },
123
+ types: {
124
+ name: "folder-typescript",
125
+ content: ()=>import("material-icon-theme/icons/folder-typescript.svg?raw")
126
+ },
127
+ typings: {
128
+ name: "folder-typescript",
129
+ content: ()=>import("material-icon-theme/icons/folder-typescript.svg?raw")
130
+ },
131
+ pages: {
132
+ name: 'folder-views',
133
+ content: ()=>import("material-icon-theme/icons/folder-views.svg?raw")
134
+ },
135
+ views: {
136
+ name: 'folder-views',
137
+ content: ()=>import("material-icon-theme/icons/folder-views.svg?raw")
138
+ },
139
+ routes: {
140
+ name: 'folder-routes',
141
+ content: ()=>import("material-icon-theme/icons/folder-routes.svg?raw")
142
+ },
143
+ docs: {
144
+ name: 'folder-docs',
145
+ content: ()=>import("material-icon-theme/icons/folder-docs.svg?raw")
146
+ },
147
+ services: {
148
+ name: 'folder-app',
149
+ content: ()=>import("material-icon-theme/icons/folder-app.svg?raw")
150
+ },
151
+ app: {
152
+ name: 'folder-app',
153
+ content: ()=>import("material-icon-theme/icons/folder-app.svg?raw")
154
+ }
155
+ };
156
+ const DEFAULT_FOLDER_ICON = {
157
+ name: 'folder',
158
+ content: ()=>import("material-icon-theme/icons/folder.svg?raw")
159
+ };
160
+ const DEFAULT_FILE_ICON = {
161
+ name: 'file',
162
+ content: ()=>import("material-icon-theme/icons/file.svg?raw"),
163
+ matcher: /^.*$/
164
+ };
165
+ function getFolderIcon(name) {
166
+ const lowerName = name.toLowerCase();
167
+ return FOLDER_ICONS[lowerName] || DEFAULT_FOLDER_ICON;
168
+ }
169
+ function getFileIcon(fileName) {
170
+ for (const language of SUPPORTED_LANGUAGES)for (const icon of language.icons)if (icon.matcher.test(fileName)) return {
171
+ name: icon.name,
172
+ content: icon.content,
173
+ matcher: icon.matcher
174
+ };
175
+ return DEFAULT_FILE_ICON;
176
+ }
177
+ export { DEFAULT_FILE_ICON, DEFAULT_FOLDER_ICON, FOLDER_ICONS, getFileIcon, getFolderIcon };
@@ -0,0 +1,7 @@
1
+ import { FileIconDefinition } from './folder-icons';
2
+ interface LanguageDefinition {
3
+ id: string;
4
+ icons: FileIconDefinition[];
5
+ }
6
+ export declare const SUPPORTED_LANGUAGES: LanguageDefinition[];
7
+ export {};
@@ -0,0 +1,98 @@
1
+ const SUPPORTED_LANGUAGES = [
2
+ {
3
+ id: "javascript",
4
+ icons: [
5
+ {
6
+ name: "javascript",
7
+ content: ()=>import("material-icon-theme/icons/javascript.svg?raw"),
8
+ matcher: /^.*\.js$/
9
+ },
10
+ {
11
+ name: "javascript-beta",
12
+ content: ()=>import("material-icon-theme/icons/javascript.svg?raw"),
13
+ matcher: /^.*\.cjs$/
14
+ },
15
+ {
16
+ name: "javascript-beta",
17
+ content: ()=>import("material-icon-theme/icons/javascript.svg?raw"),
18
+ matcher: /^.*\.mjs$/
19
+ }
20
+ ]
21
+ },
22
+ {
23
+ id: "typescript",
24
+ icons: [
25
+ {
26
+ name: "typescript",
27
+ content: ()=>import("material-icon-theme/icons/typescript.svg?raw"),
28
+ matcher: /^.*\.ts$/
29
+ },
30
+ {
31
+ name: "typescript-beta",
32
+ content: ()=>import("material-icon-theme/icons/typescript.svg?raw"),
33
+ matcher: /^.*\.mts$/
34
+ },
35
+ {
36
+ name: "typescript-beta",
37
+ content: ()=>import("material-icon-theme/icons/typescript.svg?raw"),
38
+ matcher: /^.*\.cts$/
39
+ },
40
+ {
41
+ name: 'react_ts',
42
+ content: ()=>import("material-icon-theme/icons/react_ts.svg?raw"),
43
+ matcher: /^.*\.tsx$/
44
+ }
45
+ ]
46
+ },
47
+ {
48
+ id: 'react',
49
+ icons: [
50
+ {
51
+ name: 'react',
52
+ content: ()=>import("material-icon-theme/icons/react.svg?raw"),
53
+ matcher: /^.*\.jsx$/
54
+ }
55
+ ]
56
+ },
57
+ {
58
+ id: 'css',
59
+ icons: [
60
+ {
61
+ name: 'css',
62
+ content: ()=>import("material-icon-theme/icons/css.svg?raw"),
63
+ matcher: /^.*\.css$/
64
+ },
65
+ {
66
+ name: 'less',
67
+ content: ()=>import("material-icon-theme/icons/less.svg?raw"),
68
+ matcher: /^.*\.less$/
69
+ },
70
+ {
71
+ name: 'sass',
72
+ content: ()=>import("material-icon-theme/icons/sass.svg?raw"),
73
+ matcher: /^.*\.scss$/
74
+ }
75
+ ]
76
+ },
77
+ {
78
+ id: 'json',
79
+ icons: [
80
+ {
81
+ name: 'json',
82
+ content: ()=>import("material-icon-theme/icons/json.svg?raw"),
83
+ matcher: /^.*\.json$/
84
+ }
85
+ ]
86
+ },
87
+ {
88
+ id: 'markdown',
89
+ icons: [
90
+ {
91
+ name: 'markdown',
92
+ content: ()=>import("material-icon-theme/icons/markdown.svg?raw"),
93
+ matcher: /^.*\.(md|mdx)$/
94
+ }
95
+ ]
96
+ }
97
+ ];
98
+ export { SUPPORTED_LANGUAGES };
@@ -0,0 +1,12 @@
1
+ import { ParsedTree } from './types';
2
+ /**
3
+ * Parse tree-style directory structure text into TreeNode array
4
+ *
5
+ * Supported formats:
6
+ * doc_build
7
+ * ├── file.ts
8
+ * └── folder
9
+ * ├── nested.ts
10
+ * └── another.ts
11
+ */
12
+ export declare function parseTreeContent(content: string): ParsedTree;
@@ -0,0 +1,68 @@
1
+ function parseTreeContent(content) {
2
+ const lines = content.split('\n').filter((line)=>line.trim());
3
+ const nodes = [];
4
+ const stack = [];
5
+ for (const line of lines){
6
+ const indent = calculateIndent(line);
7
+ const fullName = extractName(line);
8
+ const commentMatch = fullName.match(/^(.*?)(?:\s*\/\/\s*(.*))?$/);
9
+ const name = commentMatch ? commentMatch[1].trim() : fullName;
10
+ if (!name) continue;
11
+ const isDirectory = isDirectoryName(name);
12
+ const node = {
13
+ name: name.replace(/\/$/, ''),
14
+ type: isDirectory ? 'directory' : 'file',
15
+ children: [],
16
+ extension: isDirectory ? void 0 : getExtension(name)
17
+ };
18
+ while(stack.length > 0 && stack[stack.length - 1].indent >= indent)stack.pop();
19
+ if (0 === stack.length) nodes.push(node);
20
+ else stack[stack.length - 1].node.children.push(node);
21
+ if ('directory' === node.type) stack.push({
22
+ node,
23
+ indent
24
+ });
25
+ }
26
+ return {
27
+ nodes,
28
+ raw: content
29
+ };
30
+ }
31
+ function calculateIndent(line) {
32
+ let indent = 0;
33
+ let i = 0;
34
+ while(i < line.length){
35
+ const char = line[i];
36
+ if ('│' === char && '│ ' === line.substring(i, i + 4)) {
37
+ indent++;
38
+ i += 4;
39
+ continue;
40
+ }
41
+ if (' ' === line.substring(i, i + 4)) {
42
+ indent++;
43
+ i += 4;
44
+ continue;
45
+ }
46
+ if ('├' === char || '└' === char) {
47
+ if ('├──' === line.substring(i, i + 3) || '└──' === line.substring(i, i + 3)) indent++;
48
+ }
49
+ break;
50
+ }
51
+ return indent;
52
+ }
53
+ function extractName(line) {
54
+ return line.replace(/^[\s│]*/g, '').replace(/^[├└]──\s*/, '').trim();
55
+ }
56
+ function isDirectoryName(name) {
57
+ const cleanName = name.split(/\s+\/\//)[0].trim();
58
+ if (cleanName.endsWith('/')) return true;
59
+ const lastPart = cleanName.split('/').pop() || cleanName;
60
+ if (lastPart.startsWith('.')) return false;
61
+ if (/\.[a-zA-Z0-9]+$/.test(lastPart)) return false;
62
+ return true;
63
+ }
64
+ function getExtension(name) {
65
+ const match = name.match(/\.([^.]+)$/);
66
+ return match ? match[1] : '';
67
+ }
68
+ export { parseTreeContent };
@@ -0,0 +1,10 @@
1
+ export interface TreeNode {
2
+ name: string;
3
+ type: 'file' | 'directory';
4
+ children: TreeNode[];
5
+ extension?: string;
6
+ }
7
+ export interface ParsedTree {
8
+ nodes: TreeNode[];
9
+ raw: string;
10
+ }
File without changes