path-treeify 1.1.0-beta.94a5d17 → 1.2.0-beta.db6fe0b
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/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/types/index.d.ts +53 -0
- package/package.json +12 -2
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var t=require("fs"),
|
|
1
|
+
"use strict";var t=require("fs"),e=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}}}class i{constructor(t){this.parent=null,this.value="",this.children=[],this.base=t}getPath(){let t="",r=this;for(;r.parent;)t=t?`${r.value}${e.sep}${t}`:r.value,r=r.parent;return{relative:t,absolute:e.resolve(this.base,t)}}}exports.PathTreeify=class{constructor({filter:t,base:e}){if(void 0!==t&&(this.validateFilter(t),this.filter=t),!e||!r.isValid(e))throw new Error(`${e} is not a valid path!`);if(!r.isDirectory(e))throw new Error(`${e} is not a dirPath!`);this.base=e}validateFilter(t){if("function"!=typeof t)throw new TypeError("filter must be a function");if(1!==t.length)throw new TypeError("filter must accept exactly one parameter");try{if("boolean"!=typeof t({name:"test",postPath:"/test"}))throw new TypeError("filter must return a boolean")}catch(t){throw new TypeError("filter function threw an error during test: "+t)}}initNode(t=null){const e=new i(this.base);return t&&(e.parent=t),e}buildChildren(r,i){const s=t.readdirSync(r),a=[];for(const n of s){const s=e.join(r,n);if(!t.statSync(s).isDirectory())continue;if(this.filter&&!this.filter({dirPath:r,name:n}))continue;const o=this.initNode();o.value=n,o.parent=i,o.children=this.buildChildren(s,o),a.push(o)}return a}checkRelativePaths(t){if(!Array.isArray(t))throw new Error("Expected array, got "+typeof t);for(let i=0;i<t.length;i++){const s=t[i];if("string"!=typeof s)throw new Error(`Item at index ${i} is not a string, got ${typeof s}`);const a=e.resolve(this.base,s);if(!r.isValid(a))throw new Error(`Path does not exist or is not accessible: ${a} (from relative path: ${s})`);if(!r.isDirectory(a))throw new Error(`Path is not a directory: ${a} (from relative path: ${s})`)}}formatDirnames(t){return t.map(t=>t.replace(/^\/+|\/+$/g,"")).filter(t=>""!==t)}getAllDirNamesUnderBase(){return t.readdirSync(this.base).filter(t=>{const i=e.resolve(this.base,t);return!!r.isDirectory(i)&&!(this.filter&&!this.filter({name:t,dirPath:this.base}))})}buildByDirNames(t){const r=this.initNode();this.checkRelativePaths(t);const i=this.formatDirnames(t);for(const t of i){const i=this.initNode();i.value=t,i.parent=r,i.children=this.buildChildren(e.resolve(this.base,t),i),r.children.push(i)}return r}buildByFilter(t){const e=this.getAllDirNamesUnderBase();return this.buildByDirNames(e.filter(t))}getPathBy(t){let r="",i=t;for(;i.parent;)r=r?`${i.value}${e.sep}${r}`:i.value,i=i.parent;return{relative:r,absolute:e.resolve(this.base,r)}}buildBy(t){if(Array.isArray(t))return this.buildByDirNames(t);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.getAllDirNamesUnderBase();return this.buildByDirNames(t)}};
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readdirSync as t,statSync as r,accessSync as e,constants as i}from"fs";import{join as s,resolve as a,sep as n}from"path";class o{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}}}class l{constructor(t){this.parent=null,this.value="",this.children=[],this.base=t}getPath(){let t="",r=this;for(;r.parent;)t=t?`${r.value}${n}${t}`:r.value,r=r.parent;return{relative:t,absolute:a(this.base,t)}}}class h{constructor({filter:t,base:r}){if(void 0!==t&&(this.validateFilter(t),this.filter=t),!r||!o.isValid(r))throw new Error(`${r} is not a valid path!`);if(!o.isDirectory(r))throw new Error(`${r} is not a dirPath!`);this.base=r}validateFilter(t){if("function"!=typeof t)throw new TypeError("filter must be a function");if(1!==t.length)throw new TypeError("filter must accept exactly one parameter");try{if("boolean"!=typeof t({name:"test",postPath:"/test"}))throw new TypeError("filter must return a boolean")}catch(t){throw new TypeError("filter function threw an error during test: "+t)}}initNode(t=null){const r=new l(this.base);return t&&(r.parent=t),r}buildChildren(e,i){const a=t(e),n=[];for(const t of a){const a=s(e,t);if(!r(a).isDirectory())continue;if(this.filter&&!this.filter({dirPath:e,name:t}))continue;const o=this.initNode();o.value=t,o.parent=i,o.children=this.buildChildren(a,o),n.push(o)}return n}checkRelativePaths(t){if(!Array.isArray(t))throw new Error("Expected array, got "+typeof t);for(let r=0;r<t.length;r++){const e=t[r];if("string"!=typeof e)throw new Error(`Item at index ${r} is not a string, got ${typeof e}`);const i=a(this.base,e);if(!o.isValid(i))throw new Error(`Path does not exist or is not accessible: ${i} (from relative path: ${e})`);if(!o.isDirectory(i))throw new Error(`Path is not a directory: ${i} (from relative path: ${e})`)}}formatDirnames(t){return t.map(t=>t.replace(/^\/+|\/+$/g,"")).filter(t=>""!==t)}getAllDirNamesUnderBase(){return t(this.base).filter(t=>{const r=a(this.base,t);return
|
|
1
|
+
import{readdirSync as t,statSync as r,accessSync as e,constants as i}from"fs";import{join as s,resolve as a,sep as n}from"path";class o{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}}}class l{constructor(t){this.parent=null,this.value="",this.children=[],this.base=t}getPath(){let t="",r=this;for(;r.parent;)t=t?`${r.value}${n}${t}`:r.value,r=r.parent;return{relative:t,absolute:a(this.base,t)}}}class h{constructor({filter:t,base:r}){if(void 0!==t&&(this.validateFilter(t),this.filter=t),!r||!o.isValid(r))throw new Error(`${r} is not a valid path!`);if(!o.isDirectory(r))throw new Error(`${r} is not a dirPath!`);this.base=r}validateFilter(t){if("function"!=typeof t)throw new TypeError("filter must be a function");if(1!==t.length)throw new TypeError("filter must accept exactly one parameter");try{if("boolean"!=typeof t({name:"test",postPath:"/test"}))throw new TypeError("filter must return a boolean")}catch(t){throw new TypeError("filter function threw an error during test: "+t)}}initNode(t=null){const r=new l(this.base);return t&&(r.parent=t),r}buildChildren(e,i){const a=t(e),n=[];for(const t of a){const a=s(e,t);if(!r(a).isDirectory())continue;if(this.filter&&!this.filter({dirPath:e,name:t}))continue;const o=this.initNode();o.value=t,o.parent=i,o.children=this.buildChildren(a,o),n.push(o)}return n}checkRelativePaths(t){if(!Array.isArray(t))throw new Error("Expected array, got "+typeof t);for(let r=0;r<t.length;r++){const e=t[r];if("string"!=typeof e)throw new Error(`Item at index ${r} is not a string, got ${typeof e}`);const i=a(this.base,e);if(!o.isValid(i))throw new Error(`Path does not exist or is not accessible: ${i} (from relative path: ${e})`);if(!o.isDirectory(i))throw new Error(`Path is not a directory: ${i} (from relative path: ${e})`)}}formatDirnames(t){return t.map(t=>t.replace(/^\/+|\/+$/g,"")).filter(t=>""!==t)}getAllDirNamesUnderBase(){return t(this.base).filter(t=>{const r=a(this.base,t);return!!o.isDirectory(r)&&!(this.filter&&!this.filter({name:t,dirPath:this.base}))})}buildByDirNames(t){const r=this.initNode();this.checkRelativePaths(t);const e=this.formatDirnames(t);for(const t of e){const e=this.initNode();e.value=t,e.parent=r,e.children=this.buildChildren(a(this.base,t),e),r.children.push(e)}return r}buildByFilter(t){const r=this.getAllDirNamesUnderBase();return this.buildByDirNames(r.filter(t))}getPathBy(t){let r="",e=t;for(;e.parent;)r=r?`${e.value}${n}${r}`:e.value,e=e.parent;return{relative:r,absolute:a(this.base,r)}}buildBy(t){if(Array.isArray(t))return this.buildByDirNames(t);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.getAllDirNamesUnderBase();return this.buildByDirNames(t)}}export{h as PathTreeify};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,40 +1,93 @@
|
|
|
1
|
+
/** A filter function that determines whether a directory should be included in the tree */
|
|
1
2
|
type FilterFunction = (params: {
|
|
2
3
|
name: string;
|
|
3
4
|
dirPath: string;
|
|
4
5
|
}) => boolean;
|
|
6
|
+
/** Constructor options for PathTreeify */
|
|
5
7
|
interface PathTreeifyProps {
|
|
6
8
|
base: string;
|
|
7
9
|
filter?: FilterFunction;
|
|
8
10
|
}
|
|
11
|
+
/** Represents a single node (directory) in the path tree */
|
|
9
12
|
declare class PathTreeNode {
|
|
13
|
+
/** The root base path used to resolve absolute paths */
|
|
10
14
|
private base;
|
|
15
|
+
/** Reference to the parent node; null for the root node */
|
|
11
16
|
parent: PathTreeNode | null;
|
|
17
|
+
/** The directory name of this node (not a full path) */
|
|
12
18
|
value: string;
|
|
19
|
+
/** Child nodes representing subdirectories */
|
|
13
20
|
children: PathTreeNode[];
|
|
14
21
|
constructor(base: string);
|
|
22
|
+
/**
|
|
23
|
+
* Walks up the parent chain to compute this node's relative and absolute paths.
|
|
24
|
+
* @returns An object containing the relative path from base and the absolute path
|
|
25
|
+
*/
|
|
15
26
|
getPath(): {
|
|
16
27
|
relative: string;
|
|
17
28
|
absolute: string;
|
|
18
29
|
};
|
|
19
30
|
}
|
|
31
|
+
/** Builds a tree of directory nodes rooted at a given base path */
|
|
20
32
|
export declare class PathTreeify {
|
|
33
|
+
/** The root directory to scan */
|
|
21
34
|
private base;
|
|
35
|
+
/** Optional filter applied to each directory during traversal */
|
|
22
36
|
private filter?;
|
|
23
37
|
constructor({ filter, base }: Partial<PathTreeifyProps>);
|
|
38
|
+
/**
|
|
39
|
+
* Validates that the provided filter is a function, accepts one parameter,
|
|
40
|
+
* and returns a boolean. Throws a TypeError if any condition is violated.
|
|
41
|
+
*/
|
|
24
42
|
private validateFilter;
|
|
43
|
+
/**
|
|
44
|
+
* Creates and optionally attaches a new PathTreeNode to a parent.
|
|
45
|
+
* @param parent - The parent node to attach to, or null for the root
|
|
46
|
+
*/
|
|
25
47
|
private initNode;
|
|
48
|
+
/**
|
|
49
|
+
* Recursively reads a directory and builds child nodes for each subdirectory.
|
|
50
|
+
* Applies the instance-level filter if one is set.
|
|
51
|
+
* @param dirPath - Absolute path of the directory to read
|
|
52
|
+
* @param parent - The parent node to attach children to
|
|
53
|
+
*/
|
|
26
54
|
private buildChildren;
|
|
55
|
+
/**
|
|
56
|
+
* Validates that each entry in the array is a string pointing to
|
|
57
|
+
* an accessible directory relative to the base path.
|
|
58
|
+
* @param relativeDirNames - Array of relative directory path strings to validate
|
|
59
|
+
*/
|
|
27
60
|
private checkRelativePaths;
|
|
61
|
+
/**
|
|
62
|
+
* Strips leading and trailing slashes from each directory name
|
|
63
|
+
* and removes any resulting empty strings.
|
|
64
|
+
*/
|
|
28
65
|
private formatDirnames;
|
|
66
|
+
/** Returns the names of all immediate subdirectories under the base path */
|
|
29
67
|
private getAllDirNamesUnderBase;
|
|
68
|
+
/**
|
|
69
|
+
* Builds a tree rooted at base, containing only the specified subdirectories.
|
|
70
|
+
* @param dirNames - Relative directory names to include as top-level nodes
|
|
71
|
+
*/
|
|
30
72
|
private buildByDirNames;
|
|
73
|
+
/**
|
|
74
|
+
* Builds a tree using only the subdirectories under base that pass the given filter.
|
|
75
|
+
* @param filter - A predicate applied to each top-level directory name
|
|
76
|
+
*/
|
|
31
77
|
private buildByFilter;
|
|
78
|
+
/**
|
|
79
|
+
* Computes the relative and absolute paths for a given node
|
|
80
|
+
* by walking up the parent chain.
|
|
81
|
+
*/
|
|
32
82
|
getPathBy(node: PathTreeNode): {
|
|
33
83
|
relative: string;
|
|
34
84
|
absolute: string;
|
|
35
85
|
};
|
|
86
|
+
/** Overload: build the tree from an explicit list of relative directory names */
|
|
36
87
|
buildBy(dirNames: string[]): PathTreeNode;
|
|
88
|
+
/** Overload: build the tree from a predicate applied to top-level directory names */
|
|
37
89
|
buildBy(filter: (dirName: string) => boolean): PathTreeNode;
|
|
90
|
+
/** Builds a full tree from all immediate subdirectories under the base path */
|
|
38
91
|
build(): PathTreeNode;
|
|
39
92
|
}
|
|
40
93
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "path-treeify",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0-beta.db6fe0b",
|
|
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",
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"dist/**/*.d.ts"
|
|
25
25
|
],
|
|
26
26
|
"scripts": {
|
|
27
|
-
"test": "
|
|
27
|
+
"test": "ava",
|
|
28
|
+
"test:watch": "ava --watch",
|
|
28
29
|
"clean": "rimraf ./dist",
|
|
29
30
|
"build": "npm run clean && rollup -c",
|
|
30
31
|
"build:dev": "NODE_ENV=development npm run build",
|
|
@@ -34,6 +35,14 @@
|
|
|
34
35
|
"publish:beta": "npm publish --tag beta --access public",
|
|
35
36
|
"publish:latest": "npm publish --tag latest --access public"
|
|
36
37
|
},
|
|
38
|
+
"ava": {
|
|
39
|
+
"files": [
|
|
40
|
+
"tests/**/*.mjs"
|
|
41
|
+
],
|
|
42
|
+
"nodeArguments": [
|
|
43
|
+
"--experimental-vm-modules"
|
|
44
|
+
]
|
|
45
|
+
},
|
|
37
46
|
"repository": {
|
|
38
47
|
"type": "git",
|
|
39
48
|
"url": "git+https://github.com/isaaxite/path-treeify.git"
|
|
@@ -62,6 +71,7 @@
|
|
|
62
71
|
"@rollup/plugin-terser": "^1.0.0",
|
|
63
72
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
64
73
|
"@types/node": "^25.5.0",
|
|
74
|
+
"ava": "^7.0.0",
|
|
65
75
|
"nodemon": "^3.1.14",
|
|
66
76
|
"rimraf": "^6.1.3",
|
|
67
77
|
"rollup": "^4.59.0",
|