@qodalis/cli-files 2.0.0-beta.13 → 2.0.0-beta.15
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/package.json +2 -2
- package/public-api.d.mts +86 -2
- package/public-api.d.ts +86 -2
- package/public-api.js +308 -17
- package/public-api.js.map +1 -1
- package/public-api.mjs +303 -19
- package/public-api.mjs.map +1 -1
- package/umd/index.global.js +178 -15
package/umd/index.global.js
CHANGED
|
@@ -628,14 +628,14 @@ var files = (() => {
|
|
|
628
628
|
var require_sort = __commonJS({
|
|
629
629
|
"../../node_modules/.pnpm/semver@7.7.4/node_modules/semver/functions/sort.js"(exports$1, module2) {
|
|
630
630
|
var compareBuild = require_compare_build();
|
|
631
|
-
var sort = (
|
|
631
|
+
var sort = (list2, loose) => list2.sort((a, b) => compareBuild(a, b, loose));
|
|
632
632
|
module2.exports = sort;
|
|
633
633
|
}
|
|
634
634
|
});
|
|
635
635
|
var require_rsort = __commonJS({
|
|
636
636
|
"../../node_modules/.pnpm/semver@7.7.4/node_modules/semver/functions/rsort.js"(exports$1, module2) {
|
|
637
637
|
var compareBuild = require_compare_build();
|
|
638
|
-
var rsort = (
|
|
638
|
+
var rsort = (list2, loose) => list2.sort((a, b) => compareBuild(b, a, loose));
|
|
639
639
|
module2.exports = rsort;
|
|
640
640
|
}
|
|
641
641
|
});
|
|
@@ -1838,6 +1838,17 @@ var files = (() => {
|
|
|
1838
1838
|
if (!provider) return {};
|
|
1839
1839
|
return typeof provider === "function" ? provider() : provider;
|
|
1840
1840
|
}
|
|
1841
|
+
var CliAccessDeniedError = class _CliAccessDeniedError extends Error {
|
|
1842
|
+
constructor(message = "permission denied") {
|
|
1843
|
+
super(message);
|
|
1844
|
+
this.code = "EACCES";
|
|
1845
|
+
this.name = "CliAccessDeniedError";
|
|
1846
|
+
Object.setPrototypeOf(this, _CliAccessDeniedError.prototype);
|
|
1847
|
+
}
|
|
1848
|
+
};
|
|
1849
|
+
function isCliAccessDeniedError(error) {
|
|
1850
|
+
return error instanceof CliAccessDeniedError || !!error && typeof error === "object" && error.name === "CliAccessDeniedError";
|
|
1851
|
+
}
|
|
1841
1852
|
var DefaultLibraryAuthor = {
|
|
1842
1853
|
name: "Nicolae Lupei",
|
|
1843
1854
|
email: "nicolae.lupei@qodalis.com"
|
|
@@ -2701,7 +2712,7 @@ var files = (() => {
|
|
|
2701
2712
|
};
|
|
2702
2713
|
|
|
2703
2714
|
// src/lib/version.ts
|
|
2704
|
-
var LIBRARY_VERSION = "2.0.0-beta.
|
|
2715
|
+
var LIBRARY_VERSION = "2.0.0-beta.15";
|
|
2705
2716
|
var API_VERSION2 = 2;
|
|
2706
2717
|
|
|
2707
2718
|
// src/lib/interfaces/i-file-system-service.ts
|
|
@@ -2714,6 +2725,7 @@ var files = (() => {
|
|
|
2714
2725
|
var CWD_KEY = "cwd";
|
|
2715
2726
|
var HOME_KEY = "home";
|
|
2716
2727
|
var DEFAULT_HOME = "/";
|
|
2728
|
+
var ANONYMOUS_OWNERSHIP = { uid: "nobody", gid: "nogroup" };
|
|
2717
2729
|
function createSeedFileSystem() {
|
|
2718
2730
|
const now = Date.now();
|
|
2719
2731
|
return {
|
|
@@ -2761,6 +2773,88 @@ var files = (() => {
|
|
|
2761
2773
|
this.homePath = DEFAULT_HOME;
|
|
2762
2774
|
this.currentUid = null;
|
|
2763
2775
|
this.currentGroups = [];
|
|
2776
|
+
this.systemDepth = 0;
|
|
2777
|
+
}
|
|
2778
|
+
// --- Access control ---
|
|
2779
|
+
setAccessPolicy(policy) {
|
|
2780
|
+
this.accessPolicy = policy;
|
|
2781
|
+
}
|
|
2782
|
+
runAsSystem(fn) {
|
|
2783
|
+
this.systemDepth++;
|
|
2784
|
+
try {
|
|
2785
|
+
return fn();
|
|
2786
|
+
} finally {
|
|
2787
|
+
this.systemDepth--;
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
reassignOwner(fromUid, toUid) {
|
|
2791
|
+
const from = fromUid.toLowerCase();
|
|
2792
|
+
if (!from || !toUid) return 0;
|
|
2793
|
+
let changed = 0;
|
|
2794
|
+
const visit = (node) => {
|
|
2795
|
+
if (node.ownership && node.ownership.uid.toLowerCase() === from) {
|
|
2796
|
+
node.ownership = { ...node.ownership, uid: toUid };
|
|
2797
|
+
changed++;
|
|
2798
|
+
}
|
|
2799
|
+
node.children?.forEach(visit);
|
|
2800
|
+
};
|
|
2801
|
+
visit(this.root);
|
|
2802
|
+
return changed;
|
|
2803
|
+
}
|
|
2804
|
+
canTraverse(path) {
|
|
2805
|
+
try {
|
|
2806
|
+
this.assertTraverse(this.resolvePath(path), "stat", path);
|
|
2807
|
+
return true;
|
|
2808
|
+
} catch {
|
|
2809
|
+
return false;
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
get enforcing() {
|
|
2813
|
+
return !!this.accessPolicy && this.systemDepth === 0;
|
|
2814
|
+
}
|
|
2815
|
+
deny(op, path, reason = "Permission denied") {
|
|
2816
|
+
throw new CliAccessDeniedError(`${op}: ${path}: ${reason}`);
|
|
2817
|
+
}
|
|
2818
|
+
/** `x` on every existing directory on the way to `resolved` (excluding the target). */
|
|
2819
|
+
assertTraverse(resolved, op, display) {
|
|
2820
|
+
if (!this.enforcing) return;
|
|
2821
|
+
const parts = resolved.split("/").filter(Boolean);
|
|
2822
|
+
let current = this.root;
|
|
2823
|
+
for (let i = 0; i < parts.length; i++) {
|
|
2824
|
+
if (!current || current.type !== "directory") return;
|
|
2825
|
+
if (!this.accessPolicy.canAccess(current, "execute")) this.deny(op, display);
|
|
2826
|
+
current = current.children?.find((c) => c.name === parts[i]);
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
assertAccess(node, action, op, display) {
|
|
2830
|
+
if (this.enforcing && !this.accessPolicy.canAccess(node, action)) this.deny(op, display);
|
|
2831
|
+
}
|
|
2832
|
+
/** Recursive delete: every directory inside must allow removing its entries (`w` + `x`, readable). */
|
|
2833
|
+
assertRemovableTree(dir, dirPath, display) {
|
|
2834
|
+
if (!this.enforcing) return;
|
|
2835
|
+
this.assertAccess(dir, "read", "rm", display);
|
|
2836
|
+
this.assertAccess(dir, "execute", "rm", display);
|
|
2837
|
+
if ((dir.children?.length ?? 0) > 0) this.assertAccess(dir, "write", "rm", display);
|
|
2838
|
+
for (const child of dir.children ?? []) {
|
|
2839
|
+
if (child.type === "directory") this.assertRemovableTree(child, `${dirPath}/${child.name}`, display);
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
/** Copying reads everything it copies: `r` on every file, `r` + `x` on every directory. */
|
|
2843
|
+
assertReadableTree(node, display) {
|
|
2844
|
+
if (!this.enforcing) return;
|
|
2845
|
+
this.assertAccess(node, "read", "cp", display);
|
|
2846
|
+
if (node.type !== "directory") return;
|
|
2847
|
+
this.assertAccess(node, "execute", "cp", display);
|
|
2848
|
+
for (const child of node.children ?? []) {
|
|
2849
|
+
this.assertReadableTree(child, `${display.replace(/\/+$/, "")}/${child.name}`);
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
/** Creating/removing entries needs `w` and `x` on the containing directory. */
|
|
2853
|
+
assertModifyDir(dir, dirPath, op, display) {
|
|
2854
|
+
if (!this.enforcing) return;
|
|
2855
|
+
this.assertTraverse(dirPath, op, display);
|
|
2856
|
+
this.assertAccess(dir, "execute", op, display);
|
|
2857
|
+
this.assertAccess(dir, "write", op, display);
|
|
2764
2858
|
}
|
|
2765
2859
|
// --- User context ---
|
|
2766
2860
|
setCurrentUser(uid, groups) {
|
|
@@ -2768,7 +2862,9 @@ var files = (() => {
|
|
|
2768
2862
|
this.currentGroups = groups;
|
|
2769
2863
|
}
|
|
2770
2864
|
getDefaultOwnership() {
|
|
2771
|
-
if (!this.currentUid)
|
|
2865
|
+
if (!this.currentUid) {
|
|
2866
|
+
return this.accessPolicy ? { ...ANONYMOUS_OWNERSHIP } : void 0;
|
|
2867
|
+
}
|
|
2772
2868
|
return {
|
|
2773
2869
|
uid: this.currentUid,
|
|
2774
2870
|
gid: this.currentGroups[0] || "users"
|
|
@@ -2787,6 +2883,8 @@ var files = (() => {
|
|
|
2787
2883
|
if (node.type !== "directory") {
|
|
2788
2884
|
throw new Error(`cd: ${path}: Not a directory`);
|
|
2789
2885
|
}
|
|
2886
|
+
this.assertTraverse(resolved, "cd", path);
|
|
2887
|
+
this.assertAccess(node, "execute", "cd", path);
|
|
2790
2888
|
this.cwd = resolved;
|
|
2791
2889
|
}
|
|
2792
2890
|
getHomePath() {
|
|
@@ -2843,6 +2941,8 @@ var files = (() => {
|
|
|
2843
2941
|
if (node.type !== "directory") {
|
|
2844
2942
|
throw new Error(`ls: ${path}: Not a directory`);
|
|
2845
2943
|
}
|
|
2944
|
+
this.assertTraverse(this.resolvePath(path), "ls", path);
|
|
2945
|
+
this.assertAccess(node, "read", "ls", path);
|
|
2846
2946
|
return node.children || [];
|
|
2847
2947
|
}
|
|
2848
2948
|
readFile(path) {
|
|
@@ -2853,6 +2953,8 @@ var files = (() => {
|
|
|
2853
2953
|
if (node.type === "directory") {
|
|
2854
2954
|
throw new Error(`cat: ${path}: Is a directory`);
|
|
2855
2955
|
}
|
|
2956
|
+
this.assertTraverse(this.resolvePath(path), "cat", path);
|
|
2957
|
+
this.assertAccess(node, "read", "cat", path);
|
|
2856
2958
|
return node.content ?? "";
|
|
2857
2959
|
}
|
|
2858
2960
|
exists(path) {
|
|
@@ -2877,6 +2979,10 @@ var files = (() => {
|
|
|
2877
2979
|
}
|
|
2878
2980
|
let child = current.children.find((c) => c.name === part);
|
|
2879
2981
|
if (!child) {
|
|
2982
|
+
if (this.enforcing) {
|
|
2983
|
+
this.assertAccess(current, "execute", "mkdir", path);
|
|
2984
|
+
this.assertAccess(current, "write", "mkdir", path);
|
|
2985
|
+
}
|
|
2880
2986
|
const now = Date.now();
|
|
2881
2987
|
child = {
|
|
2882
2988
|
name: part,
|
|
@@ -2892,6 +2998,8 @@ var files = (() => {
|
|
|
2892
2998
|
current.modifiedAt = now;
|
|
2893
2999
|
} else if (child.type !== "directory") {
|
|
2894
3000
|
throw new Error(`mkdir: ${part}: Not a directory`);
|
|
3001
|
+
} else {
|
|
3002
|
+
this.assertAccess(child, "execute", "mkdir", path);
|
|
2895
3003
|
}
|
|
2896
3004
|
current = child;
|
|
2897
3005
|
}
|
|
@@ -2910,6 +3018,7 @@ var files = (() => {
|
|
|
2910
3018
|
if (parent.children?.find((c) => c.name === dirName)) {
|
|
2911
3019
|
throw new Error(`mkdir: ${path}: File exists`);
|
|
2912
3020
|
}
|
|
3021
|
+
this.assertModifyDir(parent, parentPath, "mkdir", path);
|
|
2913
3022
|
const now = Date.now();
|
|
2914
3023
|
if (!parent.children) {
|
|
2915
3024
|
parent.children = [];
|
|
@@ -2944,6 +3053,12 @@ var files = (() => {
|
|
|
2944
3053
|
}
|
|
2945
3054
|
const existing = parent.children?.find((c) => c.name === fileName);
|
|
2946
3055
|
const now = Date.now();
|
|
3056
|
+
if (existing) {
|
|
3057
|
+
this.assertTraverse(resolved, "touch", path);
|
|
3058
|
+
this.assertAccess(existing, "write", "touch", path);
|
|
3059
|
+
} else {
|
|
3060
|
+
this.assertModifyDir(parent, parentPath, "touch", path);
|
|
3061
|
+
}
|
|
2947
3062
|
if (existing) {
|
|
2948
3063
|
existing.modifiedAt = now;
|
|
2949
3064
|
} else {
|
|
@@ -2970,6 +3085,8 @@ var files = (() => {
|
|
|
2970
3085
|
if (node.type === "directory") {
|
|
2971
3086
|
throw new Error(`write: ${path}: Is a directory`);
|
|
2972
3087
|
}
|
|
3088
|
+
this.assertTraverse(resolved, "write", path);
|
|
3089
|
+
this.assertAccess(node, "write", "write", path);
|
|
2973
3090
|
const now = Date.now();
|
|
2974
3091
|
node.content = append ? (node.content ?? "") + content : content;
|
|
2975
3092
|
node.size = new Blob([node.content]).size;
|
|
@@ -2998,6 +3115,8 @@ var files = (() => {
|
|
|
2998
3115
|
if (target.type === "directory" && !recursive) {
|
|
2999
3116
|
throw new Error(`rm: ${path}: Is a directory`);
|
|
3000
3117
|
}
|
|
3118
|
+
this.assertModifyDir(parent, parentPath, "rm", path);
|
|
3119
|
+
if (target.type === "directory") this.assertRemovableTree(target, resolved, path);
|
|
3001
3120
|
parent.children.splice(index, 1);
|
|
3002
3121
|
parent.modifiedAt = Date.now();
|
|
3003
3122
|
}
|
|
@@ -3012,10 +3131,13 @@ var files = (() => {
|
|
|
3012
3131
|
`cp: -r not specified; omitting directory '${src}'`
|
|
3013
3132
|
);
|
|
3014
3133
|
}
|
|
3134
|
+
this.assertTraverse(srcResolved, "cp", src);
|
|
3135
|
+
this.assertReadableTree(srcNode, src);
|
|
3015
3136
|
const destResolved = this.resolvePath(dest);
|
|
3016
3137
|
const destNode = this.getNode(destResolved);
|
|
3017
3138
|
if (destNode && destNode.type === "directory") {
|
|
3018
|
-
|
|
3139
|
+
this.assertModifyDir(destNode, destResolved, "cp", dest);
|
|
3140
|
+
const clone = this.ownedByCurrentUser(this.cloneNode(srcNode));
|
|
3019
3141
|
if (!destNode.children) {
|
|
3020
3142
|
destNode.children = [];
|
|
3021
3143
|
}
|
|
@@ -3035,7 +3157,8 @@ var files = (() => {
|
|
|
3035
3157
|
if (!parent || parent.type !== "directory") {
|
|
3036
3158
|
throw new Error(`cp: ${parentPath}: No such file or directory`);
|
|
3037
3159
|
}
|
|
3038
|
-
|
|
3160
|
+
this.assertModifyDir(parent, parentPath, "cp", dest);
|
|
3161
|
+
const clone = this.ownedByCurrentUser(this.cloneNode(srcNode));
|
|
3039
3162
|
clone.name = newName;
|
|
3040
3163
|
if (!parent.children) {
|
|
3041
3164
|
parent.children = [];
|
|
@@ -3067,10 +3190,12 @@ var files = (() => {
|
|
|
3067
3190
|
if (!srcParent || !srcParent.children) {
|
|
3068
3191
|
throw new Error(`mv: ${src}: No such file or directory`);
|
|
3069
3192
|
}
|
|
3193
|
+
this.assertModifyDir(srcParent, srcParentPath, "mv", src);
|
|
3070
3194
|
const srcIndex = srcParent.children.findIndex(
|
|
3071
3195
|
(c) => c.name === srcNode.name
|
|
3072
3196
|
);
|
|
3073
3197
|
if (destNode && destNode.type === "directory") {
|
|
3198
|
+
this.assertModifyDir(destNode, destResolved, "mv", dest);
|
|
3074
3199
|
if (!destNode.children) {
|
|
3075
3200
|
destNode.children = [];
|
|
3076
3201
|
}
|
|
@@ -3093,6 +3218,7 @@ var files = (() => {
|
|
|
3093
3218
|
`mv: ${destParentPath}: No such file or directory`
|
|
3094
3219
|
);
|
|
3095
3220
|
}
|
|
3221
|
+
this.assertModifyDir(destParent, destParentPath, "mv", dest);
|
|
3096
3222
|
srcParent.children.splice(srcIndex, 1);
|
|
3097
3223
|
srcNode.name = newName;
|
|
3098
3224
|
if (!destParent.children) {
|
|
@@ -3116,6 +3242,9 @@ var files = (() => {
|
|
|
3116
3242
|
if (!node) {
|
|
3117
3243
|
throw new Error(`chmod: ${path}: No such file or directory`);
|
|
3118
3244
|
}
|
|
3245
|
+
if (this.enforcing && !this.accessPolicy.canChangeOwnership(node)) {
|
|
3246
|
+
this.deny("chmod", path, "Operation not permitted");
|
|
3247
|
+
}
|
|
3119
3248
|
node.permissions = permissions;
|
|
3120
3249
|
}
|
|
3121
3250
|
chown(path, ownership) {
|
|
@@ -3124,6 +3253,9 @@ var files = (() => {
|
|
|
3124
3253
|
if (!node) {
|
|
3125
3254
|
throw new Error(`chown: ${path}: No such file or directory`);
|
|
3126
3255
|
}
|
|
3256
|
+
if (this.enforcing && !this.accessPolicy.canChangeOwnership(node, ownership)) {
|
|
3257
|
+
this.deny("chown", path, "Operation not permitted");
|
|
3258
|
+
}
|
|
3127
3259
|
node.ownership = ownership;
|
|
3128
3260
|
}
|
|
3129
3261
|
// --- Persistence ---
|
|
@@ -3165,6 +3297,18 @@ var files = (() => {
|
|
|
3165
3297
|
}
|
|
3166
3298
|
}
|
|
3167
3299
|
// --- Private helpers ---
|
|
3300
|
+
/** A copy belongs to whoever made it (like `cp` without `-p`) */
|
|
3301
|
+
ownedByCurrentUser(node) {
|
|
3302
|
+
const owner = this.getDefaultOwnership();
|
|
3303
|
+
if (owner) {
|
|
3304
|
+
const apply = (n) => {
|
|
3305
|
+
n.ownership = { ...owner };
|
|
3306
|
+
n.children?.forEach(apply);
|
|
3307
|
+
};
|
|
3308
|
+
apply(node);
|
|
3309
|
+
}
|
|
3310
|
+
return node;
|
|
3311
|
+
}
|
|
3168
3312
|
cloneNode(node) {
|
|
3169
3313
|
const now = Date.now();
|
|
3170
3314
|
const clone = {
|
|
@@ -3773,6 +3917,16 @@ var files = (() => {
|
|
|
3773
3917
|
}
|
|
3774
3918
|
};
|
|
3775
3919
|
|
|
3920
|
+
// src/lib/utils/readable-children.ts
|
|
3921
|
+
function readableChildren(fs, path) {
|
|
3922
|
+
try {
|
|
3923
|
+
return fs.listDirectory(path);
|
|
3924
|
+
} catch (e) {
|
|
3925
|
+
if (isCliAccessDeniedError(e)) return null;
|
|
3926
|
+
throw e;
|
|
3927
|
+
}
|
|
3928
|
+
}
|
|
3929
|
+
|
|
3776
3930
|
// src/lib/processors/cli-tree-command-processor.ts
|
|
3777
3931
|
var CliTreeCommandProcessor = class {
|
|
3778
3932
|
constructor() {
|
|
@@ -3820,7 +3974,8 @@ var files = (() => {
|
|
|
3820
3974
|
)
|
|
3821
3975
|
);
|
|
3822
3976
|
const counts = { dirs: 0, files: 0 };
|
|
3823
|
-
this.
|
|
3977
|
+
this.fs = fs;
|
|
3978
|
+
this.printTree(node, "", true, 0, maxDepth, context, counts, resolvedPath);
|
|
3824
3979
|
context.writer.writeln();
|
|
3825
3980
|
context.writer.writeln(
|
|
3826
3981
|
`${counts.dirs} directories, ${counts.files} files`
|
|
@@ -3829,11 +3984,15 @@ var files = (() => {
|
|
|
3829
3984
|
context.writer.writeError(e.message);
|
|
3830
3985
|
}
|
|
3831
3986
|
}
|
|
3832
|
-
printTree(node, prefix, isRoot, depth, maxDepth, context, counts) {
|
|
3833
|
-
if (
|
|
3987
|
+
printTree(node, prefix, isRoot, depth, maxDepth, context, counts, path = "/") {
|
|
3988
|
+
if (depth >= maxDepth) {
|
|
3989
|
+
return;
|
|
3990
|
+
}
|
|
3991
|
+
const visible = this.fs ? readableChildren(this.fs, path) : node.children;
|
|
3992
|
+
if (!visible) {
|
|
3834
3993
|
return;
|
|
3835
3994
|
}
|
|
3836
|
-
const children = [...
|
|
3995
|
+
const children = [...visible].sort((a, b) => {
|
|
3837
3996
|
if (a.type !== b.type) {
|
|
3838
3997
|
return a.type === "directory" ? -1 : 1;
|
|
3839
3998
|
}
|
|
@@ -3858,7 +4017,8 @@ var files = (() => {
|
|
|
3858
4017
|
depth + 1,
|
|
3859
4018
|
maxDepth,
|
|
3860
4019
|
context,
|
|
3861
|
-
counts
|
|
4020
|
+
counts,
|
|
4021
|
+
path === "/" ? `/${child.name}` : `${path}/${child.name}`
|
|
3862
4022
|
);
|
|
3863
4023
|
} else {
|
|
3864
4024
|
counts.files++;
|
|
@@ -4156,6 +4316,7 @@ var files = (() => {
|
|
|
4156
4316
|
const resolvedBase = fs.resolvePath(searchPath);
|
|
4157
4317
|
const nameRegex = namePattern ? this.globToRegex(namePattern) : null;
|
|
4158
4318
|
const results = [];
|
|
4319
|
+
this.fs = fs;
|
|
4159
4320
|
this.walk(
|
|
4160
4321
|
node,
|
|
4161
4322
|
resolvedBase,
|
|
@@ -4183,8 +4344,9 @@ var files = (() => {
|
|
|
4183
4344
|
return new RegExp(`^${regexStr}$`, "i");
|
|
4184
4345
|
}
|
|
4185
4346
|
walk(node, currentPath, depth, maxDepth, nameRegex, typeFilter, results) {
|
|
4186
|
-
|
|
4187
|
-
|
|
4347
|
+
const children = this.fs ? readableChildren(this.fs, currentPath) : node.children;
|
|
4348
|
+
if (!children) return;
|
|
4349
|
+
for (const child of children) {
|
|
4188
4350
|
const childPath = currentPath === "/" ? `/${child.name}` : `${currentPath}/${child.name}`;
|
|
4189
4351
|
let matches = true;
|
|
4190
4352
|
if (nameRegex && !nameRegex.test(child.name)) {
|
|
@@ -4417,8 +4579,9 @@ var files = (() => {
|
|
|
4417
4579
|
};
|
|
4418
4580
|
}
|
|
4419
4581
|
collectFiles(fs, basePath, node, result) {
|
|
4420
|
-
|
|
4421
|
-
|
|
4582
|
+
const children = readableChildren(fs, basePath);
|
|
4583
|
+
if (!children) return;
|
|
4584
|
+
for (const child of children) {
|
|
4422
4585
|
const childPath = basePath === "/" ? `/${child.name}` : `${basePath}/${child.name}`;
|
|
4423
4586
|
if (child.type === "file") {
|
|
4424
4587
|
result.push(childPath);
|