export function find()

in node/task.ts [907:1017]


export function find(findPath: string, options?: FindOptions): string[] {
    if (!findPath) {
        debug('no path specified');
        return [];
    }

    // normalize the path, otherwise the first result is inconsistently formatted from the rest of the results
    // because path.join() performs normalization.
    findPath = path.normalize(findPath);

    // debug trace the parameters
    debug(`findPath: '${findPath}'`);
    options = options || _getDefaultFindOptions();
    _debugFindOptions(options)

    // return empty if not exists
    try {
        fs.lstatSync(findPath);
    }
    catch (err) {
        if (err.code == 'ENOENT') {
            debug('0 results')
            return [];
        }

        throw err;
    }

    try {
        let result: string[] = [];

        // push the first item
        let stack: _FindItem[] = [new _FindItem(findPath, 1)];
        let traversalChain: string[] = []; // used to detect cycles

        while (stack.length) {
            // pop the next item and push to the result array
            let item = stack.pop()!; // non-null because `stack.length` was truthy

            let stats: fs.Stats;
            try {
                // `item.path` equals `findPath` for the first item to be processed, when the `result` array is empty
                const isPathToSearch: boolean = !result.length;

                // following specified symlinks only if current path equals specified path
                const followSpecifiedSymbolicLink: boolean = options.followSpecifiedSymbolicLink && isPathToSearch;

                // following all symlinks or following symlink for the specified path
                const followSymbolicLink: boolean = options.followSymbolicLinks || followSpecifiedSymbolicLink;

                // stat the item. The stat info is used further below to determine whether to traverse deeper
                stats = _getStats(item.path, followSymbolicLink, options.allowBrokenSymbolicLinks);
            } catch (err) {
                if (err.code == 'ENOENT' && options.skipMissingFiles) {
                    warning(`No such file or directory: "${item.path}" - skipping.`);
                    continue;
                }
                throw err;
            }
            result.push(item.path);

            // note, isDirectory() returns false for the lstat of a symlink
            if (stats.isDirectory()) {
                debug(`  ${item.path} (directory)`);

                if (options.followSymbolicLinks) {
                    // get the realpath
                    let realPath: string;
                    if (im._isUncPath(item.path)) {
                        // Sometimes there are spontaneous issues when working with unc-paths, so retries have been added for them.
                        realPath = retry(fs.realpathSync, [item.path], { continueOnError: false, retryCount: 5 });
                    } else {
                        realPath = fs.realpathSync(item.path);
                    }

                    // fixup the traversal chain to match the item level
                    while (traversalChain.length >= item.level) {
                        traversalChain.pop();
                    }

                    // test for a cycle
                    if (traversalChain.some((x: string) => x == realPath)) {
                        debug('    cycle detected');
                        continue;
                    }

                    // update the traversal chain
                    traversalChain.push(realPath);
                }

                // push the child items in reverse onto the stack
                let childLevel: number = item.level + 1;
                let childItems: _FindItem[] =
                    fs.readdirSync(item.path)
                        .map((childName: string) => new _FindItem(path.join(item.path, childName), childLevel));
                for (var i = childItems.length - 1; i >= 0; i--) {
                    stack.push(childItems[i]);
                }
            }
            else {
                debug(`  ${item.path} (file)`);
            }
        }

        debug(`${result.length} results`);
        return result;
    }
    catch (err) {
        throw new Error(loc('LIB_OperationFailed', 'find', err.message));
    }
}