path-treeify 1.3.0-beta.56a60fd → 1.3.0-beta.6923d77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -50
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/types/dev/index.d.ts +1 -0
- package/dist/types/index.d.ts +51 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
<a href="https://github.com/isaaxite/path-treeify/commits/main/">
|
|
36
36
|
<img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/isaaxite/path-treeify">
|
|
37
37
|
</a>
|
|
38
|
-
<a href='https://
|
|
39
|
-
<img src='https://github.com/isaaxite/path-treeify/actions/workflows/unittests.yml/badge.svg' alt='
|
|
38
|
+
<a href='https://github.com/isaaxite/path-treeify/actions/workflows/unittests.yml'>
|
|
39
|
+
<img src='https://github.com/isaaxite/path-treeify/actions/workflows/unittests.yml/badge.svg' alt='Test CI Status' />
|
|
40
40
|
</a>
|
|
41
41
|
<a href='https://coveralls.io/github/isaaxite/path-treeify'>
|
|
42
42
|
<img src='https://coveralls.io/repos/github/isaaxite/path-treeify/badge.svg' alt='Coverage Status' />
|
|
@@ -50,9 +50,11 @@
|
|
|
50
50
|
- 🌲 Builds a recursive tree from one or more directory paths
|
|
51
51
|
- 🔗 Each node carries a `parent` circular reference for upward traversal
|
|
52
52
|
- 📍 Each node exposes a `getPath()` method to retrieve its own paths directly
|
|
53
|
-
-
|
|
53
|
+
- 🏷️ Each node has a `type` field — `PathTreeNodeKind.Dir` or `PathTreeNodeKind.File`
|
|
54
|
+
- 👁️ `fileVisible` option includes files as leaf nodes alongside directories
|
|
55
|
+
- 🔍 Optional `filter` callback applied at **every depth**, including top-level entries
|
|
54
56
|
- ⚡ `build()` scans the entire `base` directory with zero configuration
|
|
55
|
-
- 🎛️ `buildBy()` accepts either a
|
|
57
|
+
- 🎛️ `buildBy()` accepts either a path segment array or a top-level filter function
|
|
56
58
|
- 📦 Ships as both ESM (`index.mjs`) and CJS (`index.cjs`) with full TypeScript types
|
|
57
59
|
- 🚫 Zero runtime dependencies
|
|
58
60
|
|
|
@@ -79,18 +81,27 @@ yarn add path-treeify
|
|
|
79
81
|
## Quick Start
|
|
80
82
|
|
|
81
83
|
```ts
|
|
82
|
-
import { PathTreeify } from 'path-treeify';
|
|
84
|
+
import { PathTreeify, PathTreeNodeKind } from 'path-treeify';
|
|
83
85
|
|
|
86
|
+
// Directories only (default)
|
|
84
87
|
const treeify = new PathTreeify({ base: '/your/project/root' });
|
|
88
|
+
const tree = treeify.build();
|
|
85
89
|
|
|
86
|
-
//
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
// Include files as leaf nodes
|
|
91
|
+
const treeifyWithFiles = new PathTreeify({
|
|
92
|
+
base: '/your/project/root',
|
|
93
|
+
fileVisible: true,
|
|
94
|
+
});
|
|
95
|
+
const fullTree = treeifyWithFiles.build();
|
|
96
|
+
|
|
97
|
+
// Check node type
|
|
98
|
+
for (const child of tree.children) {
|
|
99
|
+
if (child.type === PathTreeNodeKind.Dir) {
|
|
100
|
+
console.log('dir:', child.value);
|
|
101
|
+
} else if (child.type === PathTreeNodeKind.File) {
|
|
102
|
+
console.log('file:', child.value);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
94
105
|
```
|
|
95
106
|
|
|
96
107
|
---
|
|
@@ -101,10 +112,11 @@ const fullTree = treeify.build();
|
|
|
101
112
|
|
|
102
113
|
Creates a new instance.
|
|
103
114
|
|
|
104
|
-
| Option
|
|
105
|
-
|
|
106
|
-
| `base`
|
|
107
|
-
| `filter`
|
|
115
|
+
| Option | Type | Required | Description |
|
|
116
|
+
|---------------|------------------------------|----------|--------------------------------------------------------------------------|
|
|
117
|
+
| `base` | `string` | ✅ | Absolute path to the root directory to scan from |
|
|
118
|
+
| `filter` | `FilterFunction` (see below) | ❌ | Applied at **every depth** — top-level entries included |
|
|
119
|
+
| `fileVisible` | `boolean` | ❌ | When `true`, files are included as leaf nodes. Defaults to `false` |
|
|
108
120
|
|
|
109
121
|
`base` must exist and be a directory, otherwise the constructor throws.
|
|
110
122
|
|
|
@@ -116,14 +128,14 @@ Used as the `filter` option in the constructor. Applied at every level of the tr
|
|
|
116
128
|
|
|
117
129
|
```ts
|
|
118
130
|
type FilterFunction = (params: {
|
|
119
|
-
name: string; //
|
|
131
|
+
name: string; // entry name (file or directory name)
|
|
120
132
|
dirPath: string; // absolute path of the parent directory
|
|
121
133
|
}) => boolean;
|
|
122
134
|
```
|
|
123
135
|
|
|
124
|
-
Return `true` to **include** the
|
|
136
|
+
Return `true` to **include** the entry; `false` to **skip** it entirely.
|
|
125
137
|
|
|
126
|
-
**Example — exclude `node_modules` and hidden
|
|
138
|
+
**Example — exclude `node_modules` and hidden entries at every depth:**
|
|
127
139
|
|
|
128
140
|
```ts
|
|
129
141
|
const treeify = new PathTreeify({
|
|
@@ -136,7 +148,7 @@ const treeify = new PathTreeify({
|
|
|
136
148
|
|
|
137
149
|
### `build(): PathTreeNode`
|
|
138
150
|
|
|
139
|
-
Scans all
|
|
151
|
+
Scans all entries directly under `base` that pass the instance-level `filter` and returns a synthetic root `PathTreeNode`. When `fileVisible` is `true`, files are included as leaf nodes.
|
|
140
152
|
|
|
141
153
|
```ts
|
|
142
154
|
const tree = treeify.build();
|
|
@@ -144,64 +156,70 @@ const tree = treeify.build();
|
|
|
144
156
|
|
|
145
157
|
---
|
|
146
158
|
|
|
147
|
-
### `buildBy(
|
|
159
|
+
### `buildBy(segments: string[]): PathTreeNode`
|
|
148
160
|
|
|
149
|
-
Builds a tree from the given list of
|
|
161
|
+
Builds a tree from the given list of relative path segments. When `fileVisible` is `true`, file paths are also accepted.
|
|
150
162
|
|
|
151
163
|
```ts
|
|
152
164
|
const tree = treeify.buildBy(['src', 'docs', 'tests']);
|
|
165
|
+
|
|
166
|
+
// With fileVisible: true, files can also be specified
|
|
167
|
+
const treeWithFiles = new PathTreeify({ base: '/your/project', fileVisible: true });
|
|
168
|
+
treeWithFiles.buildBy(['src', 'README.md']);
|
|
153
169
|
```
|
|
154
170
|
|
|
155
|
-
-
|
|
156
|
-
-
|
|
171
|
+
- Both `/` and `\` separators are normalised automatically.
|
|
172
|
+
- Leading/trailing slashes and empty segments are stripped.
|
|
173
|
+
- Throws if any segment does not resolve to a valid entry under `base`.
|
|
157
174
|
|
|
158
|
-
### `buildBy(filter: (
|
|
175
|
+
### `buildBy(filter: (segment: string) => boolean): PathTreeNode`
|
|
159
176
|
|
|
160
|
-
Collects all top-level
|
|
177
|
+
Collects all top-level entries under `base`, applies the predicate to select which ones to include, then builds a tree. The instance-level `filter` still applies during deep traversal.
|
|
161
178
|
|
|
162
179
|
```ts
|
|
163
180
|
const tree = treeify.buildBy(name => name !== 'node_modules' && !name.startsWith('.'));
|
|
164
181
|
```
|
|
165
182
|
|
|
166
|
-
> **Note:** the predicate passed to `buildBy(fn)` only selects which **top-level**
|
|
183
|
+
> **Note:** the predicate passed to `buildBy(fn)` only selects which **top-level** entries to include. To filter entries at every depth, pass a `filter` to the constructor.
|
|
167
184
|
|
|
168
185
|
---
|
|
169
186
|
|
|
170
|
-
### `
|
|
187
|
+
### `PathTreeNode`
|
|
171
188
|
|
|
172
|
-
|
|
189
|
+
`PathTreeNode` is an **interface** — each node exposes a `getPath()` method to retrieve its paths without needing the `PathTreeify` instance.
|
|
173
190
|
|
|
174
191
|
```ts
|
|
175
|
-
|
|
176
|
-
//
|
|
177
|
-
//
|
|
192
|
+
interface PathTreeNode {
|
|
193
|
+
parent: PathTreeNode | null; // null only on the synthetic root
|
|
194
|
+
value: string; // entry name for this node
|
|
195
|
+
children: PathTreeNode[]; // empty for file nodes
|
|
196
|
+
type: PathTreeNodeKind; // Dir, File, or Unknown
|
|
197
|
+
|
|
198
|
+
getPath(): { relative: string; absolute: string };
|
|
199
|
+
}
|
|
178
200
|
```
|
|
179
201
|
|
|
202
|
+
> ⚠️ **Circular references** — `parent` points back up the tree. Use `JSON.stringify` replacers or a library like `flatted` if you need to serialize the result.
|
|
203
|
+
|
|
180
204
|
---
|
|
181
205
|
|
|
182
|
-
### `
|
|
206
|
+
### `PathTreeNodeKind`
|
|
183
207
|
|
|
184
|
-
|
|
208
|
+
An enum classifying each node's filesystem type.
|
|
185
209
|
|
|
186
210
|
```ts
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
getPath(): { relative: string; absolute: string };
|
|
211
|
+
enum PathTreeNodeKind {
|
|
212
|
+
Dir = 'dir',
|
|
213
|
+
File = 'file',
|
|
214
|
+
Unknown = 'unknown', // assigned before the type is resolved
|
|
193
215
|
}
|
|
194
216
|
```
|
|
195
217
|
|
|
196
|
-
`node.getPath()` returns the same result as `treeify.getPathBy(node)` — both are available for convenience.
|
|
197
|
-
|
|
198
|
-
> ⚠️ **Circular references** — `parent` points back up the tree. Use `JSON.stringify` replacers or a library like `flatted` if you need to serialize the result.
|
|
199
|
-
|
|
200
218
|
---
|
|
201
219
|
|
|
202
220
|
## Examples
|
|
203
221
|
|
|
204
|
-
###
|
|
222
|
+
### Directories only (default)
|
|
205
223
|
|
|
206
224
|
```ts
|
|
207
225
|
import { PathTreeify } from 'path-treeify';
|
|
@@ -210,6 +228,16 @@ const treeify = new PathTreeify({ base: '/your/project' });
|
|
|
210
228
|
const tree = treeify.build();
|
|
211
229
|
```
|
|
212
230
|
|
|
231
|
+
### Include files as leaf nodes
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
const treeify = new PathTreeify({
|
|
235
|
+
base: '/your/project',
|
|
236
|
+
fileVisible: true,
|
|
237
|
+
});
|
|
238
|
+
const tree = treeify.build();
|
|
239
|
+
```
|
|
240
|
+
|
|
213
241
|
### Exclude directories at every depth via constructor filter
|
|
214
242
|
|
|
215
243
|
```ts
|
|
@@ -220,13 +248,13 @@ const treeify = new PathTreeify({
|
|
|
220
248
|
const tree = treeify.build();
|
|
221
249
|
```
|
|
222
250
|
|
|
223
|
-
### Scan specific
|
|
251
|
+
### Scan specific paths
|
|
224
252
|
|
|
225
253
|
```ts
|
|
226
254
|
const tree = treeify.buildBy(['src', 'tests', 'docs']);
|
|
227
255
|
```
|
|
228
256
|
|
|
229
|
-
### Select top-level
|
|
257
|
+
### Select top-level entries with a predicate
|
|
230
258
|
|
|
231
259
|
```ts
|
|
232
260
|
const tree = treeify.buildBy(name => name !== 'node_modules' && !name.startsWith('.'));
|
|
@@ -238,7 +266,7 @@ const tree = treeify.buildBy(name => name !== 'node_modules' && !name.startsWith
|
|
|
238
266
|
function printPaths(node) {
|
|
239
267
|
for (const child of node.children) {
|
|
240
268
|
const { absolute } = child.getPath();
|
|
241
|
-
console.log(absolute);
|
|
269
|
+
console.log(`[${child.type}] ${absolute}`);
|
|
242
270
|
printPaths(child);
|
|
243
271
|
}
|
|
244
272
|
}
|
|
@@ -249,7 +277,7 @@ printPaths(tree);
|
|
|
249
277
|
### CommonJS usage
|
|
250
278
|
|
|
251
279
|
```js
|
|
252
|
-
const { PathTreeify } = require('path-treeify');
|
|
280
|
+
const { PathTreeify, PathTreeNodeKind } = require('path-treeify');
|
|
253
281
|
|
|
254
282
|
const treeify = new PathTreeify({ base: __dirname });
|
|
255
283
|
const tree = treeify.build();
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e,t=require("fs"),
|
|
1
|
+
"use strict";var e,t=require("fs"),i=require("path");class r{static isValid(e){try{return t.accessSync(e,t.constants.F_OK),!0}catch{return!1}}static isDirectory(e){try{return t.statSync(e).isDirectory()}catch{return!1}}static isFile(e){try{return t.statSync(e).isFile()}catch{return!1}}}exports.PathTreeNodeKind=void 0,(e=exports.PathTreeNodeKind||(exports.PathTreeNodeKind={})).Dir="dir",e.File="file",e.Unknown="unknown";class s{constructor(e){this.usePathCache=!1,this.base=e.base,"boolean"==typeof e.usePathCache&&(this.usePathCache=e.usePathCache)}getPath(){let e=this;const t=()=>{let t="",r=this;for(;r.parent;)t=t?`${r.value}${i.sep}${t}`:r.value,r=r.parent;return{relative:t,absolute:i.resolve(e.base,t)}};return e.usePathCache?(e._pathCache||(e._pathCache=t()),e._pathCache):t()}}exports.PathTreeify=class{constructor(e){this.fileVisible=!1;const{filter:t,base:i,fileVisible:n,usePathCache:a}=e;if("boolean"==typeof n&&n&&(this.fileVisible=n),void 0!==t&&(this.validateFilter(t),this.userFilter=t),!i||!r.isValid(i))throw new Error(`${i} is not a valid path!`);if(!r.isDirectory(i))throw new Error(`${i} is not a dirPath!`);this.base=i,this.pathTreeNodeShared=new s({base:i,usePathCache:a})}applyFilter(e,t){return!(!this.fileVisible&&!r.isDirectory(e))&&(!this.userFilter||this.userFilter({name:t,dirPath:i.dirname(e)}))}validateFilter(e){if("function"!=typeof e)throw new TypeError("filter must be a function")}initNode(){const e=Object.create(this.pathTreeNodeShared),t=Object.create(e);return t.parent=null,t.value="",t.children=[],t.type=exports.PathTreeNodeKind.Unknown,t.depth=-1,t}buildChildren(e,s,n){const a=[],o=n||t.readdirSync(e),h=s.depth+1;for(const t of o){const n=i.join(e,t);if(!this.applyFilter(n,t))continue;const o=this.initNode();o.depth=h,o.value=t,o.parent=s,a.push(o),this.fileVisible&&r.isFile(n)?o.type=exports.PathTreeNodeKind.File:(o.type=exports.PathTreeNodeKind.Dir,o.children=this.buildChildren(n,o))}return a}checkRelativePaths(e){for(let t=0;t<e.length;t++){const s=e[t];if("string"!=typeof s)throw new Error(`Item at index ${t} is not a string, got ${typeof s}`);const n=i.resolve(this.base,s);if(!r.isValid(n))throw new Error(`Path does not exist or is not accessible: ${n} (from relative path: ${s})`);if(!(r.isDirectory(n)||this.fileVisible&&r.isFile(n)))throw new Error(`Path is not a directory: ${n} (from relative path: ${s})`)}}formatSegments(e){return e.map(e=>e.split(/[/\\]/).filter(Boolean).join(i.sep)).filter(Boolean)}getAllEntriesUnderBase(){return t.readdirSync(this.base).filter(e=>{const t=i.resolve(this.base,e);return this.applyFilter(t,e)})}buildBySegments(e){const t=this.initNode();return t.depth=0,t.children=this.buildChildren(this.base,t,e),t}buildByFilter(e){const t=this.getAllEntriesUnderBase();return this.buildBySegments(t.filter(e))}buildBy(e){if(Array.isArray(e)){const t=this.formatSegments(e);return this.checkRelativePaths(t),this.buildBySegments(t)}if("function"==typeof e)return this.buildByFilter(e);throw new TypeError("buildBy: expected an array of strings or a filter function, but received "+typeof e)}build(){const e=this.getAllEntriesUnderBase();return this.buildBySegments(e)}};
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readdirSync as t,accessSync as
|
|
1
|
+
import{readdirSync as t,accessSync as e,constants as i,statSync as r}from"fs";import{dirname as s,join as n,resolve as a,sep as h}from"path";class l{static isValid(t){try{return e(t,i.F_OK),!0}catch{return!1}}static isDirectory(t){try{return r(t).isDirectory()}catch{return!1}}static isFile(t){try{return r(t).isFile()}catch{return!1}}}var o;!function(t){t.Dir="dir",t.File="file",t.Unknown="unknown"}(o||(o={}));class c{constructor(t){this.usePathCache=!1,this.base=t.base,"boolean"==typeof t.usePathCache&&(this.usePathCache=t.usePathCache)}getPath(){let t=this;const e=()=>{let e="",i=this;for(;i.parent;)e=e?`${i.value}${h}${e}`:i.value,i=i.parent;return{relative:e,absolute:a(t.base,e)}};return t.usePathCache?(t._pathCache||(t._pathCache=e()),t._pathCache):e()}}class u{constructor(t){this.fileVisible=!1;const{filter:e,base:i,fileVisible:r,usePathCache:s}=t;if("boolean"==typeof r&&r&&(this.fileVisible=r),void 0!==e&&(this.validateFilter(e),this.userFilter=e),!i||!l.isValid(i))throw new Error(`${i} is not a valid path!`);if(!l.isDirectory(i))throw new Error(`${i} is not a dirPath!`);this.base=i,this.pathTreeNodeShared=new c({base:i,usePathCache:s})}applyFilter(t,e){return!(!this.fileVisible&&!l.isDirectory(t))&&(!this.userFilter||this.userFilter({name:e,dirPath:s(t)}))}validateFilter(t){if("function"!=typeof t)throw new TypeError("filter must be a function")}initNode(){const t=Object.create(this.pathTreeNodeShared),e=Object.create(t);return e.parent=null,e.value="",e.children=[],e.type=o.Unknown,e.depth=-1,e}buildChildren(e,i,r){const s=[],a=r||t(e),h=i.depth+1;for(const t of a){const r=n(e,t);if(!this.applyFilter(r,t))continue;const a=this.initNode();a.depth=h,a.value=t,a.parent=i,s.push(a),this.fileVisible&&l.isFile(r)?a.type=o.File:(a.type=o.Dir,a.children=this.buildChildren(r,a))}return s}checkRelativePaths(t){for(let e=0;e<t.length;e++){const i=t[e];if("string"!=typeof i)throw new Error(`Item at index ${e} is not a string, got ${typeof i}`);const r=a(this.base,i);if(!l.isValid(r))throw new Error(`Path does not exist or is not accessible: ${r} (from relative path: ${i})`);if(!(l.isDirectory(r)||this.fileVisible&&l.isFile(r)))throw new Error(`Path is not a directory: ${r} (from relative path: ${i})`)}}formatSegments(t){return t.map(t=>t.split(/[/\\]/).filter(Boolean).join(h)).filter(Boolean)}getAllEntriesUnderBase(){return t(this.base).filter(t=>{const e=a(this.base,t);return this.applyFilter(e,t)})}buildBySegments(t){const e=this.initNode();return e.depth=0,e.children=this.buildChildren(this.base,e,t),e}buildByFilter(t){const e=this.getAllEntriesUnderBase();return this.buildBySegments(e.filter(t))}buildBy(t){if(Array.isArray(t)){const e=this.formatSegments(t);return this.checkRelativePaths(e),this.buildBySegments(e)}if("function"==typeof t)return this.buildByFilter(t);throw new TypeError("buildBy: expected an array of strings or a filter function, but received "+typeof t)}build(){const t=this.getAllEntriesUnderBase();return this.buildBySegments(t)}}export{o as PathTreeNodeKind,u as PathTreeify};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -11,16 +11,22 @@ interface PathTreeifyProps {
|
|
|
11
11
|
filter?: FilterFunction;
|
|
12
12
|
/** When true, files are included as leaf nodes alongside directories. Defaults to false */
|
|
13
13
|
fileVisible?: boolean;
|
|
14
|
+
usePathCache?: boolean;
|
|
14
15
|
}
|
|
15
16
|
/** Classification of a node in the path tree */
|
|
16
|
-
export declare enum
|
|
17
|
+
export declare enum PathTreeNodeKind {
|
|
17
18
|
Dir = "dir",
|
|
18
19
|
File = "file",
|
|
19
20
|
/** Assigned before the node's type has been resolved */
|
|
20
21
|
Unknown = "unknown"
|
|
21
22
|
}
|
|
22
|
-
/**
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Public interface for a node in the path tree.
|
|
25
|
+
* Consumers receive this type; the internal implementation class is not exported.
|
|
26
|
+
*/
|
|
27
|
+
export interface PathTreeNode {
|
|
28
|
+
/** Distance from the root node; root itself is 0, its direct children are 1, and so on */
|
|
29
|
+
depth: number;
|
|
24
30
|
/** Reference to the parent node; null for the root node */
|
|
25
31
|
parent: PathTreeNode | null;
|
|
26
32
|
/** The entry name of this node (not a full path) */
|
|
@@ -28,17 +34,27 @@ export declare class PathTreeNode {
|
|
|
28
34
|
/** Child nodes; non-empty only for directory nodes */
|
|
29
35
|
children: PathTreeNode[];
|
|
30
36
|
/** Whether this node is a directory, a file, or not yet resolved */
|
|
31
|
-
type:
|
|
37
|
+
type: PathTreeNodeKind;
|
|
32
38
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
39
|
+
* Computes this node's paths using the `parentRelative` stored on the siblings'
|
|
40
|
+
* shared prototype by {@link PathTreeify.buildChildren}.
|
|
41
|
+
* @returns `relative` — path from the tree root; `absolute` — fully resolved path on disk
|
|
35
42
|
*/
|
|
36
|
-
getPath():
|
|
43
|
+
getPath(): {
|
|
44
|
+
relative: string;
|
|
45
|
+
absolute: string;
|
|
46
|
+
};
|
|
37
47
|
}
|
|
38
48
|
/** Builds a tree of {@link PathTreeNode} entries rooted at a given base path */
|
|
39
49
|
export declare class PathTreeify {
|
|
40
50
|
/** The root directory to scan */
|
|
41
51
|
private base;
|
|
52
|
+
/**
|
|
53
|
+
* Shared prototype instance for nodes produced by this builder.
|
|
54
|
+
* All nodes created via {@link initNode} inherit `base` and `getPath` from this object,
|
|
55
|
+
* avoiding per-node storage of the base path string.
|
|
56
|
+
*/
|
|
57
|
+
private pathTreeNodeShared;
|
|
42
58
|
/**
|
|
43
59
|
* Optional user-supplied filter. When set, every entry must pass this predicate
|
|
44
60
|
* in addition to the built-in visibility check.
|
|
@@ -46,6 +62,7 @@ export declare class PathTreeify {
|
|
|
46
62
|
private userFilter?;
|
|
47
63
|
/** When true, files are included as leaf nodes during traversal. Defaults to false */
|
|
48
64
|
private fileVisible;
|
|
65
|
+
constructor(props: Partial<PathTreeifyProps>);
|
|
49
66
|
/**
|
|
50
67
|
* Determines whether a given entry should be included in the tree.
|
|
51
68
|
* - If {@link fileVisible} is false, non-directory entries are always excluded.
|
|
@@ -54,27 +71,40 @@ export declare class PathTreeify {
|
|
|
54
71
|
* @param name - Entry name (filename or directory name)
|
|
55
72
|
*/
|
|
56
73
|
private applyFilter;
|
|
57
|
-
constructor({ filter, base, fileVisible }: Partial<PathTreeifyProps>);
|
|
58
74
|
/**
|
|
59
75
|
* Asserts that the provided value is a callable {@link FilterFunction}.
|
|
60
76
|
* Throws a TypeError if the check fails.
|
|
61
77
|
*/
|
|
62
78
|
private validateFilter;
|
|
63
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* Creates a new unattached {@link PathTreeNode}.
|
|
81
|
+
* The node's prototype is set to {@link pathTreeNodeShared} so that `base` and
|
|
82
|
+
* `getPath` are inherited without being stored on each instance individually.
|
|
83
|
+
* `depth` are initialised to `-1` and must be set by the caller.
|
|
84
|
+
*/
|
|
64
85
|
private initNode;
|
|
65
86
|
/**
|
|
66
87
|
* Recursively reads {@link dirPath} and builds child nodes for each entry that
|
|
67
88
|
* passes {@link applyFilter}. Directories are traversed depth-first;
|
|
68
89
|
* files (when {@link fileVisible} is true) become leaf nodes.
|
|
69
|
-
*
|
|
70
|
-
*
|
|
90
|
+
*
|
|
91
|
+
* After assembling the sibling group, injects `parentRelative` onto a new intermediate
|
|
92
|
+
* prototype shared by `children[0]`. This allows {@link PathTreeNodeShared.getPath} to
|
|
93
|
+
* resolve paths in O(1) without walking the full parent chain on every call.
|
|
94
|
+
*
|
|
95
|
+
* @param dirPath - Absolute path of the directory to read
|
|
96
|
+
* @param parent - The parent node to attach child nodes to
|
|
97
|
+
* @param segments - Optional explicit list of entry names to use instead of reading the
|
|
98
|
+
* directory from disk; used by {@link buildBySegments} to skip a
|
|
99
|
+
* redundant `readdirSync` when the segment list is already known
|
|
71
100
|
*/
|
|
72
101
|
private buildChildren;
|
|
73
102
|
/**
|
|
74
103
|
* Validates that every entry in {@link relativeSegments} refers to an accessible
|
|
75
104
|
* path under {@link base}. When {@link fileVisible} is false, each path must be
|
|
76
105
|
* a directory; when true, regular files are also accepted.
|
|
77
|
-
* @param relativeSegments - Relative path strings to validate
|
|
106
|
+
* @param relativeSegments - Relative path strings to validate; assumed to be a string
|
|
107
|
+
* array (callers are responsible for type safety at the boundary)
|
|
78
108
|
*/
|
|
79
109
|
private checkRelativePaths;
|
|
80
110
|
/**
|
|
@@ -90,29 +120,23 @@ export declare class PathTreeify {
|
|
|
90
120
|
*/
|
|
91
121
|
private getAllEntriesUnderBase;
|
|
92
122
|
/**
|
|
93
|
-
* Builds a subtree
|
|
94
|
-
*
|
|
95
|
-
* @
|
|
123
|
+
* Builds a subtree whose top-depth children correspond to {@link segments}.
|
|
124
|
+
* The root node is created at depth 0; children are built by delegating to
|
|
125
|
+
* {@link buildChildren}, passing {@link segments} directly to avoid a redundant
|
|
126
|
+
* `readdirSync` of the base directory.
|
|
127
|
+
* @param segments - Normalised and validated relative path segments
|
|
96
128
|
*/
|
|
97
129
|
private buildBySegments;
|
|
98
130
|
/**
|
|
99
|
-
* Builds a subtree from top-
|
|
100
|
-
* Note: this predicate only affects top-
|
|
131
|
+
* Builds a subtree from top-depth entries whose names satisfy {@link filter}.
|
|
132
|
+
* Note: this predicate only affects top-depth selection, not recursive traversal.
|
|
101
133
|
* For recursive filtering use the `filter` constructor option.
|
|
102
|
-
* @param filter - Predicate applied to each top-
|
|
134
|
+
* @param filter - Predicate applied to each top-depth entry name
|
|
103
135
|
*/
|
|
104
136
|
private buildByFilter;
|
|
105
|
-
/**
|
|
106
|
-
* Returns the relative and absolute paths for a given node by delegating to
|
|
107
|
-
* {@link PathTreeNode.getPath} and resolving against {@link base}.
|
|
108
|
-
*/
|
|
109
|
-
getPathBy(node: PathTreeNode): {
|
|
110
|
-
relative: string;
|
|
111
|
-
absolute: string;
|
|
112
|
-
};
|
|
113
137
|
/** Overload: build the tree from an explicit list of relative path segments */
|
|
114
138
|
buildBy(segments: string[]): PathTreeNode;
|
|
115
|
-
/** Overload: build the tree from a predicate applied to top-
|
|
139
|
+
/** Overload: build the tree from a predicate applied to top-depth entry names */
|
|
116
140
|
buildBy(filter: (segment: string) => boolean): PathTreeNode;
|
|
117
141
|
/** Builds a full tree from all immediate entries under the base path */
|
|
118
142
|
build(): PathTreeNode;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "path-treeify",
|
|
3
|
-
"version": "1.3.0-beta.
|
|
3
|
+
"version": "1.3.0-beta.6923d77",
|
|
4
4
|
"description": "Convert a path or an array of paths into a tree-structured JavaScript object, where each node has a `parent` property that holds a circular reference to its parent node.",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.mjs",
|