From 61c52e31857c756127eee113a5bcd5b4d38ec9bf Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 8 May 2019 10:41:52 -0600 Subject: [PATCH] Decaffeinate default-directory-searcher.coffee and its spec Co-Authored-By: Rafael Oleza --- spec/default-directory-searcher-spec.coffee | 28 ----- spec/default-directory-searcher-spec.js | 42 ++++++++ src/default-directory-searcher.coffee | 94 ---------------- src/default-directory-searcher.js | 114 ++++++++++++++++++++ 4 files changed, 156 insertions(+), 122 deletions(-) delete mode 100644 spec/default-directory-searcher-spec.coffee create mode 100644 spec/default-directory-searcher-spec.js delete mode 100644 src/default-directory-searcher.coffee create mode 100644 src/default-directory-searcher.js diff --git a/spec/default-directory-searcher-spec.coffee b/spec/default-directory-searcher-spec.coffee deleted file mode 100644 index 665e03409..000000000 --- a/spec/default-directory-searcher-spec.coffee +++ /dev/null @@ -1,28 +0,0 @@ -DefaultDirectorySearcher = require '../src/default-directory-searcher' -Task = require '../src/task' -path = require 'path' - -describe "DefaultDirectorySearcher", -> - [searcher, dirPath] = [] - - beforeEach -> - dirPath = path.resolve(__dirname, 'fixtures', 'dir') - searcher = new DefaultDirectorySearcher - - it "terminates the task after running a search", -> - options = - ignoreCase: false - includeHidden: false - excludeVcsIgnores: true - inclusions: [] - globalExclusions: ['a-dir'] - didMatch: -> - didError: -> - didSearchPaths: -> - searchPromise = searcher.search([{getPath: -> dirPath}], /abcdefg/, options) - spyOn(Task::, 'terminate').andCallThrough() - - waitsForPromise -> searchPromise - - runs -> - expect(Task::terminate).toHaveBeenCalled() diff --git a/spec/default-directory-searcher-spec.js b/spec/default-directory-searcher-spec.js new file mode 100644 index 000000000..d2bf8963b --- /dev/null +++ b/spec/default-directory-searcher-spec.js @@ -0,0 +1,42 @@ +const DefaultDirectorySearcher = require('../src/default-directory-searcher') +const Task = require('../src/task') +const path = require('path') + +describe('DefaultDirectorySearcher', function () { + let searcher + let dirPath + + beforeEach(function () { + dirPath = path.resolve(__dirname, 'fixtures', 'dir') + searcher = new DefaultDirectorySearcher() + }) + + it('terminates the task after running a search', function () { + const options = { + ignoreCase: false, + includeHidden: false, + excludeVcsIgnores: true, + inclusions: [], + globalExclusions: ['a-dir'], + didMatch () {}, + didError () {}, + didSearchPaths () {} + } + const searchPromise = searcher.search( + [ + { + getPath () { + return dirPath + } + } + ], + /abcdefg/, + options + ) + spyOn(Task.prototype, 'terminate').andCallThrough() + + waitsForPromise(() => searchPromise) + + runs(() => expect(Task.prototype.terminate).toHaveBeenCalled()) + }) +}) diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee deleted file mode 100644 index 3955d38e3..000000000 --- a/src/default-directory-searcher.coffee +++ /dev/null @@ -1,94 +0,0 @@ -Task = require './task' - -# Searches local files for lines matching a specified regex. Implements `.then()` -# so that it can be used with `Promise.all()`. -class DirectorySearch - constructor: (rootPaths, regex, options) -> - scanHandlerOptions = - ignoreCase: regex.ignoreCase - inclusions: options.inclusions - includeHidden: options.includeHidden - excludeVcsIgnores: options.excludeVcsIgnores - globalExclusions: options.exclusions - follow: options.follow - searchOptions = - leadingContextLineCount: options.leadingContextLineCount - trailingContextLineCount: options.trailingContextLineCount - @task = new Task(require.resolve('./scan-handler')) - @task.on 'scan:result-found', options.didMatch - @task.on 'scan:file-error', options.didError - @task.on 'scan:paths-searched', options.didSearchPaths - @promise = new Promise (resolve, reject) => - @task.on('task:cancelled', reject) - @task.start rootPaths, regex.source, scanHandlerOptions, searchOptions, => - @task.terminate() - resolve() - - then: (args...) -> - @promise.then.apply(@promise, args) - - cancel: -> - # This will cause @promise to reject. - @task.cancel() - null - -# Default provider for the `atom.directory-searcher` service. -module.exports = -class DefaultDirectorySearcher - # Determines whether this object supports search for a `Directory`. - # - # * `directory` {Directory} whose search needs might be supported by this object. - # - # Returns a `boolean` indicating whether this object can search this `Directory`. - canSearchDirectory: (directory) -> true - - # Performs a text search for files in the specified `Directory`, subject to the - # specified parameters. - # - # Results are streamed back to the caller by invoking methods on the specified `options`, - # such as `didMatch` and `didError`. - # - # * `directories` {Array} of {Directory} objects to search, all of which have been accepted by - # this searcher's `canSearchDirectory()` predicate. - # * `regex` {RegExp} to search with. - # * `options` {Object} with the following properties: - # * `didMatch` {Function} call with a search result structured as follows: - # * `searchResult` {Object} with the following keys: - # * `filePath` {String} absolute path to the matching file. - # * `matches` {Array} with object elements with the following keys: - # * `lineText` {String} The full text of the matching line (without a line terminator character). - # * `lineTextOffset` {Number} (This always seems to be 0?) - # * `matchText` {String} The text that matched the `regex` used for the search. - # * `range` {Range} Identifies the matching region in the file. (Likely as an array of numeric arrays.) - # * `didError` {Function} call with an Error if there is a problem during the search. - # * `didSearchPaths` {Function} periodically call with the number of paths searched thus far. - # * `inclusions` {Array} of glob patterns (as strings) to search within. Note that this - # array may be empty, indicating that all files should be searched. - # - # Each item in the array is a file/directory pattern, e.g., `src` to search in the "src" - # directory or `*.js` to search all JavaScript files. In practice, this often comes from the - # comma-delimited list of patterns in the bottom text input of the ProjectFindView dialog. - # * `ignoreHidden` {boolean} whether to ignore hidden files. - # * `excludeVcsIgnores` {boolean} whether to exclude VCS ignored paths. - # * `exclusions` {Array} similar to inclusions - # * `follow` {boolean} whether symlinks should be followed. - # - # Returns a *thenable* `DirectorySearch` that includes a `cancel()` method. If `cancel()` is - # invoked before the `DirectorySearch` is determined, it will resolve the `DirectorySearch`. - search: (directories, regex, options) -> - rootPaths = directories.map (directory) -> directory.getPath() - isCancelled = false - directorySearch = new DirectorySearch(rootPaths, regex, options) - promise = new Promise (resolve, reject) -> - directorySearch.then resolve, -> - if isCancelled - resolve() - else - reject() - return { - then: promise.then.bind(promise) - catch: promise.catch.bind(promise) - cancel: -> - isCancelled = true - directorySearch.cancel() - } diff --git a/src/default-directory-searcher.js b/src/default-directory-searcher.js new file mode 100644 index 000000000..505dfa6c2 --- /dev/null +++ b/src/default-directory-searcher.js @@ -0,0 +1,114 @@ +const Task = require('./task') + +// Searches local files for lines matching a specified regex. Implements `.then()` +// so that it can be used with `Promise.all()`. +class DirectorySearch { + constructor (rootPaths, regex, options) { + const scanHandlerOptions = { + ignoreCase: regex.ignoreCase, + inclusions: options.inclusions, + includeHidden: options.includeHidden, + excludeVcsIgnores: options.excludeVcsIgnores, + globalExclusions: options.exclusions, + follow: options.follow + } + const searchOptions = { + leadingContextLineCount: options.leadingContextLineCount, + trailingContextLineCount: options.trailingContextLineCount + } + this.task = new Task(require.resolve('./scan-handler')) + this.task.on('scan:result-found', options.didMatch) + this.task.on('scan:file-error', options.didError) + this.task.on('scan:paths-searched', options.didSearchPaths) + this.promise = new Promise((resolve, reject) => { + this.task.on('task:cancelled', reject) + this.task.start( + rootPaths, + regex.source, + scanHandlerOptions, + searchOptions, + () => { + this.task.terminate() + resolve() + } + ) + }) + } + + then (...args) { + return this.promise.then.apply(this.promise, args) + } + + cancel () { + // This will cause @promise to reject. + this.task.cancel() + } +} + +// Default provider for the `atom.directory-searcher` service. +module.exports = class DefaultDirectorySearcher { + // Determines whether this object supports search for a `Directory`. + // + // * `directory` {Directory} whose search needs might be supported by this object. + // + // Returns a `boolean` indicating whether this object can search this `Directory`. + canSearchDirectory (directory) { + return true + } + + // Performs a text search for files in the specified `Directory`, subject to the + // specified parameters. + // + // Results are streamed back to the caller by invoking methods on the specified `options`, + // such as `didMatch` and `didError`. + // + // * `directories` {Array} of {Directory} objects to search, all of which have been accepted by + // this searcher's `canSearchDirectory()` predicate. + // * `regex` {RegExp} to search with. + // * `options` {Object} with the following properties: + // * `didMatch` {Function} call with a search result structured as follows: + // * `searchResult` {Object} with the following keys: + // * `filePath` {String} absolute path to the matching file. + // * `matches` {Array} with object elements with the following keys: + // * `lineText` {String} The full text of the matching line (without a line terminator character). + // * `lineTextOffset` {Number} (This always seems to be 0?) + // * `matchText` {String} The text that matched the `regex` used for the search. + // * `range` {Range} Identifies the matching region in the file. (Likely as an array of numeric arrays.) + // * `didError` {Function} call with an Error if there is a problem during the search. + // * `didSearchPaths` {Function} periodically call with the number of paths searched thus far. + // * `inclusions` {Array} of glob patterns (as strings) to search within. Note that this + // array may be empty, indicating that all files should be searched. + // + // Each item in the array is a file/directory pattern, e.g., `src` to search in the "src" + // directory or `*.js` to search all JavaScript files. In practice, this often comes from the + // comma-delimited list of patterns in the bottom text input of the ProjectFindView dialog. + // * `ignoreHidden` {boolean} whether to ignore hidden files. + // * `excludeVcsIgnores` {boolean} whether to exclude VCS ignored paths. + // * `exclusions` {Array} similar to inclusions + // * `follow` {boolean} whether symlinks should be followed. + // + // Returns a *thenable* `DirectorySearch` that includes a `cancel()` method. If `cancel()` is + // invoked before the `DirectorySearch` is determined, it will resolve the `DirectorySearch`. + search (directories, regex, options) { + const rootPaths = directories.map(directory => directory.getPath()) + let isCancelled = false + const directorySearch = new DirectorySearch(rootPaths, regex, options) + const promise = new Promise(function (resolve, reject) { + directorySearch.then(resolve, function () { + if (isCancelled) { + resolve() + } else { + reject() + } + }) + }) + return { + then: promise.then.bind(promise), + catch: promise.catch.bind(promise), + cancel () { + isCancelled = true + directorySearch.cancel() + } + } + } +}