Skip to content

Commit

Permalink
improve internal types a little bit (#1363)
Browse files Browse the repository at this point in the history
* improve internal types a little bit

* more type improvements

* improve map and set types

* fmt

* type timeouts

* improve `setFsWatchFileListener` arg types
  • Loading branch information
talentlessguy authored Sep 20, 2024
1 parent 4242091 commit bf65c94
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 62 deletions.
52 changes: 26 additions & 26 deletions src/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { WatchListener, WatchEventType, Stats, FSWatcher as NativeFsWatcher
import { open, stat, lstat, realpath as fsrealpath } from 'fs/promises';
import * as sysPath from 'path';
import { type as osType } from 'os';
import type { FSWatcher, WatchHelper, FSWInstanceOptions } from './index.js';
import type { FSWatcher, WatchHelper, FSWInstanceOptions, Throttler } from './index.js';
import type { EntryInfo } from 'readdirp';

export type Path = string;
Expand All @@ -12,7 +12,7 @@ export const STR_DATA = 'data';
export const STR_END = 'end';
export const STR_CLOSE = 'close';
export const EMPTY_FN = () => {};
export const IDENTITY_FN = (val: any) => val;
export const IDENTITY_FN = (val: unknown) => val;

const pl = process.platform;
export const isWindows = pl === 'win32';
Expand Down Expand Up @@ -82,23 +82,23 @@ const isBinaryPath = (filePath: string) =>
binaryExtensions.has(sysPath.extname(filePath).slice(1).toLowerCase());

// TODO: emit errors properly. Example: EMFILE on Macos.
const foreach = (val: any, fn: any) => {
const foreach = <V extends unknown>(val: V, fn: (arg: V) => unknown) => {
if (val instanceof Set) {
val.forEach(fn);
} else {
fn(val);
}
};

const addAndConvert = (main: any, prop: any, item: any) => {
let container = main[prop];
const addAndConvert = (main: Record<string, unknown>, prop: string, item: unknown) => {
let container = (main as Record<string, unknown>)[prop];
if (!(container instanceof Set)) {
main[prop] = container = new Set([container]);
(main as Record<string, unknown>)[prop] = container = new Set([container]);
}
container.add(item);
(container as Set<unknown>).add(item);
};

const clearItem = (cont: any) => (key: string) => {
const clearItem = (cont: Record<string, unknown>) => (key: string) => {
const set = cont[key];
if (set instanceof Set) {
set.clear();
Expand All @@ -107,16 +107,16 @@ const clearItem = (cont: any) => (key: string) => {
}
};

const delFromSet = (main: any, prop: any, item: any) => {
const container = main[prop];
const delFromSet = (main: Record<string, unknown> | Set<unknown>, prop: string, item: unknown) => {
const container = (main as Record<string, unknown>)[prop];
if (container instanceof Set) {
container.delete(item);
} else if (container === item) {
delete main[prop];
delete (main as Record<string, unknown>)[prop];
}
};

const isEmptySet = (val: any) => (val instanceof Set ? val.size === 0 : !val);
const isEmptySet = (val: unknown) => (val instanceof Set ? val.size === 0 : !val);

// fs_watch helpers

Expand Down Expand Up @@ -180,9 +180,9 @@ function createFsWatchInstance(
const fsWatchBroadcast = (
fullPath: Path,
listenerType: string,
val1?: any,
val2?: any,
val3?: any
val1?: unknown,
val2?: unknown,
val3?: unknown
) => {
const cont = FsWatchInstances.get(fullPath);
if (!cont) return;
Expand Down Expand Up @@ -283,7 +283,7 @@ const setFsWatchListener = (

// object to hold per-process fs_watchFile instances
// (may be shared across chokidar FSWatcher instances)
const FsWatchFileInstances = new Map();
const FsWatchFileInstances = new Map<string, any>();

/**
* Instantiates the fs_watchFile interface or binds listeners
Expand All @@ -297,8 +297,8 @@ const FsWatchFileInstances = new Map();
const setFsWatchFileListener = (
path: Path,
fullPath: Path,
options: any,
handlers: any
options: Partial<FSWInstanceOptions>,
handlers: Pick<WatchHandlers, 'rawEmitter' | 'listener'>
): (() => void) => {
const { listener, rawEmitter } = handlers;
let cont = FsWatchFileInstances.get(fullPath);
Expand All @@ -307,7 +307,7 @@ const setFsWatchFileListener = (
// let rawEmitters = new Set();

const copts = cont && cont.options;
if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
if (copts && (copts.persistent < options.persistent! || copts.interval > options.interval!)) {
// "Upgrade" the watcher to persistence or a quicker interval.
// This creates some unlikely edge case issues if the user mixes
// settings in a very weird way, but solving for those cases
Expand All @@ -330,12 +330,12 @@ const setFsWatchFileListener = (
rawEmitters: rawEmitter,
options,
watcher: watchFile(fullPath, options, (curr, prev) => {
foreach(cont.rawEmitters, (rawEmitter: any) => {
foreach(cont.rawEmitters, (rawEmitter) => {
rawEmitter(EV.CHANGE, fullPath, { curr, prev });
});
const currmtime = curr.mtimeMs;
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
foreach(cont.listeners, (listener: any) => listener(path, curr));
foreach(cont.listeners, (listener) => listener(path, curr));
}
}),
};
Expand All @@ -362,10 +362,10 @@ const setFsWatchFileListener = (
*/
export class NodeFsHandler {
fsw: FSWatcher;
_boundHandleError: any;
_boundHandleError: (error: unknown) => void;
constructor(fsW: FSWatcher) {
this.fsw = fsW;
this._boundHandleError = (error: Error) => fsW._handleError(error);
this._boundHandleError = (error) => fsW._handleError(error as Error);
}

/**
Expand Down Expand Up @@ -530,12 +530,12 @@ export class NodeFsHandler {
target: Path,
dir: Path,
depth: number,
throttler: any
throttler: Throttler
) {
// Normalize the directory name on Windows
directory = sysPath.join(directory, '');

throttler = this.fsw._throttle('readdir', directory, 1000);
throttler = this.fsw._throttle('readdir', directory, 1000) as Throttler;
if (!throttler) return;

const previous = this.fsw._getWatchedDir(wh.path);
Expand Down Expand Up @@ -641,7 +641,7 @@ export class NodeFsHandler {
// ensure dir is tracked (harmless if redundant)
parentDir.add(sysPath.basename(dir));
this.fsw._getWatchedDir(dir);
let throttler: any;
let throttler!: Throttler;
let closer;

const oDepth = this.fsw.options.depth;
Expand Down
61 changes: 25 additions & 36 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ type BasicOpts = {
// ioLimit?: number; // Limit parallel IO operations (CPU usage + OS limits)
};

export type Throttler = {
timeoutObject: NodeJS.Timeout;
clear: () => void;
count: number;
};

export type ChokidarOptions = Partial<
BasicOpts & {
ignored: Matcher | Matcher[];
Expand Down Expand Up @@ -142,20 +148,8 @@ function anymatch(matchers: Matcher[], testString: string | undefined): boolean
return matchPatterns(patterns, testString);
}

const flatten = (list: any[], result = []) => {
list.forEach((item) => {
if (Array.isArray(item)) {
flatten(item, result);
} else {
// @ts-ignore
result.push(item);
}
});
return result;
};

const unifyPaths = (paths_: Path | Path[]) => {
const paths = flatten(arrify(paths_));
const paths = arrify(paths_).flat();
if (!paths.every((p) => typeof p === STRING_TYPE)) {
throw new TypeError(`Non-string provided as watch path: ${paths}`);
}
Expand Down Expand Up @@ -186,11 +180,11 @@ const normalizePathToUnix = (path: Path) => toUnix(sysPath.normalize(toUnix(path
// TODO: refactor
const normalizeIgnored =
(cwd = '') =>
(path: any): any => {
(path: unknown): string => {
if (typeof path === 'string') {
return normalizePathToUnix(sysPath.isAbsolute(path) ? path : sysPath.join(cwd, path));
} else {
return path;
return path as string;
}
};

Expand All @@ -207,10 +201,10 @@ const EMPTY_SET = Object.freeze(new Set<string>());
*/
class DirEntry {
path: Path;
_removeWatcher: any;
_removeWatcher: (dir: string, base: string) => void;
items: Set<Path>;

constructor(dir: Path, removeWatcher: any) {
constructor(dir: Path, removeWatcher: (dir: string, base: string) => void) {
this.path = dir;
this._removeWatcher = removeWatcher;
this.items = new Set<Path>();
Expand Down Expand Up @@ -270,7 +264,7 @@ export class WatchHelper {
followSymlinks: boolean;
statMethod: 'stat' | 'lstat';

constructor(path: string, follow: boolean, fsw: any) {
constructor(path: string, follow: boolean, fsw: FSWatcher) {
this.fsw = fsw;
const watchPath = path;
this.path = path = path.replace(REPLACER_RE, '');
Expand Down Expand Up @@ -316,12 +310,12 @@ export class FSWatcher extends EventEmitter {
_closers: Map<string, Array<any>>;
_ignoredPaths: Set<Matcher>;
_throttled: Map<ThrottleType, Map<any, any>>;
_streams: Set<any>;
_streams: Set<ReaddirpStream>;
_symlinkPaths: Map<Path, string | boolean>;
_watched: Map<string, DirEntry>;

_pendingWrites: Map<any, any>;
_pendingUnlinks: Map<any, any>;
_pendingWrites: Map<string, any>;
_pendingUnlinks: Map<string, EmitArgs>;
_readyCount: number;
_emitReady: () => void;
_closePromise?: Promise<void>;
Expand Down Expand Up @@ -626,7 +620,7 @@ export class FSWatcher extends EventEmitter {
}

if (awf && (event === EV.ADD || event === EV.CHANGE) && this._readyEmitted) {
const awfEmit = (err: Error, stats: Stats) => {
const awfEmit = (err?: Error, stats?: Stats) => {
if (err) {
event = args[0] = EV.ERROR;
args[1] = err;
Expand Down Expand Up @@ -696,17 +690,7 @@ export class FSWatcher extends EventEmitter {
* @param timeout duration of time to suppress duplicate actions
* @returns tracking object or false if action should be suppressed
*/
_throttle(
actionType: ThrottleType,
path: Path,
timeout: number
):
| {
timeoutObject: any;
clear: () => any;
count: number;
}
| false {
_throttle(actionType: ThrottleType, path: Path, timeout: number): Throttler | false {
if (!this._throttled.has(actionType)) {
this._throttled.set(actionType, new Map());
}
Expand All @@ -721,7 +705,7 @@ export class FSWatcher extends EventEmitter {
}

// eslint-disable-next-line prefer-const
let timeoutObject: any;
let timeoutObject: NodeJS.Timeout;
const clear = () => {
const item = action.get(path);
const count = item ? item.count : 0;
Expand All @@ -748,11 +732,16 @@ export class FSWatcher extends EventEmitter {
* @param event
* @param awfEmit Callback to be called when ready for event to be emitted.
*/
_awaitWriteFinish(path: Path, threshold: number, event: EventName, awfEmit: any) {
_awaitWriteFinish(
path: Path,
threshold: number,
event: EventName,
awfEmit: (err?: Error, stat?: Stats) => void
) {
const awf = this.options.awaitWriteFinish;
if (typeof awf !== 'object') return;
const pollInterval = awf.pollInterval as unknown as number;
let timeoutHandler: any;
let timeoutHandler: NodeJS.Timeout;

let fullPath = path;
if (this.options.cwd && !sysPath.isAbsolute(path)) {
Expand Down

0 comments on commit bf65c94

Please sign in to comment.