vfs.hide and .remove as single mask, no array

Massimo Melina committed Feb 1, 2022 at 15:36 UTC 0e1ea9f847894fd1241b237a2054c5d0d1211779
2 files changed +12 -13
README.md
+2 -1
@@ -94,7 +94,8 @@ Valid keys in a node are:
94 - `forbid`: set `true` to forbid listing for this folder
95 - `hide`: similar to hidden, but it's from the parent node point of view.
96 Use this to hide children read from the source, not listed in the VFS.
97 - Value can be just a file name, a mask, or a list of names/masks.
97 + Value is a file mask.
98 +- `remove`: use this to not only hide files but also prevent downloads in a folder with a source. Value is a file mask.
99 - `rename`: similar to name, but it's from the parent node point.
100 Use this to change the name of entries that are read from the source, not listed in the VFS.
101 Value is a dictionary, where the key is the original name.
src/vfs.ts
+10 -12
@@ -1,7 +1,7 @@
1 import fs from 'fs/promises'
2 import { basename } from 'path'
3 import { isMatch } from 'micromatch'
4 -import { complySlashes, enforceFinal, isDirectory, prefix, wantArray } from './misc'
4 +import { enforceFinal, isDirectory, prefix } from './misc'
5 import Koa from 'koa'
6 import glob from 'fast-glob'
7 import _ from 'lodash'
@@ -17,8 +17,8 @@ export interface VfsNode {
17 name: string,
18 source?: string,
19 children?: VfsNode[],
20 - hide?: string | string[],
21 - remove?: string | string[],
20 + hide?: string,
21 + remove?: string,
22 hidden?: boolean,
23 forbid?: boolean,
24 rename?: Record<string,string>,
@@ -57,7 +57,7 @@ export class Vfs {
57 const relativeSource = piece + prefix('/', rest.join('/'))
58 const baseSource = run.source+ '/'
59 const source = baseSource + relativeSource
60 - if (isMatch(source, wantArray(run.remove).map(x => baseSource + x)))
60 + if (run.remove && isMatch(source, run.remove.split('|').map(x => baseSource + x)))
61 return
62 try { await fs.stat(source) } // check existence
63 catch { return }
@@ -110,26 +110,24 @@ export async function* walkNode(parent:VfsNode, ctx: Koa.Context, depth:number=0
110 }
111 if (!source)
112 return
113 - const base = enforceFinal('/', complySlashes(source)) // fast-glob lib wants forward-slashes
114 - const baseForGlob = glob.escapePath(base)
115 - const ignore = [parent.hide, parent.remove].flat().filter(Boolean).map(x => baseForGlob+x)
113 const depthPath = depth === Infinity ? '**/' : _.repeat('*/',depth)
114 try {
118 - const dirStream = glob.stream(baseForGlob + depthPath + '*', {
115 + const dirStream = glob.stream(depthPath + '*', {
116 dot: true,
117 onlyFiles: false,
121 - ignore,
118 + cwd: source,
119 + ignore: [parent.hide, parent.remove].filter(Boolean) as string[],
120 })
121 + const base = enforceFinal('/', source)
122 for await (let path of dirStream) {
123 if (ctx.req.aborted)
124 return
125 if (path instanceof Buffer)
126 path = path.toString('utf8')
128 - const name = path.slice(base.length)
127 yield {
128 type: VfsNodeType.temp,
131 - source: path,
132 - name: prefixPath + (parent!.rename?.[name] || name)
129 + source: base + path,
130 + name: prefixPath + (parent!.rename?.[path] || path)
131 }
132 }
133 }