Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 115 additions & 13 deletions ext/node/polyfills/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3129,10 +3129,99 @@
next();
}

// Mirrors Node's `validateIgnoreOption` /
// `createIgnoreMatcher` from `lib/internal/fs/watchers.js`.
// Accepts a string (minimatch glob), RegExp, function, or array of those.
// Returns a function `(filename) => boolean` (or `null` if `ignore` is nullish).
type IgnoreOption =
| string
| RegExp
| ((filename: string) => boolean)
| (string | RegExp | ((filename: string) => boolean))[]
| undefined
| null;

let _lazyMinimatch: any = null;
function getMinimatch() {
_lazyMinimatch ??= core.createLazyLoader("ext:deno_node/deps/minimatch.js");
return _lazyMinimatch();
}

function validateIgnoreOptionElement(value: unknown, name: string) {
if (typeof value === "string") {
if (value.length === 0) {
throw new ERR_INVALID_ARG_VALUE(
name,
value,
"must be a non-empty string",
);
}
return;
}
if (value instanceof RegExp) return;

Check failure on line 3161 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug linux-x86_64

Don't use the global intrinsic

Check failure on line 3161 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug linux-x86_64

Don't use `instanceof` operator

Check failure on line 3161 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug macos-x86_64

Don't use the global intrinsic

Check failure on line 3161 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug macos-x86_64

Don't use `instanceof` operator

Check failure on line 3161 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug windows-x86_64

Don't use the global intrinsic

Check failure on line 3161 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug windows-x86_64

Don't use `instanceof` operator
Comment thread
nathanwhitbot marked this conversation as resolved.
Outdated
if (typeof value === "function") return;
throw new ERR_INVALID_ARG_TYPE(
name,
["string", "RegExp", "Function"],
value,
);
}

function validateIgnoreOption(value: unknown, name: string) {
if (value == null) return;
if (Array.isArray(value)) {

Check failure on line 3172 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug linux-x86_64

Don't use the global intrinsic

Check failure on line 3172 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug macos-x86_64

Don't use the global intrinsic

Check failure on line 3172 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug windows-x86_64

Don't use the global intrinsic
for (let i = 0; i < value.length; i++) {
validateIgnoreOptionElement(value[i], `${name}[${i}]`);
}
return;
}
validateIgnoreOptionElement(value, name);
}

function createIgnoreMatcher(
ignore: IgnoreOption,
): ((filename: string) => boolean) | null {
if (ignore == null) return null;
const matchers = Array.isArray(ignore) ? ignore : [ignore];

Check failure on line 3185 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug linux-x86_64

Don't use the global intrinsic

Check failure on line 3185 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug macos-x86_64

Don't use the global intrinsic

Check failure on line 3185 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug windows-x86_64

Don't use the global intrinsic
const compiled: Array<(filename: string) => boolean> = [];

for (let i = 0; i < matchers.length; i++) {
const matcher = matchers[i];
if (typeof matcher === "string") {
const { Minimatch } = getMinimatch().default;
const mm = new Minimatch(matcher, {
nocase: isMacOS || isWindows,
windowsPathsNoEscape: true,
nonegate: true,
nocomment: true,
optimizationLevel: 2,
platform: isWindows ? "win32" : "posix",
// Allow patterns without slashes to match the basename
// e.g. '*.log' matches 'subdir/file.log'.
matchBase: true,
});
compiled.push((filename: string) => mm.match(filename));

Check failure on line 3203 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug linux-x86_64

Don't use the global intrinsic

Check failure on line 3203 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug linux-x86_64

Don't use the global intrinsic

Check failure on line 3203 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug macos-x86_64

Don't use the global intrinsic

Check failure on line 3203 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug macos-x86_64

Don't use the global intrinsic

Check failure on line 3203 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug windows-x86_64

Don't use the global intrinsic

Check failure on line 3203 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug windows-x86_64

Don't use the global intrinsic
} else if (matcher instanceof RegExp) {

Check failure on line 3204 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug linux-x86_64

Don't use the global intrinsic

Check failure on line 3204 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug linux-x86_64

Don't use `instanceof` operator

Check failure on line 3204 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug macos-x86_64

Don't use the global intrinsic

Check failure on line 3204 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug macos-x86_64

Don't use `instanceof` operator

Check failure on line 3204 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug windows-x86_64

Don't use the global intrinsic

Check failure on line 3204 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug windows-x86_64

Don't use `instanceof` operator
compiled.push((filename: string) => matcher.test(filename));

Check failure on line 3205 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug linux-x86_64

Don't use the global intrinsic

Check failure on line 3205 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug macos-x86_64

Don't use the global intrinsic

Check failure on line 3205 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug windows-x86_64

Don't use the global intrinsic
} else {
// Function
compiled.push(matcher as (filename: string) => boolean);

Check failure on line 3208 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug linux-x86_64

Don't use the global intrinsic

Check failure on line 3208 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug macos-x86_64

Don't use the global intrinsic

Check failure on line 3208 in ext/node/polyfills/fs.ts

View workflow job for this annotation

GitHub Actions / lint debug windows-x86_64

Don't use the global intrinsic
}
}

return (filename: string) => {
for (let i = 0; i < compiled.length; i++) {
if (compiled[i](filename)) return true;
}
return false;
};
}

type watchOptions = {
persistent?: boolean;
recursive?: boolean;
encoding?: string;
ignore?: IgnoreOption;
};

type watchListener = (eventType: string, filename: string) => void;
Expand Down Expand Up @@ -3171,6 +3260,8 @@
const watchPath = getValidatedPath(filename).toString();

const recursive = options?.recursive || false;
validateIgnoreOption(options?.ignore, "options.ignore");
const ignoreMatcher = createIgnoreMatcher(options?.ignore);
const iterator: Deno.FsWatcher = Deno.watchFs(watchPath, {
recursive,
});
Expand All @@ -3187,6 +3278,9 @@
const filename = recursive
? relative(resolvedWatchPath, val.paths[0])
: basename(val.paths[0]);
if (ignoreMatcher !== null && ignoreMatcher(filename)) {
return;
}
fsWatcher.emit(
"change",
convertDenoFsEventToNodeFsEvent(val.kind),
Expand Down Expand Up @@ -3227,12 +3321,15 @@
recursive?: boolean;
encoding?: string;
signal?: AbortSignal;
ignore?: IgnoreOption;
},
): AsyncIterable<{ eventType: string; filename: string | Buffer | null }> {
// deno-lint-ignore prefer-primordials
const watchPath = getValidatedPath(filename).toString();

const recursive = options?.recursive ?? false;
validateIgnoreOption(options?.ignore, "options.ignore");
const ignoreMatcher = createIgnoreMatcher(options?.ignore);
const watcher = Deno.watchFs(watchPath, {
recursive,
});
Expand All @@ -3255,20 +3352,25 @@
async next(): Promise<
IteratorResult<{ eventType: string; filename: string | Buffer | null }>
> {
// deno-lint-ignore prefer-primordials
const iterResult = await fsIterable.next();
if (iterResult.done) return iterResult;
while (true) {
// deno-lint-ignore prefer-primordials
const iterResult = await fsIterable.next();
if (iterResult.done) return iterResult;

const eventType = convertDenoFsEventToNodeFsEvent(
iterResult.value.kind,
);
const fname = recursive
? relative(resolvedWatchPath, iterResult.value.paths[0])
: basename(iterResult.value.paths[0]);
return {
value: { eventType, filename: fname },
done: false,
};
const eventType = convertDenoFsEventToNodeFsEvent(
iterResult.value.kind,
);
const fname = recursive
? relative(resolvedWatchPath, iterResult.value.paths[0])
: basename(iterResult.value.paths[0]);
if (ignoreMatcher !== null && ignoreMatcher(fname)) {
continue;
}
return {
value: { eventType, filename: fname },
done: false,
};
}
},
// deno-lint-ignore no-explicit-any
return(value?: any): Promise<IteratorResult<any>> {
Expand Down
14 changes: 14 additions & 0 deletions tests/node_compat/config.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,11 @@
"parallel/test-fs-promises-readfile-empty.js": {},
"parallel/test-fs-promises-readfile-with-fd.js": {},
"parallel/test-fs-promises-statfs-validate-path.js": {},
"parallel/test-fs-promises-watch-ignore-function.mjs": {},
Comment thread
nathanwhitbot marked this conversation as resolved.
"parallel/test-fs-promises-watch-ignore-glob.mjs": {},
"parallel/test-fs-promises-watch-ignore-invalid.mjs": {},
"parallel/test-fs-promises-watch-ignore-mixed.mjs": {},
"parallel/test-fs-promises-watch-ignore-regexp.mjs": {},
"parallel/test-fs-promises-watch-iterator.js": {},
"parallel/test-fs-promises-write-optional-params.js": {},
"parallel/test-fs-promises-writefile-typedarray.js": {},
Expand Down Expand Up @@ -1190,6 +1195,15 @@
"parallel/test-fs-utimes-y2K38.js": {},
"parallel/test-fs-utimes.js": {},
"parallel/test-fs-watch-file-enoent-after-deletion.js": {},
"parallel/test-fs-watch-ignore-function.js": {},
"parallel/test-fs-watch-ignore-glob.js": {},
"parallel/test-fs-watch-ignore-invalid.js": {},
"parallel/test-fs-watch-ignore-mixed.js": {},
"parallel/test-fs-watch-ignore-recursive-glob-subdirectories.js": {},
"parallel/test-fs-watch-ignore-recursive-glob.js": {},
"parallel/test-fs-watch-ignore-recursive-mixed.js": {},
"parallel/test-fs-watch-ignore-recursive-regexp.js": {},
"parallel/test-fs-watch-ignore-regexp.js": {},
"parallel/test-fs-watch-recursive-add-file-to-existing-subfolder.js": {},
"parallel/test-fs-watch-recursive-add-folder.js": {},
"parallel/test-fs-watch-recursive-delete.js": {},
Expand Down
Loading