Skip to content

Commit 4623264

Browse files
authored
🔖 | Release 1.3.0
2 parents 2428b3b + dbce6ae commit 4623264

File tree

2 files changed

+51
-4
lines changed

2 files changed

+51
-4
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
## [1.3.0] - 2025-03-29
2+
3+
### ✨ Features
4+
- Added `useFileIcons` option to display emoji icons (📦, 📂, 📄) before each item in the tree structure
5+
- Implemented `sortOrder` option to sort items either alphabetically or by type (folders first, then files)
6+
7+
### 🐛 Bug Fixes
8+
- Fixed handling of symbolic links in the file tree generation
9+
10+
[1.3.0]: https://github.com/fuzionix/vscode-file-tree/compare/1.2.0...1.3.0
11+
112
## [1.2.0] - 2025-01-05
213

314
### ✨ Features

src/extract.js

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ const {
1414
const FILE_ICONS = {
1515
ROOT: '📦',
1616
DIRECTORY: '📂',
17-
FILE: '📄'
17+
FILE: '📄',
18+
SYMLINK: '🔗'
1819
}
1920

2021
/**
@@ -66,13 +67,28 @@ async function generateFileTree(startPath) {
6667
/**
6768
* Recursively builds a tree structure of the file system
6869
* @param {string} itemPath - The path of the current item (file or directory)
70+
* @param {string} startPath - The original starting path
71+
* @param {Object} buildConfig - Configuration options
72+
* @param {number} depth - Current depth in the tree
73+
* @param {Set} [visitedPaths] - Set of already visited paths to detect loops
6974
* @returns {Promise<Object>} A promise that resolves to an object representing the tree
7075
*/
71-
async function buildTree(itemPath, startPath, buildConfig, depth) {
76+
async function buildTree(itemPath, startPath, buildConfig, depth, visitedPaths = new Set()) {
7277
if (buildConfig.maxDepth !== -1 && depth >= buildConfig.maxDepth) {
7378
return null
7479
}
7580

81+
const normalizedPath = path.resolve(itemPath)
82+
if (visitedPaths.has(normalizedPath)) {
83+
return {
84+
name: path.basename(itemPath) + ' (symlink loop)',
85+
type: 'symlink',
86+
target: normalizedPath
87+
}
88+
}
89+
90+
visitedPaths.add(normalizedPath)
91+
7692
if (!buildConfig.showHiddenFiles && isHiddenFile(itemPath)) {
7793
return null
7894
}
@@ -81,14 +97,34 @@ async function buildTree(itemPath, startPath, buildConfig, depth) {
8197
return null
8298
}
8399

84-
let stats
100+
let stats, lstat
85101
try {
86102
stats = await fs.stat(itemPath)
103+
lstat = await fs.lstat(itemPath)
87104
} catch (error) {
88105
console.warn(`Warning: Skipping "${itemPath}" due to error:`, error.message)
89106
return null
90107
}
91108
const name = path.basename(itemPath)
109+
const isSymlink = lstat.isSymbolicLink()
110+
111+
if (isSymlink) {
112+
try {
113+
const target = await fs.readlink(itemPath)
114+
return {
115+
name,
116+
type: 'symlink',
117+
target,
118+
size: buildConfig.showFileSize ? formatFileSize(lstat.size) : null
119+
}
120+
} catch (error) {
121+
return {
122+
name: name + ' (broken symlink)',
123+
type: 'symlink',
124+
target: 'unknown'
125+
}
126+
}
127+
}
92128

93129
if (stats.isFile() && buildConfig.directoryOnly) {
94130
return null
@@ -104,7 +140,7 @@ async function buildTree(itemPath, startPath, buildConfig, depth) {
104140
try {
105141
const children = await fs.readdir(itemPath)
106142
const childNodes = await Promise.all(
107-
children.map(child => buildTree(path.join(itemPath, child), startPath, buildConfig, depth + 1))
143+
children.map(child => buildTree(path.join(itemPath, child), startPath, buildConfig, depth + 1, new Set(visitedPaths)))
108144
)
109145
const filteredNodes = childNodes.filter(node => node !== null)
110146
const sortedNodes = sortNodes(filteredNodes, buildConfig.sortOrder)

0 commit comments

Comments
 (0)